Two secrets-management paths lead from a secure vault into Kubernetes workloads

The real question is not whether to use the Azure Key Vault provider for the Secrets Store CSI Driver or the External Secrets Operator (ESO). Instead, it’s whether your workload should access secret data as mounted files or via native Kubernetes Secret objects.

That choice influences application design, rotation, incident handling, RBAC, observability, Helm compatibility, and GitOps. In short: CSI offers a more secure default for applications that consume files; ESO provides a more practical platform default when Kubernetes-native compatibility is a priority. This decision involves both GitOps and security considerations.

How each one actually works

The AKS-managed Azure Key Vault provider runs with the Secrets Store CSI Driver. A pod references a namespaced SecretProviderClass and mounts an inline CSI volume. During mount, the provider authenticates to Key Vault, retrieves the requested objects, and materializes them in the pod filesystem. It creates no Kubernetes Secret unless secretObjects is configured. Microsoft documents support for secrets, keys, certificates, auto-rotation, and optional Kubernetes Secret synchronization.

ESO is a controller. An ExternalSecret references a namespaced SecretStore or cluster-scoped ClusterSecretStore. The controller authenticates to Key Vault, reads the remote values, and creates or updates a normal Kubernetes Secret. Pods then consume that object through environment variables or projected volumes. Key Vault remains the source of truth, but secret material now also exists in the Kubernetes API data path.

CSI mounts secret material as files while ESO first creates a Kubernetes Secret

That extra object is neither automatically wrong nor free. It is the central tradeoff.

The core tradeoff: where secrets live

CSI’s default file-only pattern avoids storing secret values as Kubernetes Secret objects. This reduces the number of entries in etcd and keeps secrets hidden from standard Secret-listing processes, limiting the entities that can access them via the API. However, it does not prevent access if a malicious application, privileged pod, node, or identity with read access to the mount is present. CSI reduces the attack surface but doesn’t eliminate it.

