Secrets

Secrets provide secure storage for sensitive pieces of data, such as passwords, private keys, passphrases and certificates. This allows us to centralise management of security-critical information and inject it at the point of use. As an added benefit, Kubernetes only makes the secrets available to Nodes which it knows have dependent Pods scheduled.

Like ConfigMaps, Secrets can be injected into pods either as environment variables or files (via tmpfs, avoiding disk persistence).

Note that since secrets must be base-64 encoded in manifests there's a risk exposing the secret:

apiVersion: v1
kind: Secret
metadata:
    name: my-secret
type: Opaque
data:
    # base64 <<<hunter2
    db_pass: aHVudGVyMgo=

Or via the console:

kubectl create secret generic my-password --from-literal=db_pass=hunter2

kubectl create secret generic my-identity \
    --from-file=ssh-privatekey=id \
    --from-file=ssh-publickey=id.pub

kubectl create secret cert \
    --cert-path=domain.crt \
    --key=domain.key

Types

Secret types are used to define their use case. Search /pks/apis/core/types.go for SecretType = for a complete list.

  • "Opaque" is for secrets not intended for consumption by Kubernetes itself, but for applications hosted on it.
  • "kubernetes.io/service-account-token"
  • "kubernetes.io/dockerconfigjson" stores a raw ~/.docker/config.json file for use pulling images from a Docker registry.

Logging in to a Docker registry

First, log in to the registry and verify that the credentials are valid and saved:

docker login
docker pull some-repo/some-image:some-tag
cat ~/.docker/config.json

Now create the secret:

kubectl create secret generic my-cred \
    --from-file .dockerconfigjson=~/.docker/config.json \
    --type kubernetes.io/dockerconfigjson

Alternatively, directly enter the credentials (the effect will be the same):

kubectl create secret docker-registry my-cred \
    --docker-server 'https://registry.example.com/v1/' \
    --docker-username 'my-username' \
    --docker-password 'my-secret' \
    --docker-email 'me@example.com'

Binding via environment variables

Consuming:

# Inside a Pod.spec.containers[*]
env:
- name: DB_PASS:
  valueFrom:
    secretKeyRef:
      name: my-secret
      key: db_pass

Binding via volumes

# Inside a Pod.spec
volumes:
  - name: secrets:
    secret:
      secretName: my-secret
containers:
  volumeMounts:
  - name: secrets
    mountPath: /etc/my-app/secure
    readOnly: true

Dumping on the console

kubectl get secret my-secret --template '{{.data.MY_KEY}}' | base64 -d

Encryption at rest

The API Server accepts an --encryption-provider-config argument specifying a configuration file containing an EncryptionConfiguration. The configuration specifies a provider and a set of keys (or external KMS locations) for one or more sets of resource types.

Decryption

Place the identity provider as the first provider for each resource definition and restart the API server process. Secrets will be decrypted as they're requested.

Storage externally

Secrets can be migrated to an external key vault service using the Secrets Store CSI driver. Secrets are hosted on external secret stores accessible via providers.


Backlinks