External Secret Operator

External Secrets Operator (ESO)

External Secrets Operator (ESO) is a Kubernetes (K8s) operator that integrates with external secret management systems like Akeyless. The operator reads information from Akeyless APIs and automatically injects the values into a K8s Secret. More information can be found under Akeyless official provider.

The goal of the ESO is to synchronize secrets from Akeyless into K8s. ESO is a collection of custom API resources - ExternalSecret, SecretStore, and ClusterSecretStore that provide a user-friendly abstraction for the external API that stores and manages the lifecycle of the secrets for you.

The ESO runs within your K8s cluster as a deployment resource. It utilizes CustomResourceDefinitions to configure access to secret providers through SecretStore resources and manages K8s secret resources with ExternalSecret resources.

Prerequisites

  • Helm
  • K8s v1.16 and above (users that are still running K8s v1.15 or below should upgrade to a supported version before installing external-secrets).

Installing with Helm

External Secrets Official Git: https://github.com/external-secrets/external-secrets

helm repo add external-secrets https://charts.external-secrets.io
helm install external-secrets external-secrets/external-secrets # -n external-secrets --create-namespace

SecretStore

The idea behind the SecretStore resource is to separate concerns of authentication/access and the actual Secret and configuration needed for workloads. The ExternalSecret specifies what to fetch, and the SecretStore specifies how to access it. This resource is namespaced.

Authentication methods:

Akeyless providers require an accessId, accessType, and accessTypeParam
To set your SecretStore with an authentication method from Akeyless, create a secret item on your cluster that contains the following settings:

apiVersion: v1
kind: Secret
metadata:
  name: akeyless-secret-creds
type: Opaque
stringData:
  accessId: "p-XXXX"
  accessType:  # k8s/aws_iam/gcp/azure_ad/api_key
  accessTypeParam:  # replace by the appropriate value for: <k8s-conf-name>/<gcp-audience>/<azure-obj-id>/<access-key>

👍

Note

  • Ensure that an Access Role is defined in Akeyless for the credentials you specify and that the Access Role is associated with an Authentication Method that allows access to the required secret.

  • If you define the value of accessType as api_key, define the value of accessTypeParam as your access key.

Create the secret item for authentication:

kubectl apply -f akeylesscreds.yaml

Alternatively, you can explicitly specify the secret details as described in the K8sSecretStore example below:

Create the Akeyless SecretStore Provider:

apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: akeyless-secret-store
spec:
  provider:
    akeyless:
      # URL of your akeyless API
      akeylessGWApiURL: "https://api.akeyless.io"
      authSecretRef:
        secretRef:
          accessID:
            name: akeyless-secret-creds
            key: accessId
          accessType:
            name: akeyless-secret-creds
            key: accessType
          accessTypeParam:
            name: akeyless-secret-creds
            key: accessTypeParam
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: akeyless-secret-store
spec:
  provider:
    akeyless:
      # URL of your akeyless API
      akeylessGWApiURL: "https://api.akeyless.io"
      authSecretRef:
        kubernetesAuth:
          accessID: "p-XXXXXX"
          k8sConfName: "my-conf-name"
          # Optional service account field containing the name
          # of a kubernetes ServiceAccount
          serviceAccountRef:
            name: "my-sa"
          # Optional secret field containing a Kubernetes ServiceAccount JWT
          # used for authenticating with Akeyless
          #secretRef:
           # name: "my-secret"
            #key: "token"

👍

Note

  • Make sure the Akeyless provider is listed in the Kind=SecretStore.

  • If you use a customer fragment, define the value of akeylessGWApiURL as the URL of your Akeyless Gateway in the following format: https://your_akeyless_gw:8080/v2.

Create the Secret Store:

kubectl apply -f secretstore.yaml

Creating an External Secret:

To fetch a secret from Akeyless and store it as a K8s secret on your cluster, a Kind=ExternalSecret is required.

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: akeyless-external-secret-example
spec:
  refreshInterval: 1h

  secretStoreRef:
    kind: SecretStore
    name: akeyless-secret-store # Must match SecretStore on the cluster

  target:
    name: akeyless-secret-to-create # Name for the secret to be created on the cluster
    creationPolicy: Owner

  data:
    - secretKey: secretKey # Key given to the secret to be created on the cluster
      remoteRef:
        key: /path/to/your/secret # Full path of the secret on Akeyless

Create the ExternalSecret item:

kubectl apply -f externalsecret.yaml

Getting the K8s secret:

kubectl get secret akeyless-secret-to-create -o jsonpath='{.data.secretKey}' | base64 -d

Using dataFrom:

dataFrom can be used to get a secret as a JSON string and attempt to parse it.

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: akeyless-external-secret-example-json
spec:
  refreshInterval: 1h

  secretStoreRef:
    kind: SecretStore
    name: akeyless-secret-store # Must match SecretStore on the cluster

  target:
    name: akeyless-secret-to-create-json # Name for the secret to be created on the cluster
    creationPolicy: Owner

  # for JSON formatted secrets: each key in the JSON will be used as the secret key in the SECRET k8s target object
  dataFrom:
  - extract:
      key: /path/to/your/secret/keyname # Full path of the secret on Akeyless

Getting the K8s secret:

kubectl get secret akeyless-secret-to-create-json -o jsonpath='{.data}'

Tutorial

Check out our tutorial video on Sync Secrets to K8s with External Secrets Operator (ESO).