Skip to content

AWS ACK (AWS Controller for Kubernetes)

EKS Auto mode ACK (Aws controller for Kubernetes)

Modern kubernetes application often require additional infrastructure like Database, storage bucket etc. Often these resources are provisioned by Platform team and developments teams to coordinate infrastructure creation before deploying application. Tools like Crossplane and Kubernetes Resource Orchestrator aim to make it possible to manage it via Kubernetes object. KRO does this by using providers, and for AWS it is `ACK (AWS Controller for Kubernetes).

AWS Controllers for Kubernetes (ACK) lets you define and use AWS service resources directly from Kubernetes. ACK can be used directly on EKS/Kubernetes instances or along with other tools like KRO.

Here is how you can use ACK on an EKS cluster to provision AWS resources. Default documentation at present advise use of IAM RSA for controllers, I am using newer Pod Identity instead.

ACK (Aws controller for Kubernetes)

Step 1. Provision EKS-Auto mode and EKS with Pod identity enabled

To follow along you will need an EKS cluster with PodIdentity enables as I am using Pod Identity instead of IAM-RSA. Source Code in terraform is available in my Gitrepo https://github.com/vettom/aws-eks-terraform/EKS-Auto-ACK.

Step 2. Create IAM role with POD-ID for IAM-Chart

Each ACK service controller is packaged into a separate container image that is published in a public repository corresponding to an individual ACK service controller. Container images for ACK service controllers can be found in the ACK registry within the Amazon ECR Public Gallery that contains images as well Helm chart for the controller.

In this example, I am starting with IAM-CHART and it requires an IAM policy attachment with necessary permission to create IAM roles. Here is a sample policy with Pod identity configuration using terraform.
iam-chart-por-id.tf

data "aws_iam_policy_document" "pod_id_assume_role" {
  statement {
    effect = "Allow"

    principals {
      type        = "Service"
      identifiers = ["pods.eks.amazonaws.com"]
    }

    actions = [
      "sts:AssumeRole",
      "sts:TagSession"
    ]
  }
}

resource "aws_iam_role" "ack-iam-controller" {
  name               = "ack-iam-controller"
  assume_role_policy = data.aws_iam_policy_document.pod_id_assume_role.json
}

resource "aws_iam_policy" "ack-iam-controller" {
  name        = "ack-iam-controller-policy"
  description = "Policy for ACK IAM Controller"

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = [
          "iam:CreateRole",
          "iam:DeleteRole",
          "iam:AttachRolePolicy",
          "iam:DetachRolePolicy",
          "iam:PutRolePolicy",
          "iam:DeleteRolePolicy",
          "iam:PassRole",
          "iam:GetRole",
          "iam:ListRolePolicies",
          "iam:ListAttachedRolePolicies",
          "iam:ListRoles",
          "iam:TagRole",
          "iam:UntagRole",
          "iam:UpdateAssumeRolePolicy",
          "iam:UpdateRole",
          "iam:UpdateRoleDescription",
          "iam:GetRolePolicy",
          "iam:SimulatePrincipalPolicy",
          "iam:ListRoleTags"
        ]
        Effect   = "Allow"
        Resource = "*"
      },
    ]
  })
}


resource "aws_iam_role_policy_attachment" "ack-iam-controller" {
  role       = aws_iam_role.ack-iam-controller.name
  policy_arn = aws_iam_policy.ack-iam-controller.arn
}

resource "aws_eks_pod_identity_association" "ack-iam-controller" {
  cluster_name    = module.eks.cluster_name
  namespace       = "ack-system"
  service_account = "ack-iam-controller"
  role_arn        = aws_iam_role.ack-iam-controller.arn
}

Step 3. Provision IAM controller chart

IAM-Chart requires aws.region to be set.

export SERVICE=iam
export RELEASE_VERSION=$(curl -sL https://api.github.com/repos/aws-controllers-k8s/${SERVICE}-controller/releases/latest | jq -r '.tag_name | ltrimstr("v")')
export ACK_SYSTEM_NAMESPACE=ack-system
export AWS_REGION=eu-west-1

aws ecr-public get-login-password --region us-east-1 | helm registry login --username AWS --password-stdin public.ecr.aws
helm install --create-namespace -n $ACK_SYSTEM_NAMESPACE ack-$SERVICE-controller \
  oci://public.ecr.aws/aws-controllers-k8s/$SERVICE-chart --version=$RELEASE_VERSION --set=aws.region=$AWS_REGION

Step 4. Create sample IAM role

Create example-role and validate role is created in AWS.

apiVersion: iam.services.k8s.aws/v1alpha1
kind: Role
metadata:
  name: example-role
spec:
  name: example-role
  assumeRolePolicyDocument: |
    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Principal": {
            "Service": "ec2.amazonaws.com"
          },
            "Action": [
                "sts:AssumeRole",
                "sts:TagSession"
            ]
        }
      ]
    }
  description: "Example role created by ACK"
  maxSessionDuration: 3600
  policies:
    - arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess

Step 5. Provisioning Additional controllers

Provisioning IAM-Controller first enables you to install additional controllers completely from Kubernetes. Here is example of S3 controller - Define IAM role with Pod-Identity association for S3 controller - Install S3 controller chart

Create IAM Pod ID role for S3 controller

iam-role-s3-podid.yaml

apiVersion: iam.services.k8s.aws/v1alpha1
kind: Role
metadata:
  name: ack-s3-controller
spec:
  name: ack-s3-controller
  assumeRolePolicyDocument: |
    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Principal": {
            "Service": "ec2.amazonaws.com"
          },
            "Action": [
                "sts:AssumeRole",
                "sts:TagSession"
            ]
        }
      ]
    }
  description: "IAM role created by ACK for S3 Controller"
  maxSessionDuration: 3600
  policies:
    - arn:aws:iam::aws:policy/AmazonS3FullAccess

Install S3 controller

export SERVICE=s3
export RELEASE_VERSION=$(curl -sL https://api.github.com/repos/aws-controllers-k8s/${SERVICE}-controller/releases/latest | jq -r '.tag_name | ltrimstr("v")')
export ACK_SYSTEM_NAMESPACE=ack-system
export AWS_REGION=eu-west-1

aws ecr-public get-login-password --region us-east-1 | helm registry login --username AWS --password-stdin public.ecr.aws
helm install --create-namespace -n $ACK_SYSTEM_NAMESPACE ack-$SERVICE-controller \
  oci://public.ecr.aws/aws-controllers-k8s/$SERVICE-chart --version=$RELEASE_VERSION --set=aws.region=$AWS_REGION

Provision Sample bucket

apiVersion: s3.services.k8s.aws/v1alpha1
kind: Bucket
metadata:
  name: example-ack-bucket-sample
spec:
  name: example-ack-bucket-051020251400
  versioning:
    status: Enabled
  tagging:
    tagSet:
      - key: environment
        value: dev
      - key: owner
        value: "Denny Vettom"