In a cloud-native environment, managing sensitive data like database credentials, API keys and certificates in a secure, auditable and scalable way is crucial. The External Secrets Operator (ESO) bridges the gap between secret management systems (e.g., AWS Secrets Manager, Azure Key Vault, HashiCorp Vault, Google Secret Manager) and your Kubernetes workloads. In this tutorial, we’ll show you how to fetch secrets from AWS Secrets Manager and sync them into Kubernetes as native Secret
objects, using ESO.
Prerequisites
Before we begin, make sure you have:
- A Kubernetes cluster up and running (e.g., EKS, GKE, AKS or self-managed).
- Helm v3 installed on your local machine (or wherever you manage your cluster).
kubectl
configured to communicate with your cluster.- A secure source for your secrets. In this guide, we’ll use AWS Secrets Manager, but ESO supports many other providers.
Step 1: Install the External-Secrets Operator
Add the ESO Helm repository and install the chart. This will also install the CustomResourceDefinitions (CRDs) that define the ESO API objects.
# Add the external-secrets Helm repo
helm repo add external-secrets https://charts.external-secrets.io
# Update your local repo cache
helm repo update
# Install ESO into the 'external-secrets' namespace
helm install external-secrets \
external-secrets/external-secrets \
--namespace external-secrets \
--create-namespace \
--set installCRDs=true
Step 2: Store AWS Credentials in a Kubernetes Secret
ESO needs AWS credentials to authenticate with Secrets Manager. We’ll create a plain Kubernetes Secret
of type Opaque
to hold an IAM user’s access key and secret key. For an AWS EKS cluster, consider using IRSA (IAM Roles for Service Accounts) instead of long-lived keys.
apiVersion: v1
kind: Secret
metadata:
name: aws-sm-iam
namespace: external-secrets
type: Opaque
stringData:
access-key: "MY_AWS_SM_ACCESS_KEY"
secret-access-key: "MY_AWS_SM_SECRET_ACCESS_KEY"
Apply it:
kubectl apply -f aws-credentials-secret.yaml
Step 3: Define a SecretStore
A SecretStore
tells ESO how to connect to your external provider. Here we reference the Secret resourcee we just created for AWS credentials, specify the AWS region, and select the Secrets Manager service.
apiVersion: external-secrets.io/v1
kind: SecretStore
metadata:
name: my-secret-store
namespace: external-secrets
spec:
provider:
aws:
service: SecretsManager
region: eu-central-1
auth:
secretRef:
accessKeyIDSecretRef:
name: aws-sm-iam
key: access-key
secretAccessKeySecretRef:
name: aws-sm-iam
key: secret-access-key
Apply the SecretStore:
kubectl apply -f secretstore.yaml
Step 4: Create an ExternalSecret
The ExternalSecret
resource maps keys and properties from AWS Secrets Manager into a Kubernetes Secret
. You define:
refreshInterval
– how often ESO will reconcile and refresh the secret.secretStoreRef
– whichSecretStore
to use.target
– the name of the resulting KubernetesSecret
.data
– a list of remote secret keys and the corresponding keys in the KubernetesSecret
.
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: my-external-secrets
namespace: external-secrets
spec:
refreshInterval: 1h
secretStoreRef:
name: my-secret-store
kind: SecretStore
target:
name: my-eso-secret
creationPolicy: Owner
data:
- secretKey: DATABASE_USER
remoteRef:
key: my-aws-secrets-manager-secret
property: username
- secretKey: DATABASE_PASSWORD
remoteRef:
key: my-aws-secrets-manager-secret
property: password
Apply it:
kubectl apply -f externalsecret.yaml
ESO will now fetch the username
and password
fields from the AWS Secrets Manager secret named my-aws-secrets-manager-secret
and write them into a native Kubernetes secret called my-eso-secret
.
Step 5: Consume the Synced Secret in a Deployment
Below is a simple Deployment example that mounts the synced secret as environment variables:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: app-container
image: busybox
command: ["sh", "-c", "env && sleep 3600"]
env:
- name: DATABASE_USER
valueFrom:
secretKeyRef:
name: my-eso-secret
key: DATABASE_USER
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: my-eso-secret
key: DATABASE_PASSWORD
Apply the Deployment:
kubectl apply -f deployment.yaml
Conclusion
You’ve successfully set up the External-Secrets Operator to:
- Authenticate against AWS Secrets Manager.
- Fetch and sync secrets into a Kubernetes-native
Secret
. - Consume those secrets in your workloads securely.
This pattern decouples secret storage from your cluster, centralizes audit logs in AWS, and leverages IAM roles and policies for access control. ESO supports many other secret backends (Vault, Google Secret Manager, Azure Key Vault), so you can adopt a consistent workflow across teams and clouds.
Happy secret managing!
Member discussion