Last active
June 26, 2023 14:54
-
-
Save jimbo8098/caf59ab131ea251dc8e1c8875fed560d to your computer and use it in GitHub Desktop.
Create an assumable IAM role to access AWS Secrets Manager parameters using the Secret Store CSI Provider for AWS (ASCP)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- | |
apiVersion: secrets-store.csi.x-k8s.io/v1alpha1 | |
kind: SecretProviderClass | |
metadata: | |
name: example-secret-provider | |
namespace: secrets-csi-test | |
spec: | |
provider: aws | |
secretObjects: | |
# Each distinct secretObject creates a Secret which can be used within the namespace. Note that any pod able to access | |
# the secret can access it's contents - hence the potential danger for the syncSecrets option. Be wary of this. | |
- secretName: example-secret | |
type: Opaque | |
data: | |
# objectName refers to the objectAlias defined within the parameters defined further down. If your example isn't | |
# as complex as mine, objectAlias may simply be the objectName of the secret - assuming it's a unique identifier. | |
- objectName: username | |
key: username | |
- objectName: password | |
key: password | |
# The secret will be created with a key named secret which contains "MySecret", the entire secret defined in | |
# objects below. This is really just to demonstrate that you can set an alias an use it. | |
- objectName: MySecret | |
key: secret | |
parameters: | |
# In the object parameter, we take the JSON formatted AWS secret using it's ARN and, using the jmesPath notation, extract the | |
# username and password fields. The aliases are used in the secretObjects section to create a Secret object when the provider | |
# is called | |
objects: | | |
- objectName: "<arn>" | |
objectAlias: MySecret # optional | |
jmesPath: | |
- path: username | |
objectAlias: username | |
- path: password | |
objectAlias: password |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
apiVersion: apps/v1 | |
kind: Deployment | |
metadata: | |
name: nginx-deployment | |
namespace: secrets-csi-test | |
labels: | |
app: nginx | |
spec: | |
replicas: 2 | |
selector: | |
matchLabels: | |
app: nginx | |
template: | |
metadata: | |
labels: | |
app: nginx | |
spec: | |
serviceAccountName: deployment-service-account | |
volumes: | |
# Volume may contain multiple AWS secrets but is deployment specific. The secretProviderClass | |
# field defines which of the providers are used to create the secret. | |
- name: deployment-aws-secrets | |
csi: | |
driver: secrets-store.csi.k8s.io | |
readOnly: true | |
volumeAttributes: | |
secretProviderClass: 'example-secret-provider' | |
containers: | |
- name: nginx-deployment | |
image: nginx | |
ports: | |
- containerPort: 80 | |
volumeMounts: | |
# Mount the secret to the filesystem. You can read the contents of this secret | |
# just like any other secret. This does *not* require the use of syncSecrets but | |
# it is required to use that feature - even if you don't want to use the secret | |
# in this way. | |
- name: deployment-aws-secrets | |
mountPath: '/mnt/secrets-store' | |
readOnly: true | |
env: | |
# The secret created by secretProviderName is mounted as an environment variable | |
# This is an experimental feature at this time. | |
- name: USERNAME | |
valueFrom: | |
secretKeyRef: | |
# The secret named `example-secret` is created within the namespace of `secretProviderName` | |
# This needs to be within the same namespace as the pod. The secret is created during pod | |
# creation and removed during deletion. | |
name: example-secret | |
key: username | |
- name: PASSWORD | |
valueFrom: | |
secretKeyRef: | |
name: example-secret | |
key: password |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
data "aws_iam_policy_document" "read-secret" { | |
statement { | |
actions = [ | |
"secretsmanager:ListSecretVersionIds", | |
"secretsmanager:GetSecretValue", | |
"secretsmanager:GetResourcePolicy", | |
"secretsmanager:DescribeSecret" | |
] | |
resources = var.accessible_secret_arns | |
} | |
} | |
# Deduced from https://github.com/terraform-aws-modules/terraform-aws-iam/blob/5bdf6cbbb1612e1ad520c17781c0ebf533b42881/modules/iam-role-for-service-accounts-eks/main.tf#L38 | |
# The module used here is usable but adds quite a lot of functionality which is not necessary for our purposes. | |
data "aws_iam_policy_document" "assume-role" { | |
dynamic "statement" { | |
for_each = { | |
main = { | |
provider_arn = var.eks_oidc_provider_arn | |
namespace_service_accounts = var.namespace_service_accounts | |
} | |
} | |
content { | |
effect = "Allow" | |
actions = ["sts:AssumeRoleWithWebIdentity"] | |
principals { | |
type = "Federated" | |
identifiers = [statement.value.provider_arn] | |
} | |
condition { | |
test = "StringEquals" | |
variable = "${replace(statement.value.provider_arn, "/^(.*provider/)/", "")}:sub" | |
values = [for sa in statement.value.namespace_service_accounts : "system:serviceaccount:${sa}"] | |
} | |
# https://aws.amazon.com/premiumsupport/knowledge-center/eks-troubleshoot-oidc-and-irsa/?nc1=h_ls | |
condition { | |
test = "StringEquals" | |
variable = "${replace(statement.value.provider_arn, "/^(.*provider/)/", "")}:aud" | |
values = ["sts.amazonaws.com"] | |
} | |
} | |
} | |
} | |
resource "aws_iam_policy" "read-secrets" { | |
name = "ReadSecrets" | |
description = "Provide read-only access to required secrets" | |
policy = data.aws_iam_policy_document.read-secret.json | |
} | |
resource "aws_iam_role" "role" { | |
name = "service-account" | |
description = "The service account used by the service account to access secret parameters" | |
assume_role_policy = data.aws_iam_policy_document.assume-role.json | |
} | |
resource "aws_iam_role_policy_attachment" "read-secret-attachment" { | |
role = aws_iam_role.role.name | |
policy_arn = aws_iam_policy.read-secrets.arn | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# An annotation needs to be added to set the IAM role to assume which allows for situations where there may be | |
# multiple possible roles to assume. This is probably not very useful since it's not entirely dynamic. Setting | |
# the annotation using: | |
# | |
# kubectl annotate serviceaccount -n secrets-csi-test deployment-service-account <eks-pod-iam-role-arn> | |
# | |
# is probably better. | |
--- | |
apiVersion: v1 | |
kind: ServiceAccount | |
metadata: | |
name: deployment-service-account | |
namespace: secrets-csi-test | |
annotations: | |
eks.amazonaws.com/role-arn: <eks-pod-iam-role-arn> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
variable "eks_oidc_provider_arn" { | |
type = string | |
description = "The ARN for the OIDC provider for the EKS cluster" | |
} | |
variable "namespace_service_accounts" { | |
type = list(string) | |
default = ["secrets-csi-test:deployment-service-account"] | |
description = "An array of namespace:service_account_names to create. Each of these SAs have access to the provided accessible_secret_arns" | |
} | |
variable "accessible_secret_arns" { | |
type = list(string) | |
description = "A list of ARNs which the service account should be able to access, e.g. postgres login" | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment