{"id":827,"date":"2021-02-21T01:50:00","date_gmt":"2021-02-20T17:50:00","guid":{"rendered":"https:\/\/vinta.ws\/code\/?p=827"},"modified":"2026-03-17T00:17:18","modified_gmt":"2026-03-16T16:17:18","slug":"amazon-eks-setup-kubernetes-external-secrets-with-aws-secret-manager","status":"publish","type":"post","link":"https:\/\/vinta.ws\/code\/amazon-eks-setup-kubernetes-external-secrets-with-aws-secret-manager.html","title":{"rendered":"Amazon EKS: Setup kubernetes-external-secrets with AWS Secret Manager"},"content":{"rendered":"<p>kubernetes-external-secrets allows you to use external secret management systems, like AWS Secrets Manager, to securely add Secrets in Kubernetes, so Pods can access Secrets normally.<\/p>\n<p>ref:<br \/>\n<a href=\"https:\/\/github.com\/external-secrets\/kubernetes-external-secrets\">https:\/\/github.com\/external-secrets\/kubernetes-external-secrets<\/a><\/p>\n<h2>AWS Secret Manager<\/h2>\n<p>For instance, we create a secret named <code>YOUR_SECRET<\/code> on AWS Secret Manager in the same region as our EKS cluster, using <code>DefaultEncryptionKey<\/code> as the encryption key. The content of the secret entity looks like:<\/p>\n<pre class=\"line-numbers\"><code class=\"language-json\">{\n  \"KEY_1\": \"VALUE_1\",\n  \"KEY_2\": \"VALUE_2\",\n}<\/code><\/pre>\n<p>We can retrieve the secret value:<\/p>\n<pre class=\"line-numbers\"><code class=\"language-bash\">aws secretsmanager get-secret-value --profile=perp \n--region ap-northeast-1 \n--secret-id YOUR_SECRET<\/code><\/pre>\n<h2>kubernetes-external-secrets<\/h2>\n<p>For kubernetes-external-secrets to work properly, it must be granted access to AWS Secrets Manager. To achieve that, we need to create an IAM role for kubernetes-external-secrets' service account.<\/p>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.aws.amazon.com\/eks\/latest\/userguide\/iam-roles-for-service-accounts.html\">https:\/\/docs.aws.amazon.com\/eks\/latest\/userguide\/iam-roles-for-service-accounts.html<\/a><\/p>\n<h3>Configure Secrets Backends<\/h3>\n<p>Create an IAM OIDC provider for the cluster:<\/p>\n<pre class=\"line-numbers\"><code class=\"language-bash\">eksctl utils associate-iam-oidc-provider --profile=perp \n--region ap-northeast-1 \n--cluster perp-staging \n--approve\n\naws iam list-open-id-connect-providers --profile=perp<\/code><\/pre>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.aws.amazon.com\/eks\/latest\/userguide\/enable-iam-roles-for-service-accounts.html\">https:\/\/docs.aws.amazon.com\/eks\/latest\/userguide\/enable-iam-roles-for-service-accounts.html<\/a><\/p>\n<p>Create an IAM policy that allows the role to access all secrets we created on AWS Secret Manager:<\/p>\n<pre class=\"line-numbers\"><code class=\"language-bash\">AWS_ACCOUNT_ID=$(aws sts get-caller-identity --profile=perp --query \"Account\" --output text)\n\ncat &lt;&lt;EOF &gt; policy.json\n{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"secretsmanager:GetResourcePolicy\",\n        \"secretsmanager:GetSecretValue\",\n        \"secretsmanager:DescribeSecret\",\n        \"secretsmanager:ListSecretVersionIds\"\n      ],\n      \"Resource\": [\n        \"arn:aws:secretsmanager:ap-northeast-1:${AWS_ACCOUNT_ID}:secret:*\"\n      ]\n    }\n  ]\n}\nEOF\n\naws iam create-policy --profile=perp \n--policy-name perp-staging-secrets-policy --policy-document file:\/\/policy.json<\/code><\/pre>\n<p>Attach the above IAM policy to an IAM role, and define AssumeRole for the service account <code>external-secrets-kubernetes-external-secrets<\/code> which will be created later:<\/p>\n<pre class=\"line-numbers\"><code class=\"language-bash\">AWS_ACCOUNT_ID=$(aws sts get-caller-identity --profile=perp --query \"Account\" --output text)\nOIDC_PROVIDER=$(aws eks describe-cluster --profile=perp --name perp-staging --region ap-northeast-1 --query \"cluster.identity.oidc.issuer\" --output text | sed -e \"s\/^https:\/\/\/\/\") \n\ncat &lt;&lt;EOF &gt; trust.json\n{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Principal\": {\n        \"Federated\": \"arn:aws:iam::${AWS_ACCOUNT_ID}:oidc-provider\/${OIDC_PROVIDER}\"\n      },\n      \"Action\": \"sts:AssumeRoleWithWebIdentity\",\n      \"Condition\": {\n        \"StringEquals\": {\n          \"${OIDC_PROVIDER}:aud\": \"sts.amazonaws.com\",\n          \"${OIDC_PROVIDER}:sub\": \"system:serviceaccount:default:external-secrets-kubernetes-external-secrets\"\n        }\n      }\n    }\n  ]\n}\nEOF\n\naws iam create-role --profile=perp \n--role-name perp-staging-secrets-role \n--assume-role-policy-document file:\/\/trust.json\n\naws iam attach-role-policy --profile=perp \n--role-name perp-staging-secrets-role \n--policy-arn YOUR_POLICY_ARN<\/code><\/pre>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.aws.amazon.com\/eks\/latest\/userguide\/iam-roles-for-service-accounts.html\">https:\/\/docs.aws.amazon.com\/eks\/latest\/userguide\/iam-roles-for-service-accounts.html<\/a><br \/>\n<a href=\"https:\/\/gist.github.com\/lukaszbudnik\/f1f42bd5a57430e3c25034200ba44c2e\">https:\/\/gist.github.com\/lukaszbudnik\/f1f42bd5a57430e3c25034200ba44c2e<\/a><\/p>\n<h3>Deploy kubernetes-external-secrets Controller<\/h3>\n<pre class=\"line-numbers\"><code class=\"language-bash\">helm repo add external-secrets https:\/\/external-secrets.github.io\/kubernetes-external-secrets\/\n\nhelm install external-secrets \nexternal-secrets\/kubernetes-external-secrets \n--skip-crds \n--set env.AWS_REGION=ap-northeast-1 \n--set securityContext.fsGroup=65534 \n--set serviceAccount.annotations.\"eks.amazonaws.com\/role-arn\"='YOUR_ROLE_ARN'\n\nhelm list<\/code><\/pre>\n<p>It would automatically create a service account named <code>external-secrets-kubernetes-external-secrets<\/code> in Kubernetes.<\/p>\n<p>ref:<br \/>\n<a href=\"https:\/\/github.com\/external-secrets\/kubernetes-external-secrets\/tree\/master\/charts\/kubernetes-external-secrets\">https:\/\/github.com\/external-secrets\/kubernetes-external-secrets\/tree\/master\/charts\/kubernetes-external-secrets<\/a><\/p>\n<h3>Deploy ExternalSecret<\/h3>\n<p>ExternalSecret <code>app-secrets<\/code> will generate a Secret object with the same name, and the content would look like:<\/p>\n<pre class=\"line-numbers\"><code class=\"language-yaml\">apiVersion: kubernetes-client.io\/v1\nkind: ExternalSecret\nmetadata:\n  name: example-secret\nspec:\n  backendType: secretsManager\n  region: ap-northeast-1\n  dataFrom:\n    - YOUR_SECRET\n---\napiVersion: apps\/v1\nkind: Deployment\nmetadata:\n  name: example-app\nspec:\n  replicas: 3\n  selector:\n    matchLabels:\n      app: example-app\n  template:\n    metadata:\n      labels:\n        app: example-app\n    spec:\n      containers:\n      - name: example-app\n        image: busybox:latest\n        envFrom:\n        - secretRef:\n            name: example-secret<\/code><\/pre>\n<pre class=\"line-numbers\"><code class=\"language-bash\">kubectl get secret example-secret -o jsonpath=\"{.data.KEY_1}\" | base64 --decode<\/code><\/pre>\n<p>ref:<br \/>\n<a href=\"https:\/\/gist.github.com\/lukaszbudnik\/f1f42bd5a57430e3c25034200ba44c2e\">https:\/\/gist.github.com\/lukaszbudnik\/f1f42bd5a57430e3c25034200ba44c2e<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>kubernetes-external-secrets allows you to use external secret management systems, like AWS Secrets Manager, to securely add Secrets in Kubernetes, so Pods can access Secrets normally.<\/p>\n","protected":false},"author":1,"featured_media":830,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[38,116],"tags":[16,136,123],"class_list":["post-827","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-about-devops","category-about-web-development","tag-amazon-web-services","tag-aws-eks","tag-kubernetes"],"_links":{"self":[{"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/posts\/827","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/comments?post=827"}],"version-history":[{"count":0,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/posts\/827\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/media\/830"}],"wp:attachment":[{"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/media?parent=827"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/categories?post=827"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/tags?post=827"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}