External Secrets Operator with AWS Secrets Manager

External Secrets Operator (ESO) is a Kubernetes operator that synchronizes secrets from external APIs (such as AWS Secrets Manager, HashiCorp Vault, and GCP Secret Manager) into native Kubernetes Secret objects.
This guide demonstrates how to configure ESO on Amazon EKS using EKS Pod Identity and ClusterSecretStores.
Architecture
graph LR
AWS["AWS Secrets Manager<br/>(e.g. eks/mysecret)"] --> ESO["External Secrets Operator Pod"]
ESO --> CSS["ClusterSecretStore (eks-secretstore)"]
CSS --> ES["ExternalSecret CRD"]
ES --> K8sSecret["Native Kubernetes Secret<br/>(mysecretink8s)"]
K8sSecret --> Pod["Application Pod"]
Step 1. IAM Policy & EKS Pod Identity
eso-iam.tf
# 1. IAM Policy scoped to path 'eks/*'
resource "aws_iam_policy" "eso_secrets_policy" {
name = "ESOSecretsManagerPolicy-${module.eks.cluster_name}"
description = "Allows External Secrets Operator to read secrets under path eks/*"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"secretsmanager:GetResourcePolicy",
"secretsmanager:GetSecretValue",
"secretsmanager:DescribeSecret",
"secretsmanager:ListSecretVersionIds",
"secretsmanager:ListSecrets",
"secretsmanager:BatchGetSecretValue"
]
Resource = ["arn:aws:secretsmanager:eu-west-1:*:secret:eks/*"]
}
]
})
}
# 2. IAM Role with Pod Identity Trust
data "aws_iam_policy_document" "pod_id_trust" {
statement {
effect = "Allow"
principals {
type = "Service"
identifiers = ["pods.eks.amazonaws.com"]
}
actions = ["sts:AssumeRole", "sts:TagSession"]
}
}
resource "aws_iam_role" "eso_controller" {
name = "external-secrets-role-${module.eks.cluster_name}"
assume_role_policy = data.aws_iam_policy_document.pod_id_trust.json
}
resource "aws_iam_role_policy_attachment" "eso_attach" {
role = aws_iam_role.eso_controller.name
policy_arn = aws_iam_policy.eso_secrets_policy.arn
}
# 3. Pod Identity Association
resource "aws_eks_pod_identity_association" "eso" {
cluster_name = module.eks.cluster_name
namespace = "external-secrets"
service_account = "external-secrets"
role_arn = aws_iam_role.eso_controller.arn
}
Step 2. Install External Secrets Operator via Helm
helm repo add external-secrets https://charts.external-secrets.io
helm repo update
helm install external-secrets external-secrets/external-secrets \
--namespace external-secrets \
--create-namespace \
--version 0.12.1
Step 3. Create ClusterSecretStore
cluster-secret-store.yaml
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
name: eks-secretstore
spec:
provider:
aws:
service: SecretsManager
region: eu-west-1
conditions:
- namespaces:
- default
- cert-manager
Authentication via Pod Identity
When no explicit authentication credentials or roles are provided in spec.provider.aws, ESO uses the EKS Pod Identity credentials injected into the operator pod automatically.
Step 4. Create ExternalSecret to Inject Kubernetes Secrets
external-secret.yaml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: mysecretfromsecretsmanager
namespace: default
spec:
refreshInterval: 1h
secretStoreRef:
name: eks-secretstore
kind: ClusterSecretStore
target:
name: mysecretink8s
creationPolicy: Owner
data:
- secretKey: username
remoteRef:
key: eks/mysecret
property: user
- secretKey: password
remoteRef:
key: eks/mysecret
property: password