Secrets Provider - init container/sidecar - Kubernetes Secrets mode

This topic describes how to set up the CyberArk Secrets Provider for Kubernetes as an init container or sidecar, cyberark-secrets-provider-for-k8s, to populate Kubernetes Secrets with secrets stored in Conjur.

As an init container/sidecar, the Secrets Provider for Kubernetes is deployed in the same Pod as the application container, and serves only that application.

As a sidecar, secrets rotation and updates are supported.

How it works

This section shows how the Secrets Provider works.

  1. The cyberark-secrets-provider-for-k8s sidecar/init container, starts and authenticates to Conjur using the Kubernetes Authenticator (authn-k8s).​

  2. The cyberark-secrets-provider-for-k8s sidecar/init container reads all Kubernetes Secrets required by the Pod.

  3. For each mapped Kubernetes Secret, the cyberark-secrets-provider-for-k8s sidecar/init container:

    1. Fetches the Conjur secret

    2. Updates the Kubernetes Secret with the Conjur secret value

  4. If the Secrets Provider is an init container, it runs to completion.

    If the Secrets Provider is a sidecar and is configured to refresh secrets, after a specified interval the Secrets Provider checks if there are any updates to the secrets in Conjur. If changes are detected, the Secrets Provider sidecar updates the secrets files in Kubernetes Secrets.

    Moreover, the application can optionally delete secret files after consuming them. In this case, if changes are detected in the secrets in Conjur, the Secrets Provider sidecar recreates and rewrites the secret files to Kubernetes Secrets.

  5. The application container starts and consumes the Kubernetes Secrets.

Secret rotation and update detection

Supported by the Secrets Provider sidecar only.

If secrets are updated or if secrets rotation is enabled, the Secrets Provider sidecar container updates the secrets in the Kubernetes Secrets.

After a specified interval (default or specified by conjur.org/secrets-refresh-interval annotation in the Secrets Provider manifest), the Secrets Provider checks if the secrets have changed by comparing the SHA-256 checksums of the secrets with the previous checksums. The Secrets Provider does not save any of the unencrypted secrets.

If the time needed to fetch the secrets is longer than is specified for the interval, then the internal will be the actual time to retrieve the secrets.

For example: if the duration is set to two seconds, but retrieving the secrets takes three seconds, then the secrets are updated every three seconds.

If a secret is deleted from Conjur or if access to the secret has been revoked, the Secrets Provider deletes the secret from Kubernetes Secrets.

Set up Secrets Provider as an init container/sidecar

This section describes how to set up the Secrets Provider for Kubernetes as an init container/sidecar.

Decode Base64-encoded secrets

If the secrets stored in Conjur are Base64-encoded strings, Secrets Provider can decode the secrets before providing them to the application. You configure Secrets Provider to decode these strings using annotations and configuring the Kubernetes Secret with a conjur-map.

To add Base64 decoding to a Kubernetes Secret, modify the conjur-map by adding an id: and content-type: base64 to the string to decode.

For example, the following Kubernetes Secret configuration doesn't use Base64 decoding.

apiVersion: v1
kind: Secret
metadata:
  name: test-app-secrets-provider-k8s-secret
type: Opaque
stringData:
  conjur-map: |-
    DB_URL: test-secrets-provider-k8s-app-db/url
    DB_USERNAME: test-secrets-provider-k8s-app-db/username
    DB_PASSWORD: test-secrets-provider-k8s-app-db/password

In the following example, Base64 decoding is enabled for the DB_PASSWORD value using the id: and content-type: base64 annotations.

apiVersion: v1
kind: Secret
metadata:
  name: test-app-secrets-provider-k8s-secret
type: Opaque
stringData:
  conjur-map: |-
    DB_URL: test-secrets-provider-k8s-app-db/url
    DB_USERNAME: test-secrets-provider-k8s-app-db/username
    DB_PASSWORD:
      id: test-secrets-provider-k8s-app-db/password
      content-type: base64

If the secret can't be decoded, a warning is added to the log files.

Secrets Provider only decodes secrets in Base64 format.

Check Secrets Provider status using sentinel files

Supports Secrets Provider v1.4.1 and later.

Secrets Provider allows for its status to be monitored through the creation of two empty sentinel files: CONJUR_SECRETS_PROVIDED and CONJUR_SECRETS_UPDATED.

The CONJUR_SECRETS_PROVIDED file is created when the Secrets Provider has completed its first round of providing secrets via Kubernetes Secrets. It creates or recreates the CONJUR_SECRETS_UPDATED file whenever it has updated Kubernetes Secrets. If needed, application containers can mount these files via a shared volume.

The Pod would need a Volume defined as follows:

 volumes:
    - name: conjur-status
      emptyDir:
        medium: Memory

The application container and Secrets Provider container would need to include volumeMounts as follows:

volumeMounts:
    - mountPath: /conjur/status
      name: conjur-status

The sentinel files delay the start of the application until after the Secrets Provider has started up and written the secrets. Kubelet starts the Pod containers in the order they are listed in the manifest. A postStart lifecycle hook can be added to the Secrets Provider manifest to delay the start of the application container until the postStart lifecycle hook is complete.

        lifecycle:
          postStart:
            exec:
              command:
              - /usr/local/bin/conjur-secrets-provided.sh

For an example of the Secrets Provider script, see conjur-secrets-provided.

If a livenessProbe is not already being used by the container as a health probe, you can use a livenessProbe as a "file watcher" and can cause the application to be restarted after the secrets have been updated. The livenessProbe could look as follows:

livenessProbe:
          exec:
            command:
            - /conjur/status/conjur-secrets-unchanged.sh
          failureThreshold: 1
          initialDelaySeconds: 5
          periodSeconds: 5
          successThreshold: 1
          timeoutSeconds: 1