Creating an IAM OIDC provider for your cluster

  • Requirements
    • AWS CLI version Version 2.9.1 or later (version 2)

Determine whether you have an existing IAM OIDC provider for your cluster.

  • Retrieve your cluster’s OIDC provider ID and store it in a variable.
oidc_id=$(aws eks describe-cluster --name my-cluster --query "cluster.identity.oidc.issuer" --output text | cut -d '/' -f 5)
  • Determine whether an IAM OIDC provider with your cluster’s ID is already in your account.
aws iam list-open-id-connect-providers | grep $oidc_id

If output is returned from the previous command, then you already have a provider for your cluster and you can skip the next step. If no output is returned, then you must create an IAM OIDC provider for your cluster.

  • Create an IAM OIDC identity provider for your cluster with the following command. Replace my-cluster with your own value.
eksctl utils associate-iam-oidc-provider --cluster my-cluster --approve

CERT-MANAGER INSTALLATION AND CONFIGURATION

  • Create a role and attach the following policy
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "route53:GetChange",
      "Resource": "arn:aws:route53:::change/*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "route53:ChangeResourceRecordSets",
        "route53:ListResourceRecordSets"
      ],
      "Resource": "arn:aws:route53:::hostedzone/*"
    },
    {
      "Effect": "Allow",
      "Action": "route53:ListHostedZonesByName",
      "Resource": "*"
    }
  ]
}
  • Config the trust policy in the role (Created in the previous step), go to “Trust relationships” tab and set the policy.

    • <aws-account-id> with the AWS account ID of the EKS cluster.
    • <aws-region> with the region where the EKS cluster is located.
    • <eks-hash> run aws eks describe-cluster --name liberty-c62d9cc --query "cluster.identity.oidc.issuer" --output text | cut -d '/' -f 5 to get it
    • <namespace> with the namespace where cert-manager is running.
    • <service-account-name> with the name of the ServiceAccount object created by cert-manager.
    {
    "Version": "2012-10-17",
    "Statement": [
      {
        "Effect": "Allow",
        "Action": "sts:AssumeRoleWithWebIdentity",
        "Principal": {
          "Federated": "arn:aws:iam::<aws-account-id>:oidc-provider/oidc.eks.<aws-region>.amazonaws.com/id/<eks-hash>"
        },
        "Condition": {
          "StringEquals": {
            "oidc.eks.<aws-region>.amazonaws.com/id/<eks-hash>:sub": "system:serviceaccount:<namespace>:<service-account-name>",
            "oidc.eks.<aws-region>.amazonaws.com/id/<eks-hash>:aud": "sts.amazonaws.com"
          }
        }
      }
    ]
    }

    example:

    {
      "Version": "2012-10-17",
      "Statement": [
          {
              "Effect": "Allow",
              "Principal": {
                  "Federated": "arn:aws:iam::123456789:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/45DABD88EEE3A227AF0FA468BE4EF0B5"
              },
              "Action": "sts:AssumeRoleWithWebIdentity",
              "Condition": {
                  "StringEquals": {
                      "oidc.eks.us-east-1.amazonaws.com/id/45DABD88EEE3A227AF0FA468BE4EF0B5:sub": "system:serviceaccount:cert-manager:cert-manager",
                      "oidc.eks.us-east-1.amazonaws.com/id/45DABD88EEE3A227AF0FA468BE4EF0B5:aud": "sts.amazonaws.com"
                  }
              }
          }
      ]
    }
  • Install Cert Manager

    • Create cert-manager-values.yml
#cert-manager-values.yml
serviceAccount:
  create: true
  # this is very important, it has to be the same name as <service-account-name> value in trust relationship policy
  name: cert-manager
  annotations:
    # role created in the step before
    eks.amazonaws.com/role-arn: arn:aws:iam::168476488911:role/cert-manager
  installCRDs: true
# the securityContext is required, so the pod can access files required to assume the IAM role
securityContext:
  fsGroup: 1001
  • Install it using helm
helm repo add jetstack https://charts.jetstack.io
helm upgrade cert-manager jetstack/cert-manager \                                                   
  --install \              
  --namespace cert-manager \
  --create-namespace \
  --values "cert-manager-values.yml" \
  --wait
  • Define and apply ClusterIssuer
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt
spec:
  acme:
    email: EXAMPLE@EXAMPLE.com
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: letsencrypt
    solvers:
    - selector:
        dnsZones:
        # your hosted zone from route53
        - "EXAMPLE.COM"
      dns01:
        route53:
          region: us-east-1

- TESTING (Optional)

At this point you have to be able to generate certificates with status Ready in True (kubectl get certificate pointing to the ns where the resource is running). Create the following Ingress to test if cert manager is working. - cert-manager.io/cluster-issuer: the name of the ClusterIssuer. - host: the domain to certificate

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    # add an annotation indicating the issuer to use.
    cert-manager.io/cluster-issuer: letsencrypt
  name: test-ingress
  namespace: default
spec:
  rules:
  - host: test.aaa.bbb.com
    http:
      paths:
      - pathType: Prefix
        path: /
        backend:
          service:
            name: test-service
            port:
              number: 80
  tls: # < placing a host in the TLS config will determine what ends up in the cert's subjectAltNames
  - hosts:
    - test.aaa.bbb.com
    secretName: test-ingress

- References

  • https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html
  • https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html
  • https://cert-manager.io/docs/configuration/acme/dns01/route53/#eks-iam-role-for-service-accounts-irsa