Inhaltsverzeichnis

Kubernetes Cert-Manager

Complessità: Alta
Durata: 2-3 ore di configurazione
Prerequisito: Kubernetes 1.25+, Helm

Gestione automatica dei certificati in Kubernetes con cert-manager e PKI propria.


Architettura

flowchart TB subgraph K8S["☸️ CLUSTER KUBERNETES"] subgraph CM["cert-manager"] I[Issuer/ClusterIssuer] C[Certificate] CR[CertificateRequest] end subgraph APP["Applicazione"] P[Pod] S[Secret] ING[Ingress] end C --> CR --> I I --> S S --> P S --> ING end subgraph EXTERNAL["🔐 CA ESTERNA"] CA[CA Interna] V[Vault PKI] LE[Let's Encrypt] end I --> CA I --> V I --> LE style CM fill:#e3f2fd style I fill:#fff3e0


Installazione

# Aggiunta repository Helm
helm repo add jetstack https://charts.jetstack.io
helm repo update
 
# Installazione cert-manager
helm install cert-manager jetstack/cert-manager \
    --namespace cert-manager \
    --create-namespace \
    --set installCRDs=true \
    --set prometheus.enabled=true
 
# Verifica installazione
kubectl get pods -n cert-manager

Tipi di Issuer

Tipo Issuer Caso d'uso Supporto PQ
————-————————-
SelfSigned Testing, Bootstrapping No
CA PKI interna Sì (con WvdS)
Vault HashiCorp Vault PKI Parziale
ACME Let's Encrypt, CA pubbliche No
Venafi PKI Enterprise Parziale

ClusterIssuer con CA propria

Passo 1: Creazione Secret CA

# Certificato e chiave CA come Secret
kubectl create secret tls ca-key-pair \
    --cert=intermediate-ca.pem \
    --key=intermediate-ca.key \
    --namespace cert-manager

Oppure come YAML:

# ca-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: ca-key-pair
  namespace: cert-manager
type: kubernetes.io/tls
data:
  tls.crt: <base64-encoded-ca-cert>
  tls.key: <base64-encoded-ca-key>

Passo 2: Definizione ClusterIssuer

# cluster-issuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: internal-ca-issuer
spec:
  ca:
    secretName: ca-key-pair
kubectl apply -f cluster-issuer.yaml
 
# Verifica stato
kubectl get clusterissuer internal-ca-issuer

Risorsa Certificate

# certificate.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: app-tls
  namespace: production
spec:
  # Secret che verrà creato
  secretName: app-tls-secret
 
  # Durata di validità
  duration: 2160h    # 90 giorni
  renewBefore: 360h  # Rinnovo 15 giorni prima della scadenza
 
  # Subject
  subject:
    organizations:
      - EMSR DATA
  commonName: app.example.com
 
  # Configurazione chiave
  privateKey:
    algorithm: ECDSA
    size: 384
    rotationPolicy: Always
 
  # Scopo di utilizzo
  usages:
    - server auth
    - client auth
 
  # DNS/IP SAN
  dnsNames:
    - app.example.com
    - app.production.svc.cluster.local
  ipAddresses:
    - 10.0.0.100
 
  # Riferimento Issuer
  issuerRef:
    name: internal-ca-issuer
    kind: ClusterIssuer
kubectl apply -f certificate.yaml
 
# Verifica stato
kubectl get certificate -n production
kubectl describe certificate app-tls -n production
 
# Visualizza Secret
kubectl get secret app-tls-secret -n production -o yaml

Annotazione Ingress (automatico)

# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress
  namespace: production
  annotations:
    # cert-manager crea automaticamente il certificato
    cert-manager.io/cluster-issuer: "internal-ca-issuer"
spec:
  tls:
    - hosts:
        - app.example.com
      secretName: app-ingress-tls
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: app-service
                port:
                  number: 80

Integrazione Vault PKI

# vault-issuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: vault-issuer
spec:
  vault:
    server: https://vault.example.com
    path: pki/sign/server-role
    caBundle: <base64-encoded-vault-ca>
    auth:
      kubernetes:
        role: cert-manager
        mountPath: /v1/auth/kubernetes
        secretRef:
          name: vault-token
          key: token

Configurazione Vault:

# Attivazione PKI Engine
vault secrets enable pki
vault secrets tune -max-lease-ttl=87600h pki
 
# Generazione Root-CA (o importazione)
vault write pki/root/generate/internal \
    common_name="Internal Root CA" \
    ttl=87600h
 
# Ruolo per cert-manager
vault write pki/roles/server-role \
    allowed_domains="example.com,svc.cluster.local" \
    allow_subdomains=true \
    max_ttl=720h
 
# Auth Kubernetes
vault auth enable kubernetes
vault write auth/kubernetes/config \
    kubernetes_host="https://kubernetes.default.svc"

Monitoraggio

Metriche Prometheus

# ServiceMonitor per cert-manager
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: cert-manager
  namespace: monitoring
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: cert-manager
  endpoints:
    - port: http-metrics

Metriche importanti:

Metrica Descrizione Soglia alert
———————-————–
certmanager_certificate_expiration_timestamp_seconds Timestamp scadenza < 7 giorni
certmanager_certificate_ready_status Stato Ready != 1
certmanager_certificate_renewal_timestamp_seconds Ultimo rinnovo -

Regole Alert

# PrometheusRule
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: cert-manager-alerts
  namespace: monitoring
spec:
  groups:
    - name: cert-manager
      rules:
        - alert: CertificateExpiringSoon
          expr: |
            certmanager_certificate_expiration_timestamp_seconds - time() < 604800
          for: 1h
          labels:
            severity: warning
          annotations:
            summary: "Certificato {{ $labels.name }} scade in < 7 giorni"

        - alert: CertificateNotReady
          expr: |
            certmanager_certificate_ready_status != 1
          for: 10m
          labels:
            severity: critical
          annotations:
            summary: "Certificato {{ $labels.name }} non pronto"

Risoluzione problemi

# Stato Certificate
kubectl get certificate -A
kubectl describe certificate <name> -n <namespace>
 
# Verifica CertificateRequest
kubectl get certificaterequest -A
kubectl describe certificaterequest <name>
 
# Log cert-manager
kubectl logs -n cert-manager -l app=cert-manager -f
 
# Eventi
kubectl get events -n cert-manager --sort-by='.lastTimestamp'

Problemi comuni:

Problema Causa Soluzione
———-——-———–
Issuer not found ClusterIssuer vs. Issuer Verificare Kind
Secret not found Secret CA non creato Creare Secret
Failed to generate CSR Algoritmo chiave Verificare Algorithm/Size
Challenge failed Problema ACME Verificare DNS/HTTP Challenge

Post-Quantum con CA propria

Certificati PQ con cert-manager:

Cert-manager stesso non supporta algoritmi PQ, ma è possibile utilizzare una CA abilitata PQ e creare i certificati manualmente.

// Creazione Secret Kubernetes con certificato PQ
using var intermediate = new X509Certificate2("intermediate.pfx", "password");
 
// Caricamento CSR da Kubernetes
var csr = CertificateRequest.LoadSigningRequest(csrBytes, HashAlgorithmName.SHA384);
 
// Emissione certificato PQ-Hybrid
var cert = csr.Create(
    intermediate,
    DateTimeOffset.UtcNow,
    DateTimeOffset.UtcNow.AddDays(90),
    Guid.NewGuid().ToByteArray(),
    CryptoMode.Hybrid);
 
// Salvataggio come Secret Kubernetes
var secret = new V1Secret
{
    Metadata = new V1ObjectMeta { Name = "pq-tls-secret" },
    Type = "kubernetes.io/tls",
    Data = new Dictionary<string, byte[]>
    {
        ["tls.crt"] = Encoding.UTF8.GetBytes(cert.ExportCertificatePem()),
        ["tls.key"] = Encoding.UTF8.GetBytes(cert.GetECDsaPrivateKey().ExportPkcs8PrivateKeyPem())
    }
};

Checklist

# Punto di verifica
——————-
1 cert-manager installato
2 ClusterIssuer configurato
3 Secret CA creato
4 Certificate di test funzionante
5 Monitoraggio Prometheus attivo
6 Alert configurati

Documentazione correlata


« ← Code-Signing CI/CD | → Rinnovo schedulato »


Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional