Skip to content

Instantly share code, notes, and snippets.

@javierguzman
Created May 13, 2024 13:12
Show Gist options
  • Save javierguzman/6a97f0d5d19424292e32ec815cfab7dd to your computer and use it in GitHub Desktop.
Save javierguzman/6a97f0d5d19424292e32ec815cfab7dd to your computer and use it in GitHub Desktop.
PKI Engine with cert manager
resource "helm_release" "cert_manager" {
name = "cert-manager"
namespace = "cert-manager"
repository = "https://charts.jetstack.io"
chart = "cert-manager"
version = "v1.15.0-alpha.0"
create_namespace = true
set {
name = "installCRDs"
value = "true"
}
}
resource "kubectl_manifest" "issuer" {
yaml_body = <<YAML
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: ${var.environment}-issuer
namespace: ${kubernetes_namespace_v1.issuer_namespace.metadata[0].name}
spec:
vault:
server: ${var.vault_address}
path: "${vault_mount.pki_engine.path}/sign/${local.raw_domain}"
auth:
kubernetes:
mountPath: /v1/auth/kubernetes-pki
role: ${vault_kubernetes_auth_backend_role.sa_issuer_role.role_name}
serviceAccountRef:
name: ${kubernetes_service_account_v1.issuer_sa.metadata[0].name}
audiences: ["vault://${var.environment}-issuer/${var.environment}-issuer-sa"]
YAML
depends_on = [helm_release.cert_manager, vault_pki_secret_backend_root_cert.root_cert]
}
resource "kubernetes_namespace_v1" "issuer_namespace" {
metadata {
name = "${var.environment}-issuer"
}
}
resource "kubernetes_service_account_v1" "issuer_sa" {
metadata {
name = "${var.environment}-issuer-sa"
namespace = kubernetes_namespace_v1.issuer_namespace.metadata[0].name
}
}
resource "kubernetes_secret_v1" "issuer_sa_secret" {
metadata {
annotations = {
"kubernetes.io/service-account.name" = kubernetes_service_account_v1.issuer_sa.metadata.0.name
"kubernetes.io/service-account.namespace" = kubernetes_namespace_v1.issuer_namespace.metadata[0].name
}
name = "${kubernetes_service_account_v1.issuer_sa.metadata[0].name}-secret"
namespace = kubernetes_namespace_v1.issuer_namespace.metadata[0].name
}
type = "kubernetes.io/service-account-token"
wait_for_service_account_token = true
}
resource "kubernetes_role_v1" "issuer_role" {
metadata {
name = "${kubernetes_service_account_v1.issuer_sa.metadata[0].name}-role"
namespace = kubernetes_namespace_v1.issuer_namespace.metadata[0].name
}
rule {
api_groups = [""]
resources = ["serviceaccounts/token"]
resource_names = [kubernetes_service_account_v1.issuer_sa.metadata[0].name]
verbs = ["create"]
}
}
resource "kubernetes_role_binding_v1" "issuer_sa_rb" {
metadata {
name = "${kubernetes_service_account_v1.issuer_sa.metadata[0].name}-rb"
namespace = kubernetes_namespace_v1.issuer_namespace.metadata[0].name
}
role_ref {
api_group = "rbac.authorization.k8s.io"
kind = "Role"
name = kubernetes_role_v1.issuer_role.metadata[0].name
}
subject {
kind = "ServiceAccount"
name = "cert-manager"
namespace = "cert-manager"
}
}
resource "kubernetes_cluster_role_binding_v1" "issuer_sa_crb" {
metadata {
name = "${kubernetes_service_account_v1.issuer_sa.metadata[0].name}-crb"
}
role_ref {
api_group = "rbac.authorization.k8s.io"
kind = "ClusterRole"
name = "system:auth-delegator"
}
subject {
kind = "ServiceAccount"
name = kubernetes_service_account_v1.issuer_sa.metadata[0].name
namespace = kubernetes_namespace_v1.issuer_namespace.metadata[0].name
}
}
resource "vault_mount" "pki_engine" {
description = "Enable PKI Engine"
path = "pki"
type = "pki"
default_lease_ttl_seconds = 3600 # 1 hour
max_lease_ttl_seconds = 86400 # 1 day
}
resource "vault_auth_backend" "kubernetes" {
type = "kubernetes"
path = "kubernetes-pki"
}
data "aws_eks_cluster" "eks_cluster" {
name = "mydomaincluster-${var.environment}"
}
locals {
domain = "mydomain.com"
raw_domain = "mydomain-dot-com"
organization = "MyDomain"
}
resource "vault_kubernetes_auth_backend_config" "connect_sa_with_vault" {
backend = vault_auth_backend.kubernetes.path
kubernetes_host = data.aws_eks_cluster.eks_cluster.endpoint
//token_reviewer_jwt = kubernetes_secret_v1.issuer_sa_secret.data["token"]
kubernetes_ca_cert = kubernetes_secret_v1.issuer_sa_secret.data["ca.crt"]
//disable_iss_validation = "false"
issuer = "https://oidc.eks.whatever-region.amazonaws.com/id/randomID"
}
resource "vault_pki_secret_backend_root_cert" "root_cert" {
depends_on = [vault_mount.pki_engine]
backend = vault_mount.pki_engine.path
type = "internal"
common_name = local.domain
ttl = "8760h"
format = "pem"
private_key_format = "der"
key_type = "rsa"
key_bits = 4096
exclude_cn_from_sans = true
organization = local.organization
}
resource "vault_pki_secret_backend_config_urls" "pki_urls" {
backend = vault_mount.pki_engine.path
issuing_certificates = ["${var.vault_address}/v1/${vault_mount.pki_engine.path}/ca"]
crl_distribution_points = ["${var.vault_address}/v1/${vault_mount.pki_engine.path}/crl"]
}
resource "vault_pki_secret_backend_role" "pki_role" {
backend = vault_mount.pki_engine.path
name = local.raw_domain
ttl = 3600
max_ttl = 259200 #72h
allow_ip_sans = true
key_type = "rsa"
key_bits = 4096
allowed_domains = [local.domain]
allow_subdomains = true
allow_localhost = false
}
resource "vault_policy" "pki_policy" {
name = "pki-policy"
policy = <<EOT
path "${vault_mount.pki_engine.path}*" { capabilities = ["read", "list"] }
path "${vault_mount.pki_engine.path}/sign/${local.raw_domain}" { capabilities = ["create", "update"] }
path "${vault_mount.pki_engine.path}/roles/${local.raw_domain}" { capabilities = ["create", "update"] }
path "${vault_mount.pki_engine.path}/issuers/${local.raw_domain}" { capabilities = ["create"] }
EOT
}
resource "vault_kubernetes_auth_backend_role" "sa_issuer_role" {
backend = vault_auth_backend.kubernetes.path
role_name = "${var.environment}-issuer-hashi-role"
bound_service_account_names = [kubernetes_service_account_v1.issuer_sa.metadata[0].name]
bound_service_account_namespaces = [kubernetes_namespace_v1.issuer_namespace.metadata[0].name]
audience = "vault://${kubernetes_namespace_v1.issuer_namespace.metadata[0].name}/${kubernetes_service_account_v1.issuer_sa.metadata[0].name}"
token_ttl = 3600 # seconds
token_policies = [vault_policy.pki_policy.name, "default"]
}
resource "vault_generic_endpoint" "pki_auto_tidy" {
# 24h is 86400 seconds, we do this to avoid incorrect TF drifting
path = "${vault_mount.pki_engine.path}/config/auto-tidy"
ignore_absent_fields = true
data_json = <<EOT
{
"enabled": true,
"tidy_cert_store": true,
"safety_buffer": 86400
}
EOT
depends_on = [vault_mount.pki_engine]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment