Logo Kubeship

Install cert-manager on AWS Elastic Kubernetes Service (EKS)


cert-manager is a tool that can request SSL certificates in Kubernetes, similar to certbot on the command line.

Install cert-manager from the official manifest files :

kubectl apply -f \
    https://github.com/cert-manager/cert-manager/releases/download/v1.19.1/cert-manager.yaml

Next create a file cert-manager-policy.json and save the following content :

{
  "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": "*"
    }
  ]
}

Use the following command to create the policy :

aws iam create-policy                           \
    --policy-name      cert-manager-policy      \
    --policy-document  file://cert-manager-policy.json

The policy will allow cert-manager to create DNS resources in Route 53 to prove we own the domain (DNS challenge).

We can use the eksctl command to create service account that will access Route 53.

eksctl create iamserviceaccount                                                         \
    --name                cert-manager                                                  \
    --namespace           cert-manager                                                  \
    --cluster             $CLUSTER_NAME                                                 \
    --attach-policy-arn   arn:aws:iam::${AWS_ACCOUNT_ID}:policy/cert-manager-policy     \
    --role-name           cert-manager-role                                             \
    --override-existing-serviceaccounts                                                 \
    --approve

Create the following file and save as rbac.yaml :

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: cert-manager-token-request-role
  namespace: cert-manager
rules:
  - apiGroups: ['']
    resources: ['serviceaccounts/token']
    resourceNames: ['cert-manager-policy']
    verbs: ['create']
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: cert-manager-token-request-role
  namespace: cert-manager
subjects:
  - kind: ServiceAccount
    name: cert-manager
    namespace: cert-manager
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: cert-manager-token-request-role

Link the role to service account for cert-manager :

kubectl apply -f rbac.yaml

We should be able to request certificates. We need to create a cluster issuer.

Create the following file :

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: email@mydomain.com
    privateKeySecretRef:
      name: letsencrypt-private-key
    solvers:
    - dns01:
        route53:
          region: ${AWS_REGION}
          role: arn:aws:iam::${AWS_ACCOUNT_ID}:role/cert-manager
          auth:
            kubernetes:
              serviceAccountRef:
                name: cert-manager

Save the file and execute the command :

envsubst < clusterissuer-yaml | kubectl apply -f  -

Create a new certificate resouce :

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: certificate
  namespace: my-namespace
spec:
  secretName: certificate-tls
  privateKey:
    rotationPolicy: Always
  dnsNames:
    - "mydomain.com"
    - "*.mydomain.com"
    - "*.dev.mydomain.com"
    - "*.staging.mydomain.com"
  usages:
    - digital signature
    - key encipherment
    - server auth
  issuerRef:
    kind: ClusterIssuer
    name: letsencrypt-prod

Now that we can request SSL certificates, continue to Part II - Install Ingress-NGINX

Keywords : AWS, Kubernetes, cert-manager, SSL, Let's Encrypt