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 – which SecretStore to use.
  • target – the name of the resulting Kubernetes Secret.
  • data – a list of remote secret keys and the corresponding keys in the Kubernetes Secret.
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:

  1. Authenticate against AWS Secrets Manager.
  2. Fetch and sync secrets into a Kubernetes-native Secret.
  3. 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!

Share this post