/kube-vault-auth-init

A Kubernetes init Docker image for authenticating against Vault

Primary LanguageShellMIT LicenseMIT

Kubernetes Vault Auth Init Docker Image

This Docker image is designed to bootstrap the Vault secrets in a Kubernetes pods. This uses the Kubernetes Auth Method to request the secrets required to generate an AppRole Auth role id and secret id.

This will then authenticate against the AppRole and provide the Vault token in a file that can be sourced by other containers that share the volume.

This is useful to externalise the Vault authentication from the containers you want to run. When used in conjunction with the Kubernetes Vault Auth Renewer, then the secrets can be injected into a container and renewed for as long as the pod is running, without the main container requiring any knowledge of Vault. This allows you to run public docker images without modification.

Prerequisites

A vault installation with the following auth methods enabled and configured:

The Kubernetes auth method must be configured with a policy

Policy used by Kubernetes auth to get the AppRole

This grants access to the AppRole role-id and secret-id which is required to generate an auth token for accessing secrets.

path "auth/approle/role/my-app-role/role-id" {
  capabilities = ["read"]
}

path "auth/approle/role/my-app-role/secret-id" {
  capabilities = ["update"]
}

Policy assigned to the token generated by the AppRole

This grants read access to the secrets our application needs.

path "consul/creds/my-acl-policy" {
  capabilities = ["read"]
}

path "secret/some/secret" {
  capabilities = ["read"]
}

Create an Kubernetes role

This should have a limited lifespan as it is only needed to bootstrap the AppRole.

vault write auth/kubernetes/role/my-kube-role \
    bound_service_account_names=my-app-service-account \
    bound_service_account_namespaces=my-namespace \
    policies=my-app-role-login-policy \
    ttl=300 \
    max_ttl=300 \
    num_uses=3

Create an AppRole

The 'secret_id_ttl' and 'secret_id_num_uses' should be kept limited, as we only used it to get a token.

We want a periodic token - this means that as long as it is renewed it never expires. 'Period' should be set with consideration to how often you want to renew the token. If you are going to check if it needs renewing 6 hours, then a sensible period might be 24 hours. Read the AppRole documentation to customise the other options based on your requirements.

vault write auth/approle/role/my-app-role \
    secret_id_ttl=5m \
    secret_id_num_uses=3 \
    period=24h \
    bound_cidr_list="10.0.0.0/32" \
    bind_secret_id="true" \
    policies="my-app-role-policy"

Using the init container

This is designed to be run as a Kubernetes init container, which means that it is run and terminates before the main pod containers are started. This allows us to request access to Vault and the secrets before the container starts.

Configuration

The init container requires the following environmental variables:

  • VAULT_ADDR - the full address of Vault, e.g. https://vault.example.com
  • KUBERNETES_AUTH_PATH - the name of the kubernetes auth method, e.g. kubernetes
  • VAULT_LOGIN_ROLE - the name the approle/kubernetes roles created above if they are both the same, e.g. my-app-role, otherwise use KUBERNETES_ROLE and APPROLE_ROLE
  • KUBERNETES_ROLE - the kubernetes role created above, defaults to VAULT_LOGIN_ROLE, e.g. my-kube-role
  • APPROLE_ROLE - the approle role created above, defaults to VAULT_LOGIN_ROLE, e.g. my-app-role

The following are optional:

  • KUBE_SA_TOKEN - used to inject the Kubernetes auth token, for testing without Kubernetes
  • VAULT_TOKEN - used to inject a Vault token, for testing without kubernetes of app_roles
  • VARIABLES_FILE - used to override the location of the outfile for testing
  • SECRET_* - any environment variable that starts with 'SECRET_' will be injected into the container with the value retrieved from Vault

SECRET_

Any environment variables that start with 'SECRET_' are used to request secrets from Vault. The value must be the path to retrieve a secret from in Vault, with the data key optionally provided.

For example:

SECRET_CONSUL_TOKEN=consul/creds/my-acl-policy?token

Will create:

CONSUL_TOKEN=some-consul-acl-token

Where 'some-consul-acl-token' is stored in the the 'token' attribute of the following secret: consul/creds/my-acl-policy

Or

If there are multiple variables for the same vault path then only one request is made and all data keys are retrieved from the same Vault response. This is useful in the case of requesting access to secret backends, like a database, where you need more one field to access the resource.

For example:

SECRET_DATABASE_USER=database/creds/readonly?username
SECRET_DATABASE_PASSWORD=database/creds/readonly?password

Will create:

DATABASE_USER=some-database-username
DATABASE_PASSWORD=some-database-password

Where 'some-database-password' corresponds to the temporary user 'some-database-username' in the configured database.

Or:

SECRET_SOME_SECRET=secret/from/somewhere

Will create:

SOME_SECRET=some-secret-value

Where 'some-secret-value' is stored in the the 'value' attribute of the following secret: secret/from/somewhere

Outputs

The output from this container is written to a file called /env/variables.

To make use of these you should mount this as a volume shared between this init container and your main application container and then run source /env/variables as part of your containers command.

The outputs are:

  • VAULT_TOKEN - The Vault auth token to use, of your application can talk to Vault directly
  • LEASE_IDS - A list of lease ids for the secrets defined in the SECRET_ variables above, this can be used to renew the secrets, see the Kubernetes Vault Auth Renew for a sidecar container that can do this for you
  • secret values - One for each of the SECRET_ variables defined above containing the value of the secret that was retrieved from Vault

Kubernetes deployment

kubectl apply -f myfile.yml

apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-app-service-account
---
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
  name: my-app
spec:
  template:
    metadata:
      labels:
        app: my-app
        tier: backend
    spec:
      serviceAccountName: my-app-service-account
      volumes:
      - name: shared-data
        emptyDir: {}
      initContainers:
      - name: vault-init
        image: quay.io/wealthwizards/kube-vault-auth-init
        env:
        - name: KUBERNETES_AUTH_PATH
          value: "kubernetes"
        - name: VAULT_ADDR
          value: "https://vault.example.com"
        - name: VAULT_LOGIN_ROLE
          value: "my-app-role"
        - name: SECRET_SOME_SECRET
          value: "secret/from/somewhere"
        volumeMounts:
        - name: shared-data
          mountPath: /env
      containers:
      - name: my-app
        image: my-app
        command: ["/bin/sh", "-c", "source /env/variables; ./run-my-app.sh"]
        volumeMounts:
        - name: shared-data
          mountPath: /env

Testing

Tests can be run by executing:

make test

This will use docker-compose to start Vault, a mock server (for simulate kubernetes) and any other required Vault secrets backends required by the tests.

Tests can be added as a script within the test/tests directory, and executed from the main test/test.sh script.