← Policy catalog
</> ValidatingAdmissionPolicy · Apache-2.0

Stores Credentials, Tokens or Private Keys

configmap-secrets

severityCritical resourceConfigMaps productKubernetes bundles1

Credentials in a ConfigMap are stored unencrypted and readable by anyone holding the broad ConfigMap read permission most roles grant, and they leak further through logs, backups and manifests in source control.

Rejects unless

(!has(object.data) || !object.data.exists(
  k,
  v,
  (
    k.lowerAscii().matches(".*(secret|password|passwd|token|apikey|api_key|credential|private|key).*") ||
    v.matches("(?s).*-----BEGIN (RSA|DSA|EC|PGP) PRIVATE KEY-----.*") ||
    v.matches("(?i)aws(.{0,10})?(secret|access)[^\\w]?key") ||
    v.matches("(?i)AWS_?(SECRET|ACCESS)_KEY") ||
    v.matches("(?i)GOOGLE_APPLICATION_CREDENTIALS") ||
    v.matches("(?i)AZURE_CLIENT_SECRET")
  )
)) &&
(!has(object.binaryData) || !object.binaryData.exists(
  k,
  v,
  k.lowerAscii().matches(".*(secret|password|passwd|token|apikey|api_key|credential|private|key).*")
))

ConfigMaps must not contain secrets, tokens, or private keys. Use Secrets instead.

Remediation

Move passwords, tokens, private keys and cloud credentials into Secrets referenced by the workload, then delete those entries from the ConfigMap. Fields: data, binaryData.

Applies to

  • configmaps · v1 · CREATE, UPDATE

Manifest

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
  name: configmap-secrets
  annotations:
    kubeapt.io/uuid: "21735678-f711-4b9f-a267-cbd09c7afbfc"
    security.kubeapt.io/displayName: "Stores Credentials, Tokens or Private Keys"
    security.kubeapt.io/description: "Credentials in a ConfigMap are stored unencrypted and readable by anyone holding the broad ConfigMap read permission most roles grant, and they leak further through logs, backups and manifests in source control."
    security.kubeapt.io/resource: "ConfigMaps"
    security.kubeapt.io/severity: "Critical"
    security.kubeapt.io/remediation: "Move passwords, tokens, private keys and cloud credentials into Secrets referenced by the workload, then delete those entries from the ConfigMap. Fields: data, binaryData."
    security.kubeapt.io/product: "Kubernetes"
spec:
  failurePolicy: Fail
  matchConstraints:
    resourceRules:
    - apiGroups:
      - ''
      apiVersions:
      - v1
      operations:
      - CREATE
      - UPDATE
      resources:
      - configmaps
  validations:
  - expression: |
      (!has(object.data) || !object.data.exists(
        k,
        v,
        (
          k.lowerAscii().matches(".*(secret|password|passwd|token|apikey|api_key|credential|private|key).*") ||
          v.matches("(?s).*-----BEGIN (RSA|DSA|EC|PGP) PRIVATE KEY-----.*") ||
          v.matches("(?i)aws(.{0,10})?(secret|access)[^\\w]?key") ||
          v.matches("(?i)AWS_?(SECRET|ACCESS)_KEY") ||
          v.matches("(?i)GOOGLE_APPLICATION_CREDENTIALS") ||
          v.matches("(?i)AZURE_CLIENT_SECRET")
        )
      )) &&
      (!has(object.binaryData) || !object.binaryData.exists(
        k,
        v,
        k.lowerAscii().matches(".*(secret|password|passwd|token|apikey|api_key|credential|private|key).*")
      ))
    message: |
      ConfigMaps must not contain secrets, tokens, or private keys. Use Secrets instead.

Save it as configmap-secrets.yaml — the commands below assume that name.

Validate with kubeapt

Check a workload against this one policy, before anything is installed on a cluster.

$ kubeapt validate -p ./configmap-secrets.yaml -r ./workload.yaml

Or without the file, from the published policy set — -r takes a directory too:

$ kubeapt policies download && kubeapt validate --policy-name configmap-secrets -r ./manifests

Or against every namespace in the cluster your kubeconfig points at:

$ kubeapt validate --policy-name configmap-secrets -A