The price is compatibility. Kubernetes cannot directly populate an environment variable from a CSI-mounted file. Many standard Helm charts require `a secretKeyRef, and some operators accept only a Secret name. While CSI secret sync is possible, it removes the architectural benefit of having “no Kubernetes Secret” for that value.

ESO supports native Secrets, so existing charts, operators, admission policies, backup exclusions, and developer workflows work without modifications. Git only keeps references and templates, not actual values, while the controller generates the runtime objects. This approach increases the impact of the Kubernetes API and RBAC: anyone with read access to the generated Secret can obtain its value.

Avoid simplifying to “etcd is encrypted” or “etcd is plaintext." Remember, Kubernetes Secret data is merely base64-encoded, not encrypted directly by the Secret resource. AKS safeguards the underlying service storage and provides Kubernetes KMS-based encryption for Secrets, using either platform-managed or customer-managed keys. In regulated settings, explicitly verify the KMS configuration, API access, key ownership, backups, and support processes.

Rotation and freshness are consumer problems

CSI autorotation periodically polls Key Vault; the AKS add-on documents a default rotation poll interval of two minutes when autorotation is enabled. It updates mounted content and, if configured, the synced Kubernetes Secret. An application reading the CSI filesystem must watch for file changes or reopen the file. A pod restart is not inherently required for a normal file mount. A subPath mount does not receive automatic updates, and an environment variable sourced from a synced Secret requires a restart or rollout.

ESO’s default Periodic policy reads the provider on spec.refreshInterval and updates the target Secret. It also supports CreatedOnce and OnChange. Updating the Secret does not guarantee that the process has adopted the value: projected Secret volumes eventually update, but the application must reread them; environment variables remain fixed for the life of the container.

The honest rotation SLO is therefore:

provider polling delay + controller or driver reconciliation + Kubernetes propagation + application reload delay

Monitor the full chain. A green Key Vault rotation event says nothing about the credential a long-running process currently holds.

Identity and authorization in production

Both approaches can use Microsoft Entra Workload ID on AKS, avoiding static client secrets. I covered the broader identity principle in Identity Is the Perimeter You Forgot to Guard; the key point is to give each trust boundary its own identity and the minimum Key Vault role.

For CSI, SecretProviderClass is namespaced, and the consuming pod drives the mount. With Workload Identity, its service account determines the Azure identity. Permission to create a SecretProviderClass does not itself grant Key Vault access, but arbitrary service-account and provider pairings still deserve policy control.

ESO adds a controller-mediated boundary. A SecretStore is namespaced; a ClusterSecretStore is reusable across namespaces and can be restricted with namespace conditions. Decide whether ESO uses one central identity, referenced service accounts, or per-namespace identities. Restrict both who may reference a store and what its Azure identity may read. A cluster-wide store backed by a vault-wide reader becomes a high-value broker.

GitOps fit

ESO’s API maps cleanly to GitOps: commit ExternalSecret and SecretStore, let Flux reconcile them, and let ESO materialize the Secret. Status conditions expose whether the runtime object is current. This fits the reconciliation model in GitOps on Azure Kubernetes Service with Flux without placing secret values in Git.

CSI’s SecretProviderClass, service account, and pod volume declaration are equally valid GitOps resources. The friction appears at the application contract: a chart that insists on an existing Secret cannot declare the file-only state you want. Patching charts, adding init logic, or enabling CSI sync creates platform exceptions that Flux can reconcile but your team must still own.

Neither controller makes Git a secret store. Commit remote keys, vault URIs, templates, and identity bindings; never commit the values or a rendered Secret manifest.

Multi-cloud and multi-backend reality

ESO supports providers including Azure Key Vault, AWS Secrets Manager, Google Secret Manager, and HashiCorp Vault. That helps when one platform spans clouds or must migrate backends, although provider semantics and maturity vary.

The Secrets Store CSI Driver itself has multiple providers, but the AKS-managed add-on and operational path discussed here use the Azure Key Vault provider. That Azure focus is an advantage for a single-cloud AKS estate: Microsoft manages the add-on lifecycle and integration. It is a constraint if a single platform contract must span clouds and backends.

Production comparison

DimensionSecrets Store CSI DriverExternal Secrets Operator
Secret object created?No by default; optional secretObjects sync creates oneYes; ExternalSecret creates or updates a native Secret
Rotation mechanismDriver/provider poll; updates mount and optional synced SecretController reconciliation using refreshPolicy and refreshInterval
GitOps compatibilityCRDs and pod specs reconcile cleanly; file consumption can conflict with chart assumptionsStrong fit for native Secret consumers and declarative CRDs
Multi-backend supportProvider ecosystem exists; AKS-managed path is Azure Key Vault-specificBroad provider catalog across clouds and secret stores
Operational overheadAKS manages the add-on, but every workload needs volume wiring and reload behaviorYou operate and upgrade the controller, CRDs, RBAC, stores, and controller capacity
Failure if Key Vault is unreachableExisting pods retain their last mounted content; rotation fails, and new mounts or pod starts can failExisting generated Secrets remain usable; refresh reports errors, and pods can still start while the Secret exists

The outage row matters in production. ESO deliberately creates a local cache in Kubernetes, which can improve workload startup during a Key Vault outage but extends the lifetime and reach of secret material. CSI keeps fewer copies but creates a new pod mount that depends on Key Vault, identity, network, provider, and node-plugin health. Test both stale-secret behavior and scale-out during a denied-vault or blocked-egress exercise.

Decision guide

Decision guide for choosing CSI file mounts or External Secrets Operator

Choose CSI when minimizing Kubernetes Secret objects is a real control objective, workloads can read mounted files, your estate is Azure-centric, and you can implement file reload plus startup-failure handling. It is especially compelling for certificates and applications already designed around filesystem credentials.

Choose ESO when existing tooling requires native Secrets, teams rely heavily on Helm conventions, one platform contract must cover several backends, or GitOps consistency matters more than avoiding the Secret object. Pair it with tight Secret RBAC, explicit KMS requirements, short-lived credentials, namespace-scoped stores where practical, and alerting on stale reconciliation.

Do not choose CSI and then enable Secret sync everywhere without acknowledging that you have effectively selected both trade-offs. Do not choose ESO merely because the manifest is shorter while ignoring controller identity and cluster-wide store scope.

My take

For a smaller AKS workload within a single team, I default to the AKS-managed CSI add-on if the application reads files natively. It removes a controller from the platform and, by default, avoids creating Kubernetes Secrets. If the application or chart expects secretKeyRef, I would use ESO rather than wrap the workload in brittle glue.

For a platform team standardizing across clusters, namespaces, and secret backends, ESO is usually the better paved road. Its CRDs align with how Flux-based platforms already express the desired state, and native Secrets minimize exceptions for product teams. That recommendation comes with a non-negotiable set of controls: scoped stores, separated workload identities, restricted Secret reads, KMS posture, stale-sync alerts, and tested rotation reloads.

Running both is not an architectural failure. Use CSI for workloads whose security model benefits from file-only delivery, and ESO for workloads that need the Kubernetes Secret contract. The mistake is not having two tools; it is letting teams choose without defining which secret classes, identities, and failure modes belong to each path.

Sources and validation notes

Validated against Microsoft, Kubernetes, and External Secrets Operator documentation in September 2026. Be aware that versions, preview status, defaults, and provider behavior may change; verify the target AKS release and ESO version before deploying in production.