Review Kubernetes Secret management

Choose secret management that meets access-control, rotation and audit requirements.

Description

Native Kubernetes Secrets can be used with appropriate access controls and encryption at rest. Managing credentials across applications and clusters can complicate rotation, expiry, auditing and central administration, making an external secret store useful. Native Secret use is not inherently a vulnerability.

External stores also require credential delivery and access permissions. KMS encryption at rest is distinct from secret lifecycle management, and synchronizing external values into Secrets can leave copies in Kubernetes.

Potential impact

  • Manual rotation and expiry handling can leave old credentials in use.
  • Excessive Secret permissions or real values stored in manifests can expose secrets.

Remediation

  • Choose native Secrets or integrations such as Vault, cloud secret stores and Secrets Store CSI Driver according to scale, audit and rotation needs. KMS encryption alone does not replace a secret store’s functions.
  • With either approach, apply least privilege, encryption at rest and auditing, and do not commit real secrets to a repository. Check how rotation reaches files, environment variables and the application, including any required restarts.

Examples

The before values are nonproduction examples. The after SecretProviderClass is part of an Azure Key Vault integration; separately configure the CSI driver, Azure provider, identity and vault permissions, and the Pod’s CSI volume mount. Replace placeholders with actual environment values.

Before

yaml
apiVersion: v1
kind: Secret
metadata:
  name: app-secret
stringData:
  password: "my-password"
  apiToken: "my-token"

Secret values are written directly into the manifest. Committing real values can expose them, and base64 representation in a Secret is not encryption.

After

yaml
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: app-secrets
spec:
  provider: azure
  parameters:
    keyvaultName: "<key-vault-name>"
    tenantId: "<tenant-id>"
    objects: |
      array:
        - |
          objectName: app-password
          objectType: secret

The external app-password value is selected. This resource alone does not mount it into a Pod or remove an existing Secret.

References