Cert-manager with LetsEncrypt
Free SSL certificate with LetsEncrypt
Cert-Manager is a powerful and extensible X.509 certificate controller for Kubernetes platforms. It will obtain certificates from a variety of Issuers, both popular public Issuers as well as private Issuers, and ensure the certificates are valid and up-to-date, and will attempt to renew certificates at a configured time before expiry. It also exposes metrics to enable monitoring certificate issues and expiry.
Configure Cert-manager
There 3 parts to configuring Cert-manager on your Kubernetes cluster. In this example, I have EKS cluster and domain configured in Route53. So I will configure DNS validation for Certificate issue and signing. Lets Encrypt will provide free certificate independent of cluster provider. Check cert-manager for supported certificate issuers.
- Configure authentication (Pod Identity to modify DNS entry).
- Install Cert-manager with custom values.
- Configure clusterIssuer or Issuer to sign your certificates.
- Configure
Ingress
/Gateway
resource with cert-manager annotation and TLS section.
Authentication : IAM policy and Pod Identity
Step 1.
Create IAM policy that allows creation of DNS records. This is required for Certificate issuer to perform Domain Validation. LetsEncrypt provides two ways for Domain Validation, DNS record under your domain
or HTTP resource under specific path
. In this example I will configure DNS validation, hence IAM policy with DNS record update permission.
- IAM policy
CertManagerIAMPolicy
allowing DNS record creation{ "Version" : "2012-10-17", "Statement" : [ { "Effect" : "Allow", "Action" : "route53:GetChange", "Resource" : "arn:aws:route53:::change/*" }, { "Effect" : "Allow", "Action" : [ "route53:ListHostedZones", "route53:ListHostedZonesByName" ], "Resource" : "*" }, { "Effect" : "Allow", "Action" : "route53:ListResourceRecordSets", "Resource" : "arn:aws:route53:::hostedzone/*" }, { "Effect" : "Allow", "Action" : "route53:ChangeResourceRecordSets", "Resource" : "arn:aws:route53:::hostedzone/*" } ] }
Step 2.
Create IAM role cert-manager-iam-role
with Pod Identity
trust policy and attach CertManagerIAMPolicy
- Trust policy for Pod Identity service
Step 3.
In EKS create Pod Identity Association for namespace cert-manager
and service account cert-manager
to IAM role cert-manager-iam-role
Step 5.
Prepare custom values.yaml
file for Cert-manager
-
values.yaml
-
installCRDs: CRD's are not installed by default, so this argument must be true, or install CRD's separate.
- config: Ingress is supported by default, add configuration for
Gateway API
support - serviceAccount: SA to be used by Cert-manager installation. Must match SA specified in Pod Identity spec.
Install Cert-manager with custom values.yaml
file.
helm repo add jetstack https://charts.jetstack.io ; helm repo update jetstack
helm install cert-manager jetstack/cert-manager -n cert-manager --create-namespace --version v1.16.2 -f cert-manager/values.yaml
Once Cert-manager is installed, you'll need to configure Issuer
or a ClusterIssuer
to issue certificates. These are resources that represent certificate authorities (CAs) able to sign certificates in response to certificate signing requests. The ClusterIssuer
resource is cluster scoped which will be the use case for most users. Cert-manager supports many certificate issuers, in this example I will be configuring LetsEncrypt ACME provider.
Why not use AWS Cert Authority? : At present AWS only supports Private Certificate Authority
- *
ClusterIssuer
with LetsEncrypt and DNS validation.apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-route53 spec: acme: email: admin@vettom.online server: https://acme-staging-v02.api.letsencrypt.org/directory # Staging server # server: https://acme-v02.api.letsencrypt.org/directory # Production service privateKeySecretRef: name: letsencrypt-route53 solvers: - selector: dnsZones: - vettom.online - "*.vettom.online" - "*.prd.vettom.online" dns01: route53: region: eu-west-1
- acme.server: URL of ACME server. Always start with staging URL and verify before switch to production URL.
- acme.privateKeySecretRef: Secret file holding Certificate
PrivateKey
- solvers.selector: Specify domain for which cert-manager will issue certificate.
- solvers.dns01.route53: Challenge type to be used.
Step 7.
Create Gateway resource with cert-manager annotation and TLS section. Below example configures gateway to listen for http and https traffic. HTTPS traffic is defined with wildcard domain name *.vettom.online
and cert-manager annotation added to Gateway itself. Issued certificate will be stored in secret called mygateway-cert
in namespace gateway
.
Sample Gateway app can be found in my repo aws-eks-terraform. To learn more about configuring Gateway API check https://vettom.pages.dev/Eks/eks-cluster-karpenter/
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: external-gateway
namespace: gateway
annotations:
argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true
cert-manager.io/cluster-issuer: letsencrypt-route53
spec:
gatewayClassName: external-gatewayclass
listeners:
- name: http
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: All
- name: https
hostname: "*.vettom.online"
port: 443
protocol: HTTPS
allowedRoutes:
namespaces:
from: All
tls:
certificateRefs:
- kind: Secret
group: ""
name: "mygateway-cert"
namespace: gateway
Deploy an application with respective HTTP route and validate. A sample app can be found in repo aws-eks-terraform/EKS-Cluster-generic/Sample-app
Terraform code for IAM role and Pod Identity
# IAM policy to enable DNS record creation and lookup
resource "aws_iam_policy" "certmanager_iam_policy" {
name = "CertManagerIAMPolicy"
policy = jsonencode(
{
"Version" : "2012-10-17",
"Statement" : [
{
"Effect" : "Allow",
"Action" : "route53:GetChange",
"Resource" : "arn:aws:route53:::change/*"
},
{
"Effect" : "Allow",
"Action" : [
"route53:ListHostedZones",
"route53:ListHostedZonesByName"
],
"Resource" : "*"
},
{
"Effect" : "Allow",
"Action" : "route53:ListResourceRecordSets",
"Resource" : "arn:aws:route53:::hostedzone/*"
},
{
"Effect" : "Allow",
"Action" : "route53:ChangeResourceRecordSets",
"Resource" : "arn:aws:route53:::hostedzone/*"
}
]
}
)
}
# IAM role for cert manager
resource "aws_iam_role" "certmanager_iam_role" {
name = "cert-manager-iam-role"
assume_role_policy = data.aws_iam_policy_document.podidentity.json
}
# Attach policy to IAM role
resource "aws_iam_role_policy_attachment" "certmanager_policy_attachement" {
role = aws_iam_role.certmanager_iam_role.name
policy_arn = aws_iam_policy.certmanager_iam_policy.arn
}
# Associate Pod identity with IAM role
resource "aws_eks_pod_identity_association" "certmanager" {
cluster_name = module.eks.cluster_name
namespace = "cert-manager"
service_account = "cert-manager"
role_arn = aws_iam_role.certmanager_iam_role.arn
}