How it Works
Learn about the inner workings of akv2k8s.
Akv2k8s consist of three main components:
- a Custom Resource Definition called
AzureKeyVaultSecret
- Controller
- Env Injector
The AzureKeyVaultSecret CRD
The AzureKeyVaultSecret
Custom Resource Definition (CRD) contains metadata used by the Controller and Env Injector to access objects in Azure Key Vault. For each secret, certificate or key in AzureKeyVault that you want available in Kubernetes, you create a AzureKeyVaultSecret
and provide:
- The Kubernetes namespace where the Azure Key Vault secret should be available
- The name of the Azure Key Vault
- The name, type and version (optional) of the Azure Key Vault object
- Optionally a Kubernetes
Secret
orConfigMap
and data-key to sync to
An example AzureKeyVaultSecret
looks like this:
# secret-sync.yaml
apiVersion: spv.no/v2beta1
kind: AzureKeyVaultSecret
metadata:
name: secret-sync
namespace: akv-test
spec:
vault:
name: akv2k8s-test # name of key vault
object:
name: my-secret # name of the akv object
type: secret # akv object type
output: # optional - only used to sync to a kubernetes secret
secret:
name: my-secret-from-akv # kubernetes secret name
dataKey: secret-value # key to store object value in kubernetes secret
The Controller
The Controller is responsible for:
- syncing Azure Key Vault objects into Kubernetes
Secret
's orConfigMap
s, where theAzureKeyVaultSecret
hasspec.output.secret
orspec.output.configMap
defined (like in the example above) - periodically poll Azure Key Vault for changes and apply to the Kubernetes
Secret
orConfigMap
The Env Injector
The Env Injector is a bit more complicated than the Controller and consists of:
- a Mutating Admission Webhook (see Kubernetes docs)
- a Docker image (spvest/azure-keyvault-env) containing the
azure-keyvault-env
executable
Below are the steps that gets executed for a Pod using env-injection.
- 1
The Mutating Admission Webhook triggers
The Env Injector webhook gets triggered just before every Pod gets created and inspects the Pod definition for environment variables containing
@azurekeyvault
(see example below). If it does not find any, the Pod start as normal. If it does, it mutates (changes) the Pod with:- A init-container (image: spvest/azure-keyvault-env) with a in-memory volume at
/azure-keyvault/
- Akv2k8s own executable instead of the original executable in the Pod (more on that later)
- Multiple environment variables with akv2k8s specific information
- A client certificate is generated for the Pod to use when requesting Azure Key Vault credentials
Example where environment variable has value containing
@azurekeyvault
:env: - name: MY_AKV_SECRET value: some-secret@azurekeyvault
As mentioned, the Pod container gets mutated to use a different executable. It does this by changing either the CMD or the ENTRYPOINT, depending on which was used by the original container, to use the
azure-keyvault-env
executable instead. The "old" command gets passed in as parameter to this new executable. - A init-container (image: spvest/azure-keyvault-env) with a in-memory volume at
- 2
The Pod starts the init-container
When the Env Injector webhook is finished, Kubernetes will start the Pod with the mutated changes. This will trigger the following sequence:
- The init-container will start
- The init-container copies the
azure-keyvault-env
executable into/azure-keyvault/
The volume
/azure-keyvault/
in the Pod is shared between its containers (the init-container and the original container) and is how the init-container can "give" the original container its executable. - 3
The Pod starts the original container
When the original container starts, it will execute the
azure-keyvault-env
command, which will:- Get Azure Key Vault credentials from the Env-Injector auth service (using client certificate from earlier) or from local environment (depending how auth is configured - see Authentication for details)
- Connect to Azure Key Vault, using credentials from previous step
- Download all Azure Key Vault objects, identified by the environment placeholders
- Execute the original command and params, pass on the updated environment variables with real secret values
✨The end result is secrets injected transparently in-memory during container startup. It will not reveal any of the actual secrets in the container spec, disk or logs. The only component containing the actual secrets is the application process.✨