Secrets, PKI & CertificatesIII · Cryptography for Infrastructure EngineersCryptography
Symmetric encryption in infrastructure, and why AEAD is the only sane default
What you'll learn
- Identify the places in a production estate where symmetric encryption is doing the work
- Explain why the cipher mode, not the key length, determines the security properties you get
- Describe what an AEAD construction adds over a bare cipher, including the associated data field
- Apply the nonce reuse rule and recognise the operational controls that enforce it
Prerequisites
Verified against OpenSSL 3.5.x teaching target; 3.0+ minimum · OpenSSH 10.x teaching target; 8.2+ minimum for certificate workflows · OpenBao 2.6.x · Smallstep step-ca 0.30.x · Certbot / Pebble Certbot current release; Pebble 2.10.x ACME test server · Kubernetes (cross-course target) 1.36.x · PostgreSQL 17.x · 2026-08-26
Nearly every byte that moves or rests in your estate is protected by a symmetric cipher. One key encrypts and the same key decrypts, which makes the scheme fast enough to sit in the path of a saturated network interface or a busy disk. The interesting operational questions are not about the cipher. They are about the mode it runs in, the nonce it consumes, and who holds the key.
Where the symmetric layer is actually doing the work
Asymmetric cryptography gets the attention because certificates are visible. Symmetric cryptography does the volume.
- The TLS record layer. Once a handshake completes, every application byte is protected by a symmetric AEAD key derived during that handshake. The certificate took no part in that protection beyond authenticating the party you agreed the key with.
- The SSH transport. Same shape: a key exchange establishes shared secrets, and the session that follows is symmetric.
- Block device encryption. LUKS and dm-crypt hold a volume key that encrypts sectors. The passphrase or keyfile unlocks a keyslot that unwraps the volume key; it is not itself the encryption key.
- Backups and object storage. Archive encryption, server-side encryption in an object store, and database transparent encryption are all symmetric with a key held somewhere else.
- Secret manager storage. The encrypted barrier that a secret manager writes to its storage backend is symmetric, wrapped by a key that only exists in memory while the service is unsealed.
The pattern to notice is that the key is almost never typed by a human and almost never stored beside the ciphertext. Where it does live, and who can ask for it, is the real access control. That is the subject of lesson 7 and of Part XV.
The mode is the decision, not the key length
“AES-256” names a block cipher and a key size. On its own it describes a function that transforms one 16-byte block. Turning that into something that can protect a 4 GB backup requires a mode of operation, and the mode is what determines whether you have confidentiality alone or confidentiality plus integrity.
| Mode | Provides | Operational note |
|---|---|---|
| ECB | Confidentiality, badly | Identical plaintext blocks produce identical ciphertext. Never appropriate. |
| CBC | Confidentiality only | Malleable. Needs a separate MAC, applied correctly, to be safe. |
| CTR | Confidentiality only | Turns the block cipher into a stream. Catastrophic on nonce reuse. |
| GCM | Confidentiality and integrity | An AEAD. The default for TLS and most storage. |
| ChaCha20-Poly1305 | Confidentiality and integrity | An AEAD. Faster than AES where the CPU lacks AES instructions. |
An estate that specifies “AES-256” in a policy document and nothing else has not made a decision. Two teams can both comply and end up with wildly different properties. TLS 1.3 made this explicit in its naming: a TLS 1.3 cipher suite specifies only the AEAD and the hash, because the key exchange and the authentication method are negotiated separately. A live handshake shows it plainly:
openssl s_client -connect app.lab.example:443 -servername app.lab.example </dev/null
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Protocol: TLSv1.3
Verify return code: 0 (ok)
TLS_AES_256_GCM_SHA384 names AES-256 in GCM with SHA-384 for
key derivation and nothing else. There is no RSA and no ECDHE in
that string, because in TLS 1.3 those are not part of the suite.
TLS 1.2 suite names look superficially similar and are not
interchangeable with these.
AEAD, and the field most people never use
Authenticated Encryption with Associated Data is a single primitive that takes a key, a nonce, the plaintext, and an optional block of associated data. It returns ciphertext and an authentication tag. On decryption it takes all of that back and either returns the plaintext or fails.
flowchart LR
K["Key"] --> E["AEAD encrypt"]
N["Nonce\nunique per key"] --> E
P["Plaintext"] --> E
A["Associated data\nauthenticated, not encrypted"] --> E
E --> C["Ciphertext"]
E --> T["Authentication tag"]
Three things follow from that diagram and each one matters in production. First, integrity is not optional and not a separate step, so there is no way for a developer to forget the MAC or to apply it in the wrong order. Second, decryption is all-or-nothing: a modified byte anywhere produces a tag failure and no plaintext at all, rather than plausible-looking corruption that flows onward into your data. Third, the associated data field lets you bind a ciphertext to its context without encrypting that context.
That third property is the underused one. If you store an encrypted field per row, putting the table name and the primary key into the associated data means a ciphertext lifted from row 42 cannot be pasted into row 7: the tag will not verify, because the associated data no longer matches. The same technique binds a wrapped key to the object it belongs to, which is the mechanism that makes the key hierarchy in lesson 7 safe against swapping attacks.
Nonces: the rule that turns a good algorithm into a bad day
An AEAD nonce must never repeat under the same key. This is not a best-practice recommendation; it is a hard precondition. Repeating a nonce in a counter-based mode reveals the exclusive-or of the two plaintexts, and in GCM it additionally exposes the value used to compute authentication tags, which lets an attacker forge tags for that key. A single accidental repeat is enough.
Operators do not usually choose nonces by hand, but they do choose the conditions that cause repeats:
- Cloning a running system. A virtual machine snapshot restored twice can replay the same in-memory counter state against the same key. Rekey after a restore that was not a clean boot.
- Reusing a key across processes. Two workers that each keep their own counter and share one key will collide. Nonce space must be partitioned or drawn at random from a large enough space.
- Encrypting more than the mode allows. Random 96-bit nonces
are safe for a large but finite number of messages under one
key. This is exactly why Kubernetes documents that the local
aesgcmprovider requires key rotation approximately every 200,000 writes, and it is why a key with no rotation plan is a design defect rather than a paperwork gap.
The same page documents aescbc as having weak strength because
of its padding oracle exposure, which is the practical
demonstration of the previous section: CBC without an integrity
mechanism lets an attacker learn plaintext by feeding modified
ciphertext to a service and watching how it fails.
resources:
- resources:
- secrets
providers:
- aesgcm:
keys:
- name: key-2026-08
secret: REDACTED
- identity: {}
A configuration of this shape is a statement that you will rotate
key-2026-08 on a schedule you have written down, that you know
the identity provider at the end is the read-only fallback for
data written before encryption was enabled, and that the key
material lives on the control-plane host in a file. Whether that
last point is acceptable depends entirely on your threat model,
and the alternative is a remote key service, which is where the
next parts of the course go.
Production discipline
- Specify the mode in every standard you write. A policy that says AES-256 and stops has delegated the security property to whoever implements it next.
- Give every symmetric key a rotation trigger. Time is one trigger. Volume of data encrypted is another, and for counter-based modes it is the one that actually binds.
- Bind ciphertext to context with associated data. Row identity, object path, tenant, purpose. It costs nothing and it removes an entire class of substitution attack.
- Treat a tag failure as an alertable event. Genuine corruption is rare. A sudden run of authentication failures is either a broken deployment or someone probing you.
- Do not build the construction yourself. Selecting an AEAD from your platform library is engineering. Composing a cipher with a hash by hand is a research project you did not budget for.
Cross-course references
- Linux for Production Sysadmins - Part LXXI (TLS) covers the service-side configuration that decides which of these suites a host will actually negotiate.
- Kubernetes for Production Sysadmins - Part LXV (SecretsSec) covers the encryption-at-rest providers whose mode choices this lesson explains, including why the local key file is the weak point.
- Observability for Production Sysadmins - Part LXIV (TLSMonitoring) covers measuring which protocol versions and suites are being negotiated in production rather than assuming the configuration took effect.
Quiz
Knowledge check · 4 questions
Q1. What does the cipher suite name TLS_AES_256_GCM_SHA384 tell you about a TLS 1.3 connection?
Q2. Reusing a nonce with the same key in AES-GCM can allow an attacker to forge authentication tags for that key.
Q3. What is the associated data field of an AEAD for, and give one production use of it.
Q4. Work out what property is missing and what you would change.
An internal service encrypts a per-customer token with AES-256-CBC and stores the result in a column. There is no MAC. A support tool decrypts the column and returns HTTP 400 with the message invalid padding when decryption fails, and HTTP 200 otherwise. Traffic to the tool is not rate limited.
Passing score: 75%. Answers are checked in this browser.