How would you make Kubernetes Secret data unreadable to someone who obtains a raw copy of the etcd data files or a cluster backup, and what does a KMS provider add over an encryption key configured locally on the control plane?
answer
- --encryption-provider-config, EncryptionConfiguration
- first provider writes, all providers read
- identity last, or encryption is off
- existing objects need kubectl replace rewrite
- KMS v2 = envelope, external root key, auditable + revocable
basics
~20 sConfigure encryption at rest: pass an EncryptionConfiguration to kube-apiserver naming secrets as a resource. A local aescbc or secretbox key sits in a file on the control-plane node; a KMS provider does envelope encryption so the root key lives in an external KMS/HSM instead. Existing Secrets must be rewritten to become encrypted.
solid answer
~60 sPoint `kube-apiserver --encryption-provider-config` at an `EncryptionConfiguration` that lists `secrets` (usually `configmaps` too) with a real provider ahead of `identity`. Provider order matters: the first entry encrypts writes, all entries are tried for reads, so you roll keys by prepending the new one and rewriting objects. Encryption only applies on write, so after enabling it you must force a rewrite: `kubectl get secrets -A -o json | kubectl replace -f -`. Otherwise the pre-existing Secrets stay in plaintext in etcd. A local `aescbc` or `secretbox` provider keeps the key in a file on the control-plane node, readable by root there, so it defends against a stolen disk or a leaked backup but not against control-plane compromise. A `kms` v2 provider does envelope encryption: the API server holds a data key wrapped by a key that never leaves an external KMS or HSM, so key use is centrally revocable and auditable, and rotation happens in the KMS. That is the difference: where the root of trust lives and who can audit its use.
code
yaml · 17 linesapiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
- configmaps
providers:
- kms: # first entry encrypts all writes
apiVersion: v2
name: cluster-kms
endpoint: unix:///var/run/kmsplugin/socket.sock
timeout: 3s
- aescbc: # still able to read objects written earlier
keys:
- name: key-2024
secret: <base64-encoded-32-byte-key>
- identity: {} # last, and only while migratinggo deeper
Know that Secrets are not encrypted in etcd by default and that a cluster-level EncryptionConfiguration is what changes that.
Explain the provider list semantics (first writes, all read), that existing objects need a rewrite, and the difference between a local key and a KMS provider.
Walk the full rollout: config on every API server replica, rewrite, verification straight from etcd, key rotation procedure, and the KMS availability dependency.
Weigh the threat model against cost and blast radius: what a stolen backup actually exposes, whether the organisation needs an external root of trust for compliance, how KMS outage risk is absorbed, and where secrets should not live in etcd at all.
## The threat being addressed Encryption at rest defends against an attacker who gets the bytes without going through the API server: a stolen or decommissioned control-plane disk, an etcd snapshot sitting in an object-storage bucket, a backup restored into a lab, or direct etcd client access. It does not defend against an attacker who can call the API server with sufficient RBAC, because the API server necessarily returns plaintext. RBAC and encryption at rest are complementary, not alternatives. ## Configuring it The API server takes `--encryption-provider-config=/etc/kubernetes/enc.yaml`, an `EncryptionConfiguration` object listing resources and, for each, an ordered list of providers. The available providers are `identity` (no encryption), `secretbox` (XSalsa20-Poly1305), `aesgcm`, `aescbc`, and `kms`. `aesgcm` requires strict key rotation discipline because of nonce reuse risk, so `aescbc` or `secretbox` are the usual local choices and `kms` is the recommended one. Two rules govern the list. The **first** provider is used to encrypt every write. **All** providers are tried, in order, when decrypting, which is what makes rotation possible. Consequently, `identity` must be last if it appears at all, and putting `identity` first silently disables encryption while looking configured. Because encryption happens on write, enabling it changes nothing about objects already in etcd. You must rewrite them, typically with `kubectl get secrets --all-namespaces -o json | kubectl replace -f -`. The same command is how you complete a key rotation after prepending a new key. Verify by reading a key straight out of etcd with `etcdctl` and confirming the value starts with a provider prefix such as `k8s:enc:kms:v2:` rather than showing plaintext. Also remember there are usually multiple API server replicas: every one of them needs the same configuration file before you start rewriting, or writes served by an unconfigured replica stay in plaintext and reads of newly encrypted objects fail. ## What a local key does and does not buy With `aescbc` or `secretbox`, the key material sits base64-encoded in a YAML file on each control-plane node, readable by root. That is genuinely useful: an etcd backup leaked to a bucket, a snapshot copied to a laptop, or a disposed disk becomes useless on its own. But the key travels with the machine, so anyone who compromises a control-plane node, or who obtains both the backup and a copy of the config, gets everything. There is no audit trail of key use and no way to revoke. ## What a KMS provider adds A `kms` provider moves the root of trust out of the cluster. In KMS v2 (GA in Kubernetes 1.29; v1 is deprecated) the API server generates a local key-encryption key, has the external KMS wrap it, and caches the result; individual objects are encrypted with data keys under that hierarchy, so the number of calls to the external KMS stays small while the key that matters never exists in cleartext on the node in a durable form. The provider runs as a socket-based plugin the API server talks to over a UNIX domain socket. Concretely this gives you: key material held in a managed KMS or HSM with its own access policy; every use of the root key logged in the cloud provider's audit trail; revocation as a real operation, since disabling the KMS key makes existing ciphertext undecryptable; and rotation performed in the KMS, with KMS v2 able to pick up a new key version without an API server restart (`status.key_id` changes and the API server re-wraps). The tradeoff is a hard availability dependency. If the KMS is unreachable, the API server cannot decrypt Secrets, so Secret reads fail and, in practice, so do Pod starts that need them. You size for that: regional KMS endpoints, caching, and a tested plan for a KMS outage, plus a documented recovery path since an unrecoverable key loss means unrecoverable Secrets. ## Adjacent hygiene Encryption at rest is one control among several for the same threat. etcd should also be on encrypted storage, reachable only over mutual TLS from the API servers, and never exposed on a routable network. Backups inherit whatever protection etcd had at write time, so an encrypted-at-rest cluster produces backups that are safe to store but still worth encrypting again in transit and in the bucket. And the audit policy should keep Secret request and response bodies out of the audit log, since audit sinks are usually far less protected than etcd. ## What to say Name the flag and the file, state the write-first/read-all provider ordering, mention that existing objects need a rewrite, then contrast a local key (defends the backup, not the node) with a KMS provider (external root of trust, auditable and revocable, at the price of an availability dependency).
- You enabled encryption at rest last month. How do you prove that every Secret in etcd is actually encrypted?Read the raw key from etcd with `etcdctl` and check for a provider prefix such as `k8s:enc:kms:v2:` instead of plaintext, and do it for an object created before the change, not only a fresh one. If old objects are still plaintext, run `kubectl get secrets --all-namespaces -o json | kubectl replace -f -` to rewrite them, since encryption only takes effect on write.
- What is the operational risk of depending on an external KMS for Secret decryption?It becomes a hard availability dependency on the API server's read path: if the KMS endpoint is unreachable or the key is disabled, Secret reads fail and Pods that need them cannot start. Mitigations are regional or highly available KMS endpoints, the plugin's data-key caching, health checks that surface KMS latency early, and a rehearsed procedure for a KMS outage. Permanent loss of the root key means permanent loss of every encrypted Secret.
A local key is locking the filing cabinet and taping the key under the desk in the same room: fine against someone who steals the cabinet, useless against someone who gets into the room. A KMS keeps the key at a guarded front desk that logs every time it is handed out and can stop handing it out.
saying these in an interview costs you the question
- Thinking enabling encryption retroactively encrypts Secrets already in etcd
- Putting identity first in the provider list and believing encryption is on
- Claiming encryption at rest protects against a user with RBAC read access to Secrets
- Treating a local aescbc key as equivalent to a KMS when the key file sits on the same node as etcd
- Rotating keys by replacing the old entry instead of prepending the new one, making existing data undecryptable