/

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 or ConfigMap 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 or ConfigMaps, where the AzureKeyVaultSecret has spec.output.secret or spec.output.configMap defined (like in the example above)
  • periodically poll Azure Key Vault for changes and apply to the Kubernetes Secret or ConfigMap

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.

  • 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:

    1. The init-container will start
    2. 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:

    1. 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)
    2. Connect to Azure Key Vault, using credentials from previous step
    3. Download all Azure Key Vault objects, identified by the environment placeholders
    4. 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.✨

Edit on GitHub