# ConfigMap Has Excessive Keys

> Flags Kubernetes ConfigMaps on EKS, GKE and AKS with more than 50 keys, a sign one map is serving too many owners.

Source: https://zop.dev/integrations/kubernetes/recommendations/configmap-has-excessive-keys

---

## A single oversized ConfigMap couples unrelated changes

A ConfigMap is meant to hold a small amount of configuration for one consumer. The
[ConfigMap documentation](https://kubernetes.io/docs/concepts/configuration/configmap/) says
plainly that it is not designed for large chunks of data and that its contents cannot exceed
1 MiB. Long before a map reaches that cap, a high key count causes a quieter problem: several
teams or components start editing the same object.

Every edit then has a wide blast radius. Keys consumed as environment variables are not updated
automatically; the pods reading them need a restart to see new values. So a one-line change for
service A leads someone to restart service B as well, because both read the same map. Reviewing
the diff is harder too, since a pull request touching one key sits beside dozens of keys nobody
on the review owns.

## Counting keys across every namespace

The `DATA` column of `kubectl get configmaps -A` shows the key count per map. ZopNight counts
keys in both `data` and `binaryData`, so to list only the maps above the rule's line:

```bash
kubectl get configmaps -A -o json | jq -r '
  .items[]
  | (((.data // {}) | length) + ((.binaryData // {}) | length)) as $n
  | select($n > 50)
  | "\(.metadata.namespace)/\(.metadata.name) \($n) keys"'
```

To see which workloads mount or read a given map before you split it:

```bash
kubectl get pods -n <namespace> -o json | jq -r '
  .items[] | select(tostring | contains("<configmap-name>")) | .metadata.name'
```

## The 50-key line and what ZopNight reads

The rule reads the key count ZopNight collected for each ConfigMap and fires when it is greater
than 50. Exactly 50 keys does not fire. There is no time window: the count is read fresh each
time the cluster is evaluated, and the finding clears on its own once the map drops to 50 keys
or fewer.

## Maps the check does not judge

A ConfigMap whose key count was not reported is skipped rather than guessed at. The rule does
not look at total byte size, so a map with a handful of very large values is not flagged here.
It also does not know who owns the keys: a generated map maintained by one tool, such as a
bundle of dashboards, can carry many keys for good reason. ConfigMaps in `kube-system`,
`kube-public` and `kube-node-lease` (and GKE's own system namespaces) are not collected, so they are
never flagged.

## Governance finding, no dollar amount

ConfigMaps are API objects and carry no cloud charge of their own, so this finding has no
savings figure. Its value is operational: smaller maps mean smaller reviews, fewer surprise
restarts and less risk of hitting the 1 MiB cap during a release.

## Breaking the map apart

1. Group the keys by the component or team that reads them. Prefixes in key names usually give
   the grouping away.
2. Create one ConfigMap per group and point each workload at only the maps it needs.
3. Roll the workloads so pods pick up the new references, then delete the old keys.
4. For values that should never change after release, consider an
   [immutable ConfigMap](https://kubernetes.io/docs/concepts/configuration/configmap/),
   stable since Kubernetes v1.21.

For the equivalent check on credentials, see
[Secret has excessive keys](https://zop.dev/integrations/kubernetes/recommendations/secret-has-excessive-keys).
