Base64 Is Not Encryption: Kubernetes Secrets, Key Vault and Redis Cache Words Explained

October 1, 2026 · How It Actually Works: Real Systems as State Machines (part 13)

▶ Watch on YouTube & subscribe to The Stack Underflow

Two deep dives in this series follow one Spring Boot bookstore on AKS. In one, the database password travels from Azure Key Vault into a pod. In the other, book 42 is cached in Redis so most reads skip the database. Both lean on words that are easy to mix up: a Secret that isn’t encrypted, a cache hit, a TTL. This primer gives you the words first, each with a memory peg.

The one-line version: a Kubernetes Secret is an envelope, not a lock, and a cache is a copy, not the truth.

Last verified against kubernetes.io, Microsoft Learn, redis.io and the Spring reference docs: 1 October 2026. The facts match the deep dives: Kubernetes 1.37 docs, the AKS Key Vault provider add-on with Microsoft Entra Workload ID, Spring Boot 4.1.1, Spring Framework 7.0.9, Spring Data Redis 4.1.1 and Azure Managed Redis.

Every word gets a peg from one of two pictures: a bank vault and its couriers for secrets, and a restaurant’s pass for caching. Pegs are memory aids (analogies), not facts; the text says where each one stops matching.

Secrets inside the cluster

WordMemory peg (analogy)What it actually is
ConfigMapA notice on the pinboardAn API object for non-confidential key-value settings. The Kubernetes docs say it gives no secrecy or encryption.
Kubernetes SecretAn envelope in the mailroom (base64 is not a lock)An object for a small amount of sensitive data, such as a password, a token or a key
etcd, encryption at restThe mailroom locked overnightetcd is the key-value store behind the API server. Encryption at rest protects stored data, not API readers
Volume, mountThe pod’s locked drawerA directory the pod’s containers can access; the mount is where it appears in a container
Environment variableA note taped to the deskSet from a Secret when the container starts, and not refreshed while it runs
Kubernetes RBACWho holds a key to the mailroomA Role lists allowed verbs; a RoleBinding grants it. There are no deny rules

Base64 is an encoding. In a manifest, Secret values are written in base64. The Kubernetes docs are explicit: base64 “is not an encryption method”, and checking such a manifest into a repository makes the secret available to everyone who can read it. Anyone who can read the manifest, or get the Secret through the API, decodes it in one command.

Where Secrets are stored. Upstream, Kubernetes stores Secrets unencrypted in etcd by default. On AKS, Azure always encrypts that storage at rest, and KMS can add a layer with a key from Key Vault. Where the peg breaks: locking the mailroom overnight stops someone carrying off the shelves, not a clerk with a key. API readers still get the plain value.

Files versus environment variables. Secret and CSI volumes live in tmpfs, in memory, and go away with the pod; anyone allowed to exec into the container can still read the files. A mounted file can be updated in place (not with subPath), but the app must read it again. An environment variable won’t see a change until the container restarts.

The key ring is bigger than it looks. RBAC that allows get, list or watch on Secrets reveals their contents. And anyone who can create a pod in a namespace can read the Secrets in that namespace, because the pod can mount them.

The bank vault and its couriers

WordMemory peg (analogy)What it actually is
Azure Key VaultThe bank vaultAzure’s store for secrets, keys and certificates. A new value under the same name becomes a new version
Managed identityAn account at the bankA Microsoft Entra identity for a workload; Azure manages its credentials, you never see them
Service accountThe courier’s staff recordA non-human identity in the cluster. Pods get short-lived, automatically rotating tokens for it
Workload identityThe courier’s ID badge, checked by Entra ID at the bank’s front deskEntra ID exchanges a trusted cluster token for an access token
Federated credentialThe trust letter”Trust tokens from this issuer, for this subject, with this audience”
Secrets Store CSI driverThe courierMounts secrets from an external store into a pod as a volume, through a provider
RotationThe courier restocks the drawerReplacing a secret’s value regularly; in Key Vault the new value is a new version

Access to the vault is Azure RBAC, not Kubernetes RBAC. The identity gets a role assignment on the vault, here Key Vault Secrets User, which Microsoft describes as “Read secret contents including secret portion of a certificate with private key”: it can read, not change. Don’t confuse the two RBACs: one guards the mailroom, the other the vault.

Proving who you are without a password. The cluster acts as a token issuer and publishes the public keys that check its tokens. Entra ID finds those keys through OIDC discovery, verifies the token’s signature, and checks issuer, subject and audience against the federated credential. If all match, it returns an access token. When a pod starts, the driver and the Azure provider on that node make this exchange, fetch the secret, and write it into the pod’s volume. If that fails, the pod waits in ContainerCreating.

Rotation is opt-in. On the AKS add-on, autorotation is off by default ("enableSecretRotation": "false"). Turned on, the provider polls for changes based on the rotation poll interval, two minutes by default, and updates the mounted files and any synced Kubernetes Secret. Where the peg breaks: the note taped to the desk is never restocked. Environment variables, and Spring’s cached config tree, need a restart.

