Certificate Management with cert-manager

Complete guide for setting up and managing SSL/TLS certificates using cert-manager and Let’s Encrypt.

Table of Contents

Overview

This guide covers:

  • Installing cert-manager on Kubernetes
  • Configuring AWS Route53 for DNS validation
  • Creating staging and production certificate issuers
  • Generating wildcard certificates for your domain
  • Certificate rotation procedures

Prerequisites

Software Requirements

Component Version Purpose Installation Guide
Kubernetes 1.16+ Container orchestration platform TKG Setup
kubectl 1.16+ Kubernetes command-line tool kubectl install
Helm 3.x Kubernetes package manager Helm install

AWS Requirements

Resource Purpose Configuration Required
AWS Account Route53 DNS management Valid billing account
Route53 Hosted Zone Domain DNS management Your domain must be hosted in Route53
IAM User API access for DNS validation Policy with Route53 permissions
AWS Access Keys Programmatic access Access Key ID and Secret Access Key

Required IAM Permissions:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "route53:GetChange",
        "route53:ChangeResourceRecordSets",
        "route53:ListResourceRecordSets",
        "route53:ListHostedZonesByName"
      ],
      "Resource": "*"
    }
  ]
}

Environment Variables

Variable Description Example Required
AWS_ACCESS_KEY_ID AWS access key for Route53 AKIAIOSFODNN7EXAMPLE Yes
ROUTE53_SECRET_ACCESS_KEY Route53 secret key wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY Yes
LETSENCRYPT_EMAIL Email for Let’s Encrypt notifications admin@yourdomain.com Yes

Network Requirements

Port Protocol Purpose Source Destination
443 HTTPS ACME certificate validation Let’s Encrypt Kubernetes cluster
53 DNS Route53 API access Kubernetes cluster AWS Route53
80 HTTP ACME HTTP-01 challenge (optional) Let’s Encrypt Kubernetes cluster

Domain Requirements

  • Domain Ownership: You must own and control the domain
  • Route53 Hosting: Domain must be hosted in AWS Route53
  • DNS Resolution: Domain must resolve correctly from public internet
  • Wildcard Support: For wildcard certificates, ensure subdomain delegation works

Verification Checklist

Before proceeding, verify:

  • Kubernetes cluster is healthy: kubectl get nodes
  • AWS credentials work: aws route53 list-hosted-zones
  • Domain resolves: nslookup yourdomain.com
  • Environment variables set: echo $LETSENCRYPT_EMAIL
  • Internet connectivity from cluster to Let’s Encrypt
  • cert-manager CRDs can be installed (cluster admin access)

Installation

Deploy cert-manager

Install cert-manager using the official manifests:

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

Verify installation:

kubectl get pods --namespace cert-manager
kubectl get crd | grep cert-manager

AWS Route53 Setup

IAM Role Configuration

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

Configure Credentials

Create the Route53 secret:

# Load environment variables first: source .envrc or direnv allow
kubectl create secret generic route53-secret \
  --from-literal=secret-access-key="${ROUTE53_SECRET_ACCESS_KEY}" \
  --namespace cert-manager

Verify secret creation:

kubectl get secret route53-secret --namespace cert-manager -ojsonpath={.data.secret-access-key} | base64 -d

Certificate Issuers

Staging Issuer (Testing)

Create a staging issuer for testing certificate generation:

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-staging
spec:
  acme:
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    email: ${LETSENCRYPT_EMAIL}
    privateKeySecretRef:
      name: letsencrypt-staging
    solvers:
    - dns01:
        route53:
          region: us-east-1
          accessKeyID: ${AWS_ACCESS_KEY_ID}
          secretAccessKeySecretRef:
            name: route53-secret
            key: secret-access-key

Production Issuer

Create the production issuer for real certificates:

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: ${LETSENCRYPT_EMAIL}
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
    - dns01:
        route53:
          region: us-east-1
          accessKeyID: ${AWS_ACCESS_KEY_ID}
          secretAccessKeySecretRef:
            name: route53-secret
            key: secret-access-key

Managing Certificates

Create Wildcard Certificate

Generate a wildcard certificate for your domain:

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: prod-wildcard-certs
  namespace: cert-manager
spec:
  secretName: prod-wildcard-certs
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  dnsNames:
  - "*.markalston.net"
  - "*.tkg.markalston.net"

Export Certificates

Extract the generated certificates:

# Export private key
kubectl get secrets prod-wildcard-certs -n cert-manager \
  -ojsonpath={.data.'tls\.key'} | base64 -d > prod.key

# Export certificate
kubectl get secrets prod-wildcard-certs -n cert-manager \
  -ojsonpath={.data.'tls\.crt'} | base64 -d > prod.crt

Certificate Rotation

To rotate certificates:

  1. Delete the existing certificate secret
  2. cert-manager will automatically regenerate it
kubectl delete secret prod-wildcard-certs -n cert-manager
# cert-manager will recreate the certificate

Verification

Check Certificate Status

kubectl get certificates -n cert-manager
kubectl describe certificate prod-wildcard-certs -n cert-manager

Test Certificate

openssl x509 -in prod.crt -text -noout

Troubleshooting

Common Issues

Issue: Certificate stuck in “Pending”

Check cert-manager logs:

kubectl logs -n cert-manager deployment/cert-manager

Issue: DNS validation failing

Verify Route53 permissions:

kubectl describe challenge -n cert-manager

Debug Commands

# Check all cert-manager resources
kubectl get Issuers,ClusterIssuers,Certificates,CertificateRequests,Orders,Challenges --all-namespaces

# View cert-manager events
kubectl get events -n cert-manager --sort-by='.lastTimestamp'

Best Practices

  1. Always test with staging issuer first
  2. Use wildcard certificates to minimize rate limits
  3. Monitor certificate expiration dates
  4. Automate certificate distribution to services

References


Last Updated: 2024 Part of the Homelab Documentation Series


This project is for educational and home lab purposes.