It’s one of those things that can be a real headache if you don’t automate the pain away, particularly when it comes to a large number of clusters
Enter The External Secrets Operator
What problem does this solve?
If your organisation is anything like mine, secret management at scale can become a real issue (Yes, we have historically seen secrets committed to git).
Managing secrets using ESO means you can quickly rotate compromised credentials, update expired credentials and keep secrets out of your code repository while still continuing to use your GitOps workflow. It also offers the ability to programmatically rotate the credentials periodically, improving security posture and minimising human error.
What does it do?
The external secrets operator manages the lifecycle of secrets within a Kubernetes cluster. This could be a container registry pull credential, an API key, password or any other sensitive data worth protecting.
ESO integrates with a number of backends such as Hashicorp Vault, Azure Key Vault, AWS, etc. https://external-secrets.io/latest/provider/azure-key-vault/
How does it work?
ESO adds a new Custom Resource Definition to the cluster called an ExternalSecret. This object is a reference to an entry stored within your vault of choice. You can then set a reconcile threshold to periodically query your vault for changes.
Scenario
You have a one year lifecycle on a pull credential for Azure Container Registry. You receive a notification that in 30 days the credential is going to expire. You generate a new credential, update the value in the vault and the External Secrets Operator will automatically pull in the new value without any further user interaction
Example
Here’s a registry credential I make available to my Jenkins instance. This makes the secret “regcred” available for my build agents to consume. The artifact is committed to git, but contains no secret data of its own. Only a reference point to the vault.
| |
Creating the Azure Key Vault and Configuring Authentication
Environment: Talos v1.11.5 | Kubernetes v1.34.2
Before storing or retrieving secrets, you need an Azure Key Vault instance for your secrets, and configure how your cluster will authenticate to it.
1. Create the Azure Key Vault
If you do not already have a Key Vault, create one:
| |
2. Authentication Methods
You can configure the External Secrets Operator to authenticate to Azure Key Vault in a variety of ways depending on where it’s hosted. We won’t touch on all the possibilities as they are well documented here.
However, here are the 2 primary ones we consume in my environment:
Example A: Using a Managed Identity (Recommended in AKS)
This is the one we use for both our AKS Clusters, and also for our Openshift clusters at the edge. A Workload Identity or Managed Identity is created with access to the vault and then we minimise the requirements for ongoing secrets management into the vault itself.
Configure your SecretStore or ClusterSecretStore to use a managed identity assigned to your AKS cluster/node pool.
| |
Notes:
- Use
authType: WorkloadIdentityfor clusters using Azure AD Workload Identity - Use
authType: ManagedIdentityif using legacy AKS managed identities - Set
identityIdto the client ID of your user-assigned managed identity if not relying on the default
Example B: Using a Client ID/Secret
This is handy for clusters that may not easily integrate with Azure, It uses a more traditional client id/secret method. This means you will still have to maintain at least 1 secret value per SecretStore/ClusterSecretStore that you want to authenticate with.
First, create an App Registration/Enterprise application and grant it access to the vault with a read only role.
Once created, create a client secret and create a yaml definition with your values as shown.
| |
Then configure your SecretStore or ClusterSecretStore:
EG:
| |
For more details and advanced authentication options, see the external-secrets documentation.
Be sure your app registration/enterprise app, service principal, or managed identity has set, get, and list permissions on secrets:
| |
SecretStores - Where the objects are referenced
External Secrets Operator supports two main types of “secret stores”. A SecretStore/ClusterSecretStore is a reference to your vault of choice within Kubernetes and acts as a logical permissions boundary for the secrets to be ingested.
- SecretStore: This is a namespaced resource. Secrets retrieved via a
SecretStoreare only available inside the same namespace the store is defined in. - ClusterSecretStore: This is a cluster-scoped resource. Secrets from a
ClusterSecretStorecan be referenced byExternalSecretsobjects in any namespace, not just one.
ClusterSecretStore is especially useful when you want to reference the same secret value across multiple namespaces, such as a common container registry pull credential minimising the need to update the value in multiple places.
Example YAML fragments:
ClusterSecretStore (cluster-scoped, available to all namespaces):
| |
SecretStore (namespace-scoped, only for one namespace):
| |
The important takeaway from this is you now only manage a much smaller subset of secrets - the one secret into the Vault(s). Everything else is abstracted away.
Updating a secret can now be done easily by updating the value directly in Azure Key Vault—either using the Azure CLI or the Azure Portal web interface.
Managing and updating secrets
Once you’ve set up authentication into the vault, you’ll then want to manage and update the secrets contained in the vault for consumption in your cluster. There are a few ways to approach it.
The general rule of thumb is that you want to use the “az” cli commands for files, and the webUI for strings
A. Using Azure CLI:
For example, to update (set) a secret value from the command line:
| |
B. Using the Azure Portal (GUI):
- Go to https://portal.azure.com and open your Azure Key Vault.
- In the left menu, select Secrets.
- Select the secret you want to update.
- Click + New Version, enter the new value, and click Create.
After updating the secret value in Key Vault (via CLI or the Portal), the External Secret will automatically sync the change to your Kubernetes secret on the next refresh.
That’s all for this post. I hope you found it useful. If there’s any information you want clarified, thoughts, or opinions, please do let me know.