Terraform Deployment of Cert-Manager + Cluster Issuers + certificates:

Create the following files:

variables.tf

variable "letsencrypt_email" {
  type        = string
  description = "Email address that Let's Encrypt will use to send notifications about expiring certificates and account-related issues to."
  sensitive   = true
}
 
variable "letsencrypt_cloudflare_api_token" {
  type        = string
  description = "Cloudflare API token with Zone-DNS-Edit and Zone-Zone-Read permissions, which is required for DNS01 challenge validation."
  sensitive   = true
}

helm_cert.tf

#-------------------------------
# Certificate Manager
#-------------------------------
locals {
  helm_certs_name    = "cert-manager"
  helm_certs_repo    = "https://charts.jetstack.io"
  helm_certs_version = "v1.11.0"
}
 
resource "kubernetes_namespace" "cert_manager" {
  metadata {
    name = local.helm_certs_name
  }
 
  depends_on = [module.aks]
}
 
resource "kubernetes_secret" "letsencrypt_cloudflare_api_token_secret" {
  depends_on = [kubernetes_namespace.cert_manager]
 
  metadata {
    name      = "letsencrypt-cloudflare-api-token-secret"
    namespace = kubernetes_namespace.cert_manager.metadata.0.name
  }
 
  data = {
    "api-token" = var.letsencrypt_cloudflare_api_token
  }
}
 
resource "helm_release" "cert_manager" {
  name       = local.helm_certs_name
  repository = local.helm_certs_repo
  chart      = "cert-manager"
  version    = local.helm_certs_version
  namespace  = local.helm_certs_name
  depends_on = [kubernetes_namespace.cert_manager]
 
  set {
    name  = "installCRDs"
    value = true
  }
}
 
resource "kubernetes_manifest" "letsencrypt_issuer_staging" {
  manifest = yamldecode(templatefile(
    "${path.module}/template/letsencrypt-issuer.tpl.yaml",
    {
      "name"                      = "letsencrypt-staging"
      "email"                     = var.letsencrypt_email
      "server"                    = "https://acme-staging-v02.api.letsencrypt.org/directory"
      "api_token_secret_name"     = kubernetes_secret.letsencrypt_cloudflare_api_token_secret.metadata.0.name
      "api_token_secret_data_key" = keys(kubernetes_secret.letsencrypt_cloudflare_api_token_secret.data).0
    }
  ))
 
  depends_on = [helm_release.cert_manager]
}
 
resource "kubernetes_manifest" "letsencrypt_issuer_production" {
  manifest = yamldecode(templatefile(
    "${path.module}/template/letsencrypt-issuer.tpl.yaml",
    {
      "name"                      = "letsencrypt-production"
      "email"                     = var.letsencrypt_email
      "server"                    = "https://acme-v02.api.letsencrypt.org/directory"
      "api_token_secret_name"     = kubernetes_secret.letsencrypt_cloudflare_api_token_secret.metadata.0.name
      "api_token_secret_data_key" = keys(kubernetes_secret.letsencrypt_cloudflare_api_token_secret.data).0
    }
  ))
 
  depends_on = [helm_release.cert_manager]
}
 

template/letsencrypt-issuer.tpl.yaml

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: ${name}
spec:
  acme:
    email: ${email}
    server: ${server}
    privateKeySecretRef:
      name: issuer-account-key-${name}
    solvers:
      - dns01:
          cloudflare:
            apiTokenSecretRef:
              name: ${api_token_secret_name}
              key: ${api_token_secret_data_key}

Execute:

$ terraform apply -target="helm_release.cert_manager"
$ terraform apply -target="kubernetes_manifest.letsencrypt_issuer_production"
$ terraform apply -target="kubernetes_manifest.letsencrypt_issuer_staging"

cert staging (example):

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: api.<domain>.com.br
  namespace: <namespace>
spec:
  dnsNames:
    - api.<domain>.com.br
  secretName: api-pricing-tls
  issuerRef:
    name: letsencrypt-staging
    kind: ClusterIssuer
 

cert production:

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: api.<domain>.com.br
  namespace: <namespace>
spec:
  dnsNames:
    - api.<domain>.com.br
  secretName: api-pricing-tls
  issuerRef:
    name: letsencrypt-production
    kind: ClusterIssuer
 

🌱 Back to Garden