External Secrets Operator is a tool we used to create and sync Kubernetes Secrets with Secret Managers like the AWS Secrets Manager and Hashicorp Vault. It lets you create Kubernetes secrets using custom resources like ExternalSecret and keeps it in sync if needed with different secret sources. Here we’ll see how to set this up in a Kubernetes cluster.
External Secrets
The external-secrets deployment and its CRDs can be deployed in our EKS cluster using Helm.
- Add helm chart repo
helm repo add external-secrets https://charts.external-secrets.iohelm repo update
- Install the helm chart
helm -n external-secrets install external-secrets external-secrets/external-secrets --create-namespace --set installCRDs=true
- Make sure the pods are running once the helm deployment is done
kubectl -n external-secrets get pods
AWS Secrets Manager
We will be using AWS IRSA for setting up AWS Secrets Manager access for the External Secrets Operator deployed in an EKS cluster.
IRSA
- Get the OIDC url from the EKS cluster
export OIDC_PROVIDER=$(aws eks describe-cluster --name EKS_CLUSTER_NAME --query "cluster.identity.oidc.issuer" --output text | cut -d'/' -f3-)
- Create the IAM Trust Policy JSON. Replace with the correct values:
ACCOUNT_ID
- AWS Account ID
cat <<EOF > trust-policy.json{ "Version": "2012-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::ACCOUNT_ID:oidc-provider/${OIDC_PROVIDER}" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "${OIDC_PROVIDER}:sub": "system:serviceaccount:external-secrets:aws-secrets-sa" } } } ]}EOF
- Create the IAM Role and note the Arn
export IAM_ROLE_ARN=$(aws iam create-role --role-name external-secrets-role --assume-role-policy-document file://trust-policy.json --query "Role.Arn" --output text)
- Create IAM Policy JSON. This policy allows the external-secrets operator to get the secret value from AWS Secrets Manager
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "secretsmanager:GetResourcePolicy", "secretsmanager:GetSecretValue", "secretsmanager:DescribeSecret", "secretsmanager:ListSecretVersionIds" ], "Resource": "*" } ]}
- Create IAM Policy and get the Arn
export IAM_POLICY_ARN=$(aws iam create-policy --policy-name external-secrets-policy --policy-document file://iam-policy.json --query "Policy.Arn" --output text)
- Attach the IAM Policy to the IAM Role we created
aws iam attach-role-policy --policy-arn external-secrets-policy --role-name external-secrets-role
Kubernetes Setup
Now we’ll need to create 2 custom k8s resources - ClusterSecretStore and ExternalSecret. ExternalSecret
is the resource that creates the k8s secret by accessing the AWS Secrets Manager / Vault using the ClusterSecretStore
. ClusterSecretStore
is a cluster-wide resource and the ExternalSecret
is a namespaced resource.
- Create the
ClusterSecretStore
resource. The yaml below also consists of the k8s service account that has access to the IAM Role we created earlier. ReplaceIAM_ROLE_ARN
with the value we obtained earlier.
apiVersion: v1kind: ServiceAccountmetadata: annotations: eks.amazonaws.com/role-arn: IAM_ROLE_ARN name: aws-secrets-sa namespace: external-secrets---apiVersion: external-secrets.io/v1kind: ClusterSecretStoremetadata: name: aws-secretsspec: provider: aws: service: SecretsManager region: us-east-1 auth: jwt: serviceAccountRef: name: aws-secrets-sa namespace: external-secrets
- Create the
ExternalSecret
resource. This creates a k8s secret calledExternalSecret
in the namespacedefault
, with values from the AWS Secretaws-secret
. This is set to check and refresh the values of the k8s secret every 3 minutes. So any changes made in the AWS Secrets Manager will be reflected in the cluster secret too.
apiVersion: external-secrets.io/v1kind: ExternalSecretmetadata: name: aws-secret namespace: defaultspec: refreshInterval: 3m0s secretStoreRef: kind: ClusterSecretStore name: aws-secrets dataFrom: - extract: key: aws-secret target: creationPolicy: Owner name: aws-secret
- The k8s secret with the name should be available
kubectl -n default describe secrets aws-secret
Vault
To setup access to the Vault server from the External Secrets Operator, we will be using the Kubernetes Auth method - Ref
Vault Kubernetes Auth
We will be creating a Vault Policy
, Vault Kubernetes Role
with access to the Secrets stored in the Vault server assigned to the Kubernetes Service Account used by the External Secrets Operator.
- Exec into the
vault-0
pod
kubectl -n vault exec -it vault-0 -- sh
- Login to the vault server
vault login
- Create a Vault policy with access to the Vault secrets from which we want to create k8s secrets.
vault policy write external-secrets-policy - <<EOFpath "vault-secrets/*" { capabilities = ["read", "list"]}EOF
- Create a Vault Kubernetes Role that binds the above policy to the Kubernetes Service Account used by the External Secrets Operator.
vault write auth/kubernetes/role/external-secrets-role bound_service_account_names=external-secrets bound_service_account_namespaces=external-secrets policies=external-secrets-policy ttl=24h
Kubernetes Setup
Now we’ll need to create the ClusterSecretStore
and ExternalSecret
resources for Vault.
- Create the
ClusterSecretStore
resource.
apiVersion: external-secrets.io/v1kind: ClusterSecretStoremetadata: name: hashicorp-vaultspec: provider: vault: auth: kubernetes: mountPath: kubernetes role: external-secrets-role path: vault-secrets server: http://vault.vault:8200 version: v2
- Create the
ExternalSecret
resource.
apiVersion: external-secrets.io/v1kind: ExternalSecretmetadata: name: vault-secret namespace: defaultspec: dataFrom: - extract: conversionStrategy: Default decodingStrategy: None key: vault-secrets/data/vault-secret-name metadataPolicy: None refreshInterval: 2m0s secretStoreRef: kind: ClusterSecretStore name: hashicorp-vault target: creationPolicy: Owner deletionPolicy: Retain name: vault-secret
- The k8s secret with the name should be available
kubectl -n default describe secrets vault-secret
And there you have it! We have successfully set up the External Secrets Operator with AWS Secrets Manager and HashiCorp Vault.