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.
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 provides 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.
You can use two types of resources to fetch secrets from Akeyless:
-
SecretStore: Defines how to access secrets from Akeyless within a specific namespace.
-
ClusterSecretStore: Defines how to access secrets from Akeyless across the entire Kubernetes cluster.
In addition to retrieving secrets from Akeyless to your K8s cluster, you can use the PushSecret
resource to push a local K8s secret from your cluster to Akeyless.
Prerequisites
- Helm installed
K8s v1.16
or higher
Installing with Helm
Add External Secrets official repository to your helm and install:
helm repo add external-secrets https://charts.external-secrets.io
helm install external-secrets external-secrets/external-secrets
Authentication
Akeyless official provider support the following Auth Methods:
Note
This guide demonstrates authentication using API Key and K8s Auth Methods. However, for security purposes, it’s highly recommended to avoid using API Keys in production.
To set an auth method for the external secret operator, first create a K8s Secret with the relevant settings, for example:
apiVersion: v1
kind: Secret
metadata:
name: akeyless-secret-creds
type: Opaque
stringData:
accessId: <Access ID>
accessType: api_key
accessTypeParam: <Access Key>
apiVersion: v1
kind: Secret
metadata:
name: akeyless-secret-creds
type: Opaque
stringData:
accessId: <Access ID>
accessType: k8s
accessTypeParam: <k8s-conf-name>
Where:
-
name
: A name for the k8s secret to store the Authentication details. -
accessId
: The Auth MethodAccess ID
. -
accessType
: The Auth method type. -
accessTypeParam
:Access Key
for API Key ork8s-conf-name
for K8s. For more options, check the official provider docs.
Apply the configuration:
kubectl apply -f akeylesscreds.yaml
SecretStore
The SecretStore resource is namespaced and defines how to authenticate to Akeyles, in the following example, a reference to the akeyless-secret-creds
that was created earlier is used.
Set the SecretStore resource:
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: akeyless-secret-store
spec:
provider:
akeyless:
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
Where:
-
akeylessGWApiURL
: The URL of your Gateway API v2 endpoint:https://Your-Gateway-URL:8080/v2
. -
authSecretRef
: References a K8s Secretakeyless-secret-creds
containing authentication credentials. -
secretRef
: Refers to a K8s Secret namedakeyless-secret-creds
, which contains values foraccessID
,accessType
, andaccessTypeParam
.
Apply the configuration:
kubectl apply -f secretstore.yaml
Explicit Secret Store
Authentication with Akeyless can be done using credentials stored in the akeyless-secret-creds
K8s secret through the SecretStore. Alternatively, you can authenticate directly using your k8s Auth settings.
Using an explicit secret store provides key benefits for access control and security. By segregating secrets based on service accounts, you can ensure that each service account only has access to the secrets it needs.
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: akeyless-secret-store
spec:
provider:
akeyless:
akeylessGWApiURL: "https://api.akeyless.io"
authSecretRef:
kubernetesAuth:
accessID: <AccessID>
k8sConfName: <K8s Conf Name>
serviceAccountRef:
name: <ServiceAccount Name>
Where:
-
accessId
: The K8s Auth MethodAccess ID
. -
k8sConfName
: The name of the K8s Conf on the Gateway. -
serviceAccountRef
: The name of the K8s service account used to fetch secrets from Akeyless. Only secrets defined in a role associated with that service account under claimservice_account_name
can be accessed.
ExternalSecret
To retrieve a secret from Akeyless and store it as a K8s secret in your cluster, create an ExternalSecret resource that specifies which secret to fetch:
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: akeyless-external-secret-example
spec:
refreshInterval: 1h
secretStoreRef:
kind: SecretStore
name: akeyless-secret-store
target:
name: akeyless-secret-to-create
creationPolicy: Owner
data:
- secretKey: secretKey
remoteRef:
key: /path/to/your/secret
Where:
-
refreshInterval
: The amount of time before the values are read again -
secretStoreRef
: Reference to theSecretStore
that was created earlier, in case ofClusterSecretStore
set theKind
toClusterSecretStore
-
target
: Name of the K8s secret to create. -
secretKey
: The key of the secret that will be created locally in the k8s cluster. -
key
: Full path to the secret in Akeyless
Apply the configuration:
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, where each key will be used as the secret key in the K8s Secret:
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: akeyless-external-secret-example-json
spec:
refreshInterval: 1h
secretStoreRef:
kind: SecretStore
name: akeyless-secret-store
target:
name: akeyless-secret-to-create-json
creationPolicy: Owner
dataFrom:
- extract:
key: /path/to/your/secret/keyname
Where:
-
refreshInterval
: The amount of time before the values are read again -
secretStoreRef
: Reference to theSecretStore
. -
target
: Name of the K8s secret to create. -
key
: Full path to the secret in Akeyless
Getting the K8s secret:
kubectl get secret akeyless-secret-to-create-json -o jsonpath='{.data}'
Working with Certificates
Another example is when working with Akeyless Certificate, the certificate item contains two separate PEM
blocks, the actual Certificate
and the Private Key
, to split them into different keys you can configure the resource accordingly:
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: akeyless-external-secret-example
spec:
refreshInterval: 1h
secretStoreRef:
kind: SecretStore
name: akeyless-secret-store
target:
name: akeyless-secret-to-create
creationPolicy: Owner
data:
- secretKey: tls.crt
remoteRef:
key: /path/to/your/secret
property: certificate_pem
- secretKey: tls.key
remoteRef:
key: /path/to/your/secret
property: private_key_pem
Where:
-
refreshInterval
: The amount of time before the values are read again -
secretStoreRef
: Reference to theSecretStore
. -
target
: Name of the K8s secret to create. -
secretKey
: The Secret keys that will be created. -
key
: Full path to the secret in Akeyless -
Property
: The existing keys of the secret as stored in Akeyless.
Apply the configuration:
kubectl apply -f externalsecret.yaml
Getting the K8s secret:
kubectl get secret akeyless-secret-to-create -o jsonpath='{.data.tls\.crt}' | base64 -d
kubectl get secret akeyless-secret-to-create -o jsonpath='{.data.tls\.key}' | base64 -d
ClusterSecretStore
The ClusterSecretStore is cluster-wide and can be accessed by ExternalSecrets
from any namespace, offering centralized secret management:
Note
The namespace value is required in the
secretRef
section.
Set the ClusterSecretStore resource:
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
name: akeyless-cluster-secret-store
spec:
provider:
akeyless:
akeylessGWApiURL: "https://api.akeyless.io"
authSecretRef:
secretRef:
accessID:
name: akeyless-secret-creds
key: accessId
namespace: <namespace>
accessType:
name: akeyless-secret-creds
key: accessType
namespace: <namespace>
accessTypeParam:
name: akeyless-secret-creds
key: accessTypeParam
namespace: <namespace>
Where:
-
akeylessGWApiURL
: The URL of your Gateway API v2 endpoint:https://Your-Gateway-URL:8080/v2
. -
authSecretRef
: Reference to the K8s Secret that holds the authentication details, in our exampleakeyless-secret-creds
.
Run the following command to create the ClusterSecretStore resource:
kubectl apply -f clustersecretstore.yaml
Push Secret
The PushSecret resource is namespaced and is used to push secrets from your K8s Cluster to Akeyless.
Let's create a local K8s secret in the cluster, which will then be pushed to Akeyless:
kubectl create secret generic --from-literal=cache-pass=mypassword k8s-created-secret
Upon successful secret creation, a K8s secret named k8s-created-secret
will be created in your cluster.
Next, we will create the PushSecret
resource, which will be used to push the k8s-created-secret
K8s Secret, to Akeyless:
apiVersion: external-secrets.io/v1alpha1
kind: PushSecret
metadata:
name: push-secret
spec:
refreshInterval: 5s
updatePolicy: Replace
deletionPolicy: Delete
secretStoreRefs:
- name: akeyless-secret-store
kind: SecretStore
selector:
secret:
name: k8s-created-secret
data:
- match:
remoteRef:
remoteKey: eso-created/my-secret
Where:
-
refreshInterval
: The amount of time before the values are read again -
secretStoreRef
: Reference to theSecretStore
-
updatePolicy
: Policy to overwrite existing secrets in the provider on sync -
deletePolicy
: The provider secret will be deleted if thePushSecret
is deleted -
remoteKey
The location within the provider where the secret will be stored
Apply the configuration:
kubectl apply -f pushsecret.yaml
Upon successful execution, a secret named k8s-created-secret
will be created in Akeyless, with the value of cache-pass=mypassword
Tutorial
Check out our tutorial video on Sync Secrets to K8s with External Secrets Operator (ESO).
Updated 19 days ago