AWS Secrets Manger in Kubernetes

I love to grease knots and bolts of SDLC, nurture the underlying infra, rightly automate, monitor systems and enable the dev teams to achieve more with less.
Prerequisite
Create EKS Cluster
This will create an EKS cluster in us-east-1 region with 2 nodes in the node-group.
export CLUSTER_NAME=demo-cluster
export AWS_REGION=us-east-1
eksctl create cluster --name ${CLUSTER_NAME} --version 1.26 --node-type t3.medium --nodes 2 --managed --region ${AWS_REGION}
.....
.....
2023-05-28 18:47:47 [✔] EKS cluster "demo-cluster" in "us-east-1" region is ready.
verify
When running the following command kubectl get nodes you should see the nodes in a ready state.
➜ kubectl get nodes
NAME STATUS ROLES AGE VERSION
ip-192-168-17-231.ec2.internal Ready <none> 114m v1.26.4-eks-0a21954
ip-192-168-61-195.ec2.internal Ready <none> 114m v1.26.4-eks-0a21954
Deploy External Secrets Operator
Use below helm commands to:
add/update the repo
install the operator
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 \
--set installCRDs=true \
--wait
.....
external-secrets has been deployed successfully!
....
verify
When you run k get all -n external-secrets you should be able to see all the pods pod/external-secrets-* , pod/external-secrets-cert-controller-*, pod/external-secrets-webhook-* running successfully.
➜ k get all -n external-secrets
NAME READY STATUS RESTARTS AGE
pod/external-secrets-5997dc48b4-drncs 1/1 Running 0 2m33s
pod/external-secrets-cert-controller-587977f796-mdk9p 1/1 Running 0 2m33s
pod/external-secrets-webhook-674f79cb47-jz7ds 1/1 Running 0 2m33s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/external-secrets-webhook ClusterIP 10.100.84.243 <none> 443/TCP 2m33s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/external-secrets 1/1 1 1 2m34s
deployment.apps/external-secrets-cert-controller 1/1 1 1 2m34s
deployment.apps/external-secrets-webhook 1/1 1 1 2m34s
NAME DESIRED CURRENT READY AGE
replicaset.apps/external-secrets-5997dc48b4 1 1 1 2m34s
replicaset.apps/external-secrets-cert-controller-587977f796 1 1 1 2m34s
replicaset.apps/external-secrets-webhook-674f79cb47
Configuring IAM roles for service accounts (IRSA) and Secrets Manager
Add OIDC Provider
➜ eksctl utils associate-iam-oidc-provider --cluster=${CLUSTER_NAME} --approve
2023-05-28 13:25:07 [✔] created IAM Open ID Connect provider for cluster "demo-cluster" in "us-east-1"
Create Secret in Secrets Manager
SECRET_ARN=$(aws secretsmanager create-secret --name user-creds \
--secret-string "{\"user\":\"admin\",\"password\":\"topsecret\"}" \
--region ${AWS_REGION} | jq -r .ARN)
Create IAM Policy
IAM Policy to Read/Describe the user-creds secret in the secrets manager
➜ IAM_POLICY_ARN=$(aws iam create-policy --policy-name eso-sm-reader-policy --policy-document '{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"secretsmanager:DescribeSecret",
"secretsmanager:GetSecretValue"
],
"Resource": ["'${SECRET_ARN}'"]
}
]
}' | jq -r .Policy.Arn)
Create a Service Account and Association
➜ eksctl create iamserviceaccount \
--name eso-secret-irsa \
--namespace default \
--cluster ${CLUSTER_NAME} \
--role-name "eso-sm-reader-role" \
--attach-policy-arn $IAM_POLICY_ARN \
--approve
verify
k describe sa eso-secret-irsa
Name: eso-secret-irsa
Namespace: default
Labels: app.kubernetes.io/managed-by=eksctl
Annotations: eks.amazonaws.com/role-arn: arn:aws:iam::808053714438:role/eso-sm-reader-role
Image pull secrets: <none>
Mountable secrets: <none>
Tokens: <none>
Events: <none>
Deploy External Secret Store/Secret
Create SecretStore
cat <<EOF | kubectl apply -f -
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: secret-store
spec:
provider:
aws:
service: SecretsManager
region: us-east-1
auth:
jwt:
serviceAccountRef:
name: eso-secret-irsa
EOF
Verify
kubectl get SecretStore
NAME AGE STATUS CAPABILITIES READY
secret-store 58s Valid ReadWrite True
Create ExternalSecret
cat <<EOF | kubectl apply -f -
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: user-creds
spec:
refreshInterval: 5m
secretStoreRef:
name: secret-store
kind: SecretStore
target:
name: user-creds
data:
- secretKey: user
remoteRef:
key: user-creds
property: user
- secretKey: password
remoteRef:
key: user-creds
property: password
EOF
Verify
➜ kubectl get ExternalSecret
NAME STORE REFRESH INTERVAL STATUS READY
user-creds secret-store 5m SecretSynced True
➜ kubectl get secret
NAME TYPE DATA AGE
user-creds Opaque 2 30s
Deploy Application
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: creds-app
spec:
containers:
- name: app
image: k8s.gcr.io/busybox
command: [ "/bin/sh", "-c", "env" ]
envFrom:
- secretRef:
name: user-creds
EOF
Verify
➜ kubectl logs pod/creds-app
....
user=admin
password=topsecret
....




