Route53
This guide explains how to set up an Issuer
, or ClusterIssuer
, to use Amazon
Route53 to solve DNS01 ACME challenges. It's advised you read the DNS01
Challenge Provider page first for a more general understanding of
how cert-manager handles DNS01 challenges.
âšī¸ This guide assumes that you already have a hosted zone in Route53.
đ Read the AWS + LoadBalancer + Let's Encrypt tutorial, which contains end-to-end instructions for those who are new to cert-manager and AWS.
Set up an IAM Policy
cert-manager needs to be able to add records to Route53 in order to solve the DNS01 challenge. To enable this, create a IAM policy with the following permissions:
{"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": "*"}]}
âšī¸ The
route53:ListHostedZonesByName
statement can be removed if you specify the (optional)hostedZoneID
. You can further tighten the policy by limiting the hosted zone that cert-manager has access to (e.g.arn:aws:route53:::hostedzone/DIKER8JEXAMPLE
).đ Read about actions supported by Amazon Route 53, in the Amazon Route 53 API Reference.
đ Learn how
eksctl
can automatically create the cert-manager IAM policy, if you use EKS.
Credentials
cert-manager needs an AWS access key, to authenticate to the Route53 API. An access key is defined by AWS as follows:
access key: The combination of an access key ID (for example,
AKIAIOSFODNN7EXAMPLE
) and a secret access key (for example,wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
). You use access keys to sign API requests that you make to AWS.
You have two options:
- (Best Practice) Use an IAM Role with temporary security credentials.
- Use an IAM User with a long-term access key.
Using an IAM Role with temporary security credentials is considered best practice because:
- You do not have to store the long-term access key (e.g. in a Secret)
- You don't have to manage access key rotation.
Using an IAM User with long-term access key is a reasonable choice if cert-manager is deployed outside AWS but the DNS zone is on Route53.
cert-manager supports multiple ways to get the access key and these can be categorized as either "ambient" or "non-ambient".
Ambient Credentials
Ambient credentials are credentials which are made available in the cert-manager controller Pod by one of the following mechanisms:
- EKS Pod Identity:
where cert-manager gets credentials from an EKS Auth API which runs on every Kubernetes node. - EKS IAM Roles for Service Accounts (IRSA):
where cert-manager uses a Kubernetes ServiceAccount token which is mounted into the cert-manager controller Pod. - EC2 Instance Metadata Service (IMDS):
where cert-manager gets credentials from theiam/security-credentials/<role-name>
endpoint of IMDS. - Environment variables:
where cert-manager loads credentials fromAWS_ACCESS_KEY_ID
andAWS_SECRET_ACCESS_KEY
environment variables in the cert-manager controller Pod, if those variables are present. - Shared config and credentials files:
where cert-manager loads credentials from files (~/.aws/config
and~/.aws/credentials
) which are mounted into the cert-manager controller Pod.
The advantage of ambient credentials is that they are easier to set up and extensively documented by Amazon AWS. The disadvantage of ambient credentials is that they are globally available to all ClusterIssuer and all Issuer resources, which means that in a multi-tenant environment, any tenant who has permission to create Issuer or ClusterIssuer may use the ambient credentials and gain the permissions granted to that account.
đ Read AWS SDKs and Tools standardized credential providers to learn how cert-manager supports all these ambient credential sources.
â ī¸ By default, cert-manager will only use ambient credentials for
ClusterIssuer
resources, notIssuer
resources.This is to prevent unprivileged users, who have permission to create Issuer resources, from issuing certificates using credentials that cert-manager incidentally has access to. ClusterIssuer resources are cluster scoped (not namespaced) and only platform administrators should be granted permission to create them.
â ī¸ It is possible (but not recommended) to enable ambient authentication mechanisms for
Issuer
resources, by setting the--issuer-ambient-credentials
flag on the cert-manager controller to true.
Here is an example of a ClusterIssuer
for using Route53 ambient credentials:
apiVersion: cert-manager.io/v1kind: ClusterIssuermetadata:name: letsencrypt-prodspec:acme:...solvers:- dns01:route53: {}
âšī¸ Regardless of which ambient mechanism you use, the
route53
section is left empty, because cert-manager can find the credentials, role, and region by looking for environment variables which will be added to the cert-manager Pod.
EKS Pod Identity
EKS Pod Identity is the simplest way to use ambient credentials, if you deploy cert-manager on EKS. It is a four step process:
-
Setup the EKS Pod Identity agent in your cluster.
-
Assign an IAM role to the cert-manager Kubernetes service account.
-
Restart the cert-manager Deployment so that the EKS Pod Identity Agent can inject the necessary environment variables into the Pods.
-
Create a
ClusterIssuer
resource:apiVersion: cert-manager.io/v1kind: ClusterIssuermetadata:name: letsencrypt-prodspec:acme:solvers:- dns01:route53: {}
EKS IAM Role for Service Accounts (IRSA)
IAM Roles for Service Accounts (IRSA) is another way to use ambient credentials,
if you deploy cert-manager on EKS.
It is more complicated than Pod Identity and requires coordination between the Kubernetes cluster administrator and the AWS account manager.
It involves annotating the cert-manager
ServiceAccount in Kubernetes, and setting up an IAM role, a trust policy and a trust relationship in AWS.
A mutating webhook will automatically setup a mounted service account volume in the cert-manager Pod.
-
Create an IAM OIDC provider for your cluster
To use IRSA with cert-manager you must first enable the feature for your cluster. Follow the official documentation.
-
Create a trust relationship
In this configuration an IAM role is mapped to the cert-manager
ServiceAccount
allowing it to authenticate with AWS. The IAM role you map to theServiceAccount
will need permissions on any and all Route53 zones cert-manager will be using. Create a trust relationship by adding the following trust policy to the IAM role:{"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>"}}}]}Replace the following:
-
<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>
with the hash in the EKS API URL; this will be a random 32 character hex string (example:45DABD88EEE3A227AF0FA468BE4EF0B5
). -
<namespace>
with the namespace where cert-manager is running. -
<service-account-name>
with the name of theServiceAccount
object created by cert-manager.
âšī¸ If you're following the Cross Account example, this trust policy is attached to the cert-manager role in Account X with ARN
arn:aws:iam::XXXXXXXXXXX:role/cert-manager
. The permissions policy is the same as above. -
-
Annotate the cert-manager
ServiceAccount
apiVersion: v1kind: ServiceAccountmetadata:annotations:eks.amazonaws.com/role-arn: arn:aws:iam::XXXXXXXXXXX:role/cert-managerThe cert-manager Helm chart provides a variable for injecting annotations into cert-manager's
ServiceAccount
like so:serviceAccount:annotations:eks.amazonaws.com/role-arn: arn:aws:iam::XXXXXXXXXXX:role/cert-managerâšī¸ If you're following the Cross Account example, modify the
ClusterIssuer
with the role from Account Y. -
(optional) Update file system permissions
đĸ Please help us improve this documentation
The reason for this optional step is that on EKS Fargate and on some older versions of EKS you may observe errors such as:
unable to read file at /var/run/secrets/eks.amazonaws.com/serviceaccount/token
open /var/run/secrets/eks.amazonaws.com/serviceaccount/token: permission denied
In this case, you can change the user and group of the cert-manager process so that it is able to read the mounted ServiceAccount token.
Read
cert-manager/website#697
: IRSA NeedsrunAsUser: 1001
and tell us whether this step is still necessary or obsolete.You may also need to modify the cert-manager
Deployment
with a different user and group, so theServiceAccount
token can be read.spec:template:spec:securityContext:fsGroup: 1001runAsUser: 1001The cert-manager Helm chart provides a variable for modifying cert-manager's
Deployment
like so:securityContext:fsGroup: 1001runAsUser: 1001 -
Restart the cert-manager Deployment
Restart the cert-manager Deployment, so that the webhook can inject the necessary
volume
,volumemount
, and environment variables into the Pods. -
Create a
ClusterIssuer
resourceapiVersion: cert-manager.io/v1kind: ClusterIssuermetadata:name: letsencrypt-prodspec:acme:solvers:- dns01:route53: {}
Non-ambient Credentials
Non-ambient credentials are credentials which are explicitly configured on the Issuer or ClusterIssuer resource. For example:
- Access key Secret reference:
where cert-manager loads a long-term access key from a Kubernetes Secret resource. - ServiceAccount reference:
where cert-manager gets a ServiceAccount token (signed JWT) from the Kubernetes API server, and uses the STS AssumeRoleWithWebIdentity endpoint to exchange it for temporary AWS credentials.
The advantage of non-ambient credentials is that cert-manager can perform Route53 operations in a multi-tenant environment. Each tenant can be granted permission to create and update Issuer resources in their namespace and they can provide their own AWS credentials in their namespace.
IAM Role with dedicated Kubernetes ServiceAccount
đ Read the AWS + LoadBalancer + Let's Encrypt tutorial to learn how to deploy cert-manager on EKS and use this authentication mechanism.
In this configuration you can reference your own ServiceAccounts
in your Issuer
or ClusterIssuer
and cert-manager will get a ServiceAccount token from the Kubernetes API which it will send to STS in exchange for AWS temporary credentials.
The advantages of this mechanism are:
- Each Issuer can reference a different
ServiceAccount
, which means you can lock down the permissions, such that eachServiceAccount
is mapped to an IAM role that only has permission to update the zones it needs (unlike Pod Identity or IRSA). - This mechanism works even when cert-manager is deployed outside AWS.
Here's how to set it up:
-
Create a ServiceAccount
In order to reference a
ServiceAccount
it must first exist. Unlike normal IRSA theeks.amazonaws.com/role-arn
annotation is not required.apiVersion: v1kind: ServiceAccountmetadata:name: <service-account-name> -
Create an IAM role trust policy
For every
ServiceAccount
you want to use for AWS authentication you must first set up a trust policy:{"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>"}}}]}Replace the following:
<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>
with the hash in the EKS API URL; this will be a random 32 character hex string (example:45DABD88EEE3A227AF0FA468BE4EF0B5
).<namespace>
with the namespace of theServiceAccount
object.<service-account-name>
with the name of theServiceAccount
object.
-
Create an RBAC Role and RoleBinding
In order to allow cert-manager to issue a token using your
ServiceAccount
you must deploy some RBAC to the cluster:apiVersion: rbac.authorization.k8s.io/v1kind: Rolemetadata:name: <service-account-name>-tokenrequestnamespace: <service-account-namespace>rules:- apiGroups: ['']resources: ['serviceaccounts/token']resourceNames: ['<service-account-name>']verbs: ['create']---apiVersion: rbac.authorization.k8s.io/v1kind: RoleBindingmetadata:name: cert-manager-<service-account-name>-tokenrequestnamespace: <service-account-namespace>subjects:- kind: ServiceAccountname: <cert-manager-service-account-name>namespace: <cert-manager-namespace>roleRef:apiGroup: rbac.authorization.k8s.iokind: Rolename: <service-account-name>-tokenrequestReplace the following:
<service-account-name>
name of theServiceAccount
object.<service-account-namespace>
namespace of theServiceAccount
object.<cert-manager-service-account-name>
name of cert-managersServiceAccount
object, as created during cert-manager installation.<cert-manager-namespace>
namespace that cert-manager is deployed into.
-
Create an Issuer or ClusterIssuer
You should be ready at this point to configure an Issuer to use the new
ServiceAccount
. You can see example config for this below:apiVersion: cert-manager.io/v1kind: Issuermetadata:name: examplespec:acme:...solvers:- dns01:route53:region: us-east-1role: <iam-role-arn> # This must be set so cert-manager what role to attempt to authenticate withauth:kubernetes:serviceAccountRef:name: <service-account-name> # The name of the service account created
IAM User with long-term access key
In this mechanism, cert-manager will load the credentials from a Secret resource.
If you use an Issuer
resource, the Secret must be in the same namespace as the Issuer.
If you use a ClusterIssuer
resource, the Secret must be in the cert-manager
namespace
or what ever value is supplied to the --cluster-resource-namespace
option of the cert-manager component.
The advantages of this mechanism are that it is simple and it works even when cert-manager is deployed outside AWS.
Here is an example configuration for a ClusterIssuer
:
apiVersion: cert-manager.io/v1kind: ClusterIssuermetadata:name: letsencrypt-prodspec:acme:...solvers:- dns01:route53:region: eu-central-1accessKeyIDSecretRef:name: prod-route53-credentials-secretkey: access-key-idsecretAccessKeySecretRef:name: prod-route53-credentials-secretkey: secret-access-key# (optional) you can also assume a role with these credentialsrole: arn:aws:iam::YYYYYYYYYYYY:role/dns-manager
Cross Account Access
Example: Account Y manages Route53 DNS Zones. Now you want cert-manager running in Account X (or many other accounts) to be able to manage records in Route53 zones hosted in Account Y.
First, create a role with the permissions policy above (let's call the role dns-manager
)
in Account Y, and attach a trust relationship like the one below.
{"Version": "2012-10-17","Statement": [{"Effect": "Allow","Principal": {"AWS": "arn:aws:iam::XXXXXXXXXXX:role/cert-manager"},"Action": "sts:AssumeRole"}]}
Bear in mind, that you won't be able to define this policy until cert-manager
role on account Y is created. If you are setting this up using a configuration language, you may want to define principal as:
"Principal": {"AWS": "XXXXXXXXXXX"}
And restrict it, in a future step, after all the roles are created.
This allows the role cert-manager
in Account X to assume the dns-manager
role in Account Y to manage the Route53 DNS zones in Account Y. For more information visit the official
documentation.
Second, create the cert-manager role in Account X; this will be used as a credentials source for the cert-manager pods running in Account X. Attach to the role the following permissions policy:
{"Version": "2012-10-17","Statement": [{"Effect": "Allow","Resource": "arn:aws:iam::YYYYYYYYYYYY:role/dns-manager","Action": "sts:AssumeRole"}]}
And the following trust relationship (Add AWS Service
s as needed):
{"Version": "2012-10-17","Statement": [{"Effect": "Allow","Principal": {"Service": "ec2.amazonaws.com"},"Action": "sts:AssumeRole"}]}
Region
If you omit the .spec.acme.solvers.dns01.route53.region
field, cert-manager
will get the region from the AWS_REGION
and AWS_DEFAULT_REGION
environment
variables if they are set in the cert-manager controller Pod.
If you use ambient credentials, the AWS_REGION
and
AWS_DEFAULT_REGION
environment variables have a higher priority, and the
.spec.acme.solvers.dns01.route53.region
field will only be used if the
environment variables are not set.
The .spec.acme.solvers.dns01.route53.region
field is ignored if you use EKS Pod Identities,
because an AWS_REGION
environment variable is added to the cert-manager controller Pod by
the Amazon EKS Pod Identity Agent.
The .spec.acme.solvers.dns01.route53.region
field is ignored if you use IAM Roles for Service Accounts (IRSA),
because an AWS_REGION
environment variable is added to the cert-manager controller Pod by
the Amazon EKS Pod Identity Webhook.
âšī¸ Route53 is a global service and does not have regional endpoints, but the region is used as a hint to help compute the correct AWS credential scope and partition when it connects to Route53.
đ Read Amazon Route 53 endpoints and quotas and Global services to learn more.
âšī¸ STS is a regional service and cert-manager will use regional STS endpoint URLs computed from the
region
field or environment variables. STS is used for IRSA credentials, dedicated ServiceAccount credentials, and cross account access.đ Read Manage AWS STS in an AWS Region to learn about which regions support STS.
đ Read AWS STS Regional endpoints, to learn how to configure the use of regional STS endpoints using environment variables.