Now the kitchen: cache words

WordMemory peg (analogy)What it actually is
CacheReady dishes, kept closeTemporary copies of frequently accessed data, closer to the app than the source
RedisThe warming shelf by the passAn in-memory data store; here it holds copies, not the truth
Database of recordThe kitchenWhere the real value lives
Key and valueThe label on the plate; the value is the dishA unique key; a Redis string value is a sequence of bytes
Cache hitThe dish is already on the shelfThe stored copy is returned and your method never runs
Cache missCook it, put a copy on the shelfThe method runs, queries the database, and the result is stored
Cache-asideCheck the shelf firstRead the cache; on a miss load and store; on a write update the store, then remove the copy

Microsoft’s caching guidance says to cache data that’s read often and changed rarely, and not to use the cache as “the authoritative store of critical information”. On Azure Managed Redis, replication is asynchronous, so an unexpected failover can lose a little recently written data. Fine for copies, not for the truth.

What Spring does for you. Put @Cacheable("books") on findById(42) and a proxy runs cache-aside for you, under the Redis key books::42 (cache name, ::, the single parameter). Calls from inside the same class skip the proxy.

Keeping copies honest

WordMemory peg (analogy)What it actually is
SerializationBoxing the dishObject to bytes before storing; bytes back to an object on a hit
TTLThe timer card on each plateTime to live: when it runs out, the key expires
EvictionClearing old plates when the shelf is fullWhen memory reaches maxmemory, the eviction policy picks keys to remove
Invalidation, @CacheEvictThrowing a plate away: the recipe changedDelete the copy after the data changes
Cache stampedeEveryone orders the missing dishThe common informal name for many requests missing the same key at once

Serialization. Spring Data Redis’s default value serializer is Java serialization (JdkSerializationRedisSerializer); JSON serializers exist too. After a deploy changes the class, old boxes may not open.

TTL and expiry. Redis expires keys two ways: passively, when a client touches an expired key, and actively, by periodically testing a few random keys that have an expiration. The trap: Spring Boot’s Redis cache sets no TTL by default, so entries never expire. Set spring.cache.redis.time-to-live.

Eviction is not expiry. One follows memory pressure, the other a timer. Open-source Redis, by default, has no memory limit on 64-bit systems and the noeviction policy. Azure Managed Redis defaults to volatile-lru, which only evicts keys that have a TTL. Redis’s docs say the volatile-xxx policies “behave like noeviction if no keys have an associated expiration”: writes get an error, reads keep working.

Stale data. When book 42 changes in the database, the Redis copy doesn’t. @CacheEvict removes it after your update method succeeds. Update first, then evict; the other order lets a reader re-cache the old value.

Stampedes. By default Spring’s cache abstraction locks nothing, and Spring Data Redis’s default cache writer is lock-free. The deep dive shows the opt-in locking writer, and why its lock covers the whole cache.

Pause & Prove

1. Your database password is in a Kubernetes Secret, written in base64. Name three kinds of people who can read it.

  • Anyone who can read the manifest. Base64 decodes in one command, so a manifest in a repository leaks the value.
  • Anyone allowed to get, list or watch Secrets in that namespace. Those RBAC verbs reveal the contents.
  • Anyone who can create a pod in the namespace. The pod can mount the Secret, so pod creators can read it.

Encryption at rest protects etcd’s storage, not API readers.

2. The values in a Kubernetes Secret’s manifest are base64. Base64 is…

  • Encryption. Tempting, because the value looks scrambled. There is no key: anyone can decode it.
  • An encoding. ✓ It changes the representation, not who can read it.
  • A hash. A hash can’t be reversed; base64 can, in one command.
  • A signature. A signature proves who produced data. Base64 proves nothing.

Upstream, Secrets are stored unencrypted in etcd by default; on AKS, Azure encrypts that storage at rest.

3. Peg drill

Say the peg before you look: Kubernetes Secret, workload identity, CSI driver, cache miss, TTL, @CacheEvict. (An envelope in the mailroom, base64 is not a lock · the courier’s ID badge · the courier · cook it, put a copy on the shelf · the timer card on each plate · throwing a plate away: the recipe changed.)

After this video

Sources

Defaults, dates and version-specific claims were re-checked on these pages on 1 October 2026; the ConfigMap, volume, RBAC, service account and CSI driver definitions come from the video’s own source check (29 September 2026):

Change notes

  • 1 Oct 2026: first published.

Not affiliated with or endorsed by Microsoft, The Linux Foundation, Redis Ltd., or VMware Broadcom (Spring). Found a mistake? Tell us in the video’s comments and we’ll correct this page.

Found this useful? The deep version lives on YouTube — new breakdowns of how AI dev tools actually work, weekly.

Subscribe on YouTube →

Prefer email? Get the free newsletter: one failure, traced step by step, about once a week.