• Home
  • About
  • Résumé
  • RunLog
  • Posts
    • All Posts
    • All Tags

Parameter Store and EFS access in EKS

15 Apr 2020

Reading time ~3 minutes

We use Parameter Store and EFS at our company heavily. Here are some simple steps to setup our EKS cluster with access to both.

Parameter Store

You can use ConfigMap to generate a list of parameter store ARNs into a file; then use aws-cli to parse that and stored into a new file. OR what I ended up doing was use secrets-init.

Setup a service account with parameter store access in Terraform:

The module.default-eks-c01.oidc-provider-url was created from the previous doc: EKS Group Access using AWS IAM. The aws_iam_policy.param_store_policy_ro.arn was created from the previous doc: AWS Parameter Store.

data "aws_iam_policy_document" "eks-default-service-account-assume-role-policy" {
  statement {
    actions = ["sts:AssumeRoleWithWebIdentity"]
    effect  = "Allow"

    condition {
      test     = "StringEquals"
      variable = "${replace(module.default-eks-c01.oidc-provider-url, "https://", "")}:sub"
      values   = ["system:serviceaccount:default:default-service-account"]
    }

    principals {
      identifiers = [replace(module.default-eks-c01.oidc-provider-arn, "https://", "")]
      type        = "Federated"
    }
  }
}

resource "aws_iam_role" "eks-access-role-default-service-account" {
  name               = "${var.env}-eks-default-service-account-oidc-iam-role"
  assume_role_policy = data.aws_iam_policy_document.eks-default-service-account-assume-role-policy.json
  description        = "Managed by Terraform"
}

resource "aws_iam_role_policy_attachment" "policy-attachment-eks-default-service-account" {
  role       = aws_iam_role.eks-access-role-default-service-account.name
  policy_arn = aws_iam_policy.param_store_policy_ro.arn
}

ServiceAccount

Create the default-service-account ServiceAccount account to be attached to the application’s Deployment yaml file.

---
apiVersion: v1
kind: ServiceAccount
metadata:
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::xxxyyyzzz:role/dev-eks-default-service-account-oidc-iam-role
  name: default-service-account

Deployment

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: dev-frontend-app-c01
spec:
  replicas: 2
  selector:
    matchLabels:
      app: dev-frontend-app-c01
  template:
    metadata:
      labels:
        app: dev-frontend-app-c01
      name: dev-frontend-app-c01
    spec:
      serviceAccountName: default-service-account
      initContainers:
        - name: secrets-init
          image: doitintl/secrets-init:v0.2.1
          command:
            - sh
          args:
            - -c
            - cp /usr/local/bin/secrets-init /secrets-init/bin/;
              /secrets-init/bin/secrets-init env |
              grep -E `env | awk -F'=' '$2 ~ /arn:aws:ssm:.+:parameter/ {print $1}' | paste -sd '|' -` >
              /parameter-store/secrets
          env:
            - name: AWS_REGION
              value: us-east-1
            - name: LICENSE_KEY
              value: arn:aws:ssm:us-east-1:xxxyyyzzz:parameter/dev/newrelic/LICENSE_KEY
          volumeMounts:
            - mountPath: /secrets-init/bin
              name: secrets-init-volume
            - mountPath: /parameter-store
              name: parameter-store-volume
      containers:
        - name: frontend
          image: nginx
          env:
            - name: AWS_REGION
              value: us-east-1
            - name: LICENSE_KEY
              value: arn:aws:ssm:us-east-1:xxxyyyzzz:parameter/dev/newrelic/LICENSE_KEY
          ports:
            - containerPort: 80
          volumeMounts:
            - mountPath: /secrets-init/bin
              name: secrets-init-volume
            - mountPath: /parameter-store
              name: parameter-store-volume
      volumes:
        - name: secrets-init-volume
          emptyDir: {}
        - name: parameter-store-volume
          emptyDir: {}

In the initContainers: block, we load the secrets-init container and store the values in a file to be used in the main containers: block.

The parameter store values will be stored in /parameter-store/secrets. We can source the file or eval them into environment variables before we start our application.

root@dev-frontend-app-c01-6fbf55dfdf-fbshf:/# cat /parameter-store/secrets
LICENSE_KEY=1234567890

Instead of running the the secrets-init env command in the init container, we can remove the following args:

/secrets-init/bin/secrets-init env |
grep -E `env | awk -F'=' '$2 ~ /arn:aws:ssm:.+:parameter/ {print $1}' | paste -sd '|' -` >
/parameter-store/secrets

Since our main containers: block has the parameter environments, we can just run the secrets-init in the main container.

root@dev-frontend-app-c01-6fbf55dfdf-fbshf:/# echo $LICENSE_KEY
arn:aws:ssm:us-east-1:xxxyyyzzz:parameter/dev/newrelic/LICENSE_KEY

root@dev-frontend-app-c01-6fbf55dfdf-fbshf:/# apt-get update && apt-get install awscli -y
...

root@dev-frontend-app-c01-6fbf55dfdf-fbshf:/# /secrets-init/bin/secrets-init env | grep LICENSE_KEY
LICENSE_KEY=1234567890

root@dev-frontend-app-c01-6fbf55dfdf-fbshf:/# /secrets-init/bin/secrets-init sh -c 'echo $LICENSE_KEY'
1234567890

EFS

Once you have the efs-provisioner service running by following the instructions from AWS Knowledge Center, we can start creating PVC in our application deployments.

Create Persistent Volume Claim

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  annotations:
    volume.beta.kubernetes.io/storage-class: efs
  name: dev-eks-efs-data-frontend-c01
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 5Mi
$ kubectl get pvc dev-eks-efs-data-frontend-c01
NAME                            STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
dev-eks-efs-data-frontend-c01   Bound    pvc-2c97c0ca-810a-11ea-bd9e-1238d378ba75   5Mi        RWX            aws-efs        6m14s

Create Deployment with EFS volume

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: dev-frontend-app-c01
spec:
  replicas: 2
  selector:
    matchLabels:
      app: dev-frontend-app-c01
  template:
    metadata:
      labels:
        app: dev-frontend-app-c01
      name: dev-frontend-app-c01
    spec:
      containers:
        - name: frontend
          image: nginx
          ports:
            - containerPort: 80
          volumeMounts:
            - mountPath: /efs
              name: efs-pvc
      volumes:
        - name: efs-pvc
          persistentVolumeClaim:
            claimName: dev-eks-efs-data-initjs-c01
$ kubectl exec -it dev-frontend-app-c01-7f85fc6c69-4hgfl -- 'df'
Filesystem                                                                           1K-blocks     Used        Available Use% Mounted on
overlay                                                                               20959212  8425264         12533948  41% /
...
fs-xxxxxxxx.efs.us-east-1.amazonaws.com:/dev-eks-efs-data-initjs-c01-pvc-xxxx 9007199254739968 13434880 9007199241305088   1% /efs
...


technologydocdevopsawsekskubernetes Share Tweet +1