PKI

Tworzenie PKI w organizacji

PKI (Public Key Infrastructure) to infrastruktura klucza publicznego – zestaw technologii, zasad i komponentów, które umożliwiają bezpieczną komunikację, uwierzytelnianie i szyfrowanie w systemach informatycznych.


Utworzenie drzewa certyfikatów Root CA i Intermediate CA

stateDiagram
  direction TB
  classDef Sky stroke-width:1px,stroke-dasharray:none,stroke:#374D7C,fill:#E2EBFF,color:#374D7C;
  classDef Peach stroke-width:1px,stroke-dasharray:none,stroke:#FBB35A,fill:#FFEFDB,color:#8F632D;
  [*] --> s1
  s1 --> s2
  s1 --> s5
  s1:Root CA
s1:*.rachuna-net.pl

  s2:Infrastructure Intermediate CA
s2:Certyfikaty Infrastruktury

  [*]
  s5:Apps Intermediate CA
s5:Certyfikaty Aplikacji

  class s5 Peach
module "vault_pki" {
  source = "git@gitlab.rachuna-net.pl:pl.rachuna-net/infrastructure/opentofu/modules/vault-pki.git?ref=v1.0.0"

  root_domain      = "rachuna-net.pl"
  root_common_name = "rachuna-net.pl ROOT CA"
  pki_urls_base    = "https://ct01101.rachuna-net.pl:8200/"

  intermediates = {
    infrastructure = {
      path        = "pki-infrastructure"
      common_name = "rachuna-net.pl Infrastructure Intermediate CA"
      role_name   = "infrastructure-default"
    }
    apps = {
      path        = "pki-apps"
      common_name = "rachuna-net.pl Apps Intermediate CA"
      role_name   = "apps-default"
    }
  }

}

Przykładowe rozwiązanie reprezentuje certyfikat główny ROOT CA oraz certyfikaty pośredniczące nfrastructure Intermediate CA dedykowany dla infrastruktury oraz Apps Intermediate CA


Wygenerowanie certyfikatu końcowego

  1. Generowanie certyfikaty końcowe (leaf) dla konkretnych usług:

    • gitlab.rachuna-net.pl
    • consul.rachuna-net.pl
    • vault.rachuna-net.pl
    • docs.rachuna-net.pl
module "vault_pki" {
  source = "git@gitlab.rachuna-net.pl:pl.rachuna-net/infrastructure/opentofu/modules/vault-pki.git?ref=v1.0.0"

  root_domain   = "rachuna-net.pl"
  pki_urls_base = "https://ct01101.rachuna-net.pl:8200/"

  intermediates = {
    infrastructure = {
      path        = "pki-infrastructure"
      common_name = "Infrastructure Intermediate CA"
      role_name   = "infrastructure-default"
    }
    apps = {
      path        = "pki-apps"
      common_name = "Apps Intermediate CA"
      role_name   = "apps-default"
    }
  }

  leaf_requests = {
    "infra-gitlab" = {
      backend_key = "infrastructure"
      common_name = "gitlab.rachuna-net.pl"
      alt_names = [
        "registry.rachuna-net.pl"
      ]
    }
    "infra-consul" = {
      backend_key = "infrastructure"
      common_name = "consul.rachuna-net.pl"
      alt_names = [
        "ct01101.rachuna-net.pl",
        "ct01102.rachuna-net.pl",
        "ct01103.rachuna-net.pl",
      ]
    }
    "infra-vault" = {
      backend_key = "infrastructure"
      common_name = "vault.rachuna-net.pl"
      alt_names = [
        "ct01101.rachuna-net.pl",
        "ct01102.rachuna-net.pl",
        "ct01103.rachuna-net.pl",
      ]
    }
    "apps-docs" = {
      backend_key = "apps"
      common_name = "docs.rachuna-net.pl"
    }
  }
}

Kluczowe parametry:

  • root_domain = "rachuna-net.pl" Root CA będzie wystawiony dla tej domeny, np. Rachuna-Net Root CA.

  • pki_urls_base = "https://ct01101.rachuna-net.pl:8200/" Baza do ustawienia:

    • issuing_certificates
    • crl_distribution_points
    • ocsp_servers czyli gdzie klienci mają się zgłaszać po CRL / certyfikaty.
  • intermediates – definicja CA pośrednich (mapa):

    • klucz (infrastructure, apps) to alias używany dalej w module,
    • path – mount w Vault, np. pki-infrastructure,
    • common_name – CN tego CA,
    • role_name – domyślna rola w tym backendzie (do wystawiania leafów).
  • leaf_requestslista certyfikatów końcowych do wygenerowania:

    • klucz mapy (infra-gitlab, infra-consul…) to tylko nazwa logiczna w module,
    • backend_key – mówi, z którego intermediate CA korzystać (infrastructure / apps),
    • common_name – CN certyfikatu (zazwyczaj FQDN usługi),
    • alt_names – Subject Alternative Names (SAN) – dodatkowe nazwy DNS w certyfikacie.

Pobieranie certyfikatu

Zależy, jak moduł jest napisany, ale typowo:

  • Zapisane są certyfikaty w kv (np. kv-certificates/leaf/grafana),
{
  "alt_names": [],
  "backend_key": "apps",
  "ca_chain": "-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----",
  "certificate": "-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----",
  "common_name": "test.rachuna-net.pl",
  "issuing_ca": "-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----",
  "private_key": "-----BEGIN RSA PRIVATE KEY-----\n-----END RSA PRIVATE KEY-----",
  "serial_number": "42:b5:19:73:cd:f9:70:0c:30:81:93:fb:b5:56:a1:7e:f9:25:6a:23"
}
  • bezpośrednio do pobrania z pki
RESP=$(curl \
  --header "X-Vault-Token: $VAULT_TOKEN" \
  --request POST \
  --data '{"common_name": "grafana.rachuna-net.pl"}' \
  https://ct01005.rachuna-net.pl:8200/v1/pki-apps/issue/apps-default)

echo "$RESP" | jq -r '.data.certificate'  > grafana.crt
echo "$RESP" | jq -r '.data.private_key'  > grafana.key
echo "$RESP" | jq -r '.data.issuing_ca'   > grafana.chain.crt

Proponowany podział PKI?

Z poziomu dev/DevOps masz bardzo prosty mentalny model:

  • Root CA – trzymasz w Vault, ale używasz tylko do podpisywania intermediates.

  • Intermediate CA – logiczny podział według typu systemów:

    • infrastructure: Proxmox, Consul, Vault, GitLab, routery, load balancery.
    • apps: aplikacje biznesowe, frontend, API.
    • (opcjonalnie) dmz, internal, storage, kubernetes itd.
  • Leaf certyfikaty – dla konkretnych hostów/usług.

I wszystko opisujesz w dwóch mapach: intermediates i leaf_requests.


Przykłady rozbudowania PKI

Kilka konkretnych trików:

  1. Osobny intermediate dla Kubernetes:

    intermediates = {
      # ...
      kubernetes = {
        path        = "pki-k8s"
        common_name = "Kubernetes Intermediate CA"
        role_name   = "k8s-default"
      }
    }
    
  2. Cert dla Ingress Controller:

    leaf_requests = {
      "k8s-ingress" = {
        backend_key = "kubernetes"
        common_name = "ingress.rachuna-net.pl"
        alt_names = [
          "*.apps.rachuna-net.pl",
        ]
      }
    }
    

Użycie ACME

Ten blok możesz podmienić w sekcji „Utworzenie drzewa certyfikatów Root CA i Intermediate CA” (stary przykład z ref=v1.0.0 → nowy z ref=v1.1.0 + ACME):

module "vault_pki" {
  source = "git@gitlab.rachuna-net.pl:pl.rachuna-net/infrastructure/opentofu/modules/vault-pki.git?ref=v1.1.0"

  root_domain      = "rachuna-net.pl"
  root_common_name = "rachuna-net.pl ROOT CA"
  pki_urls_base    = "https://ct01005.rachuna-net.pl:8200"

  intermediates = {
    infrastructure = {
      path        = "pki-infrastructure"
      common_name = "rachuna-net.pl Infrastructure Intermediate CA"
      role_name   = "infrastructure-default"

      # klasyczne parametry PKI
      ttl     = "26280h"
      max_ttl = "26280h"

      # konfiguracja ACME dla infrastruktury
      acme = {
        acme_enabled                = true
        acme_cluster_path           = "https://ct01005.rachuna-net.pl"
        allow_wildcard_certificates = true
        max_ttl                     = "168h"
      }

      # (opcjonalnie) aliasy/parametry dla zachowania wstecznej kompatybilności modułu
      acme_enabled      = true
      acme_cluster_path = "https://ct01005.rachuna-net.pl"
    }

    apps = {
      path        = "pki-apps"
      common_name = "rachuna-net.pl Apps Intermediate CA"
      role_name   = "apps-default"

      # zezwalamy na wildcardy z tego backendu
      allow_wildcard_certificates = true

      # klasyczne parametry PKI
      ttl     = "26h"
      max_ttl = "26h"

      # konfiguracja ACME dla aplikacji
      acme = {
        acme_enabled      = true
        acme_cluster_path = "https://ct01005.rachuna-net.pl"
        max_ttl           = "25h"
      }
    }
  }
}
Last modified December 19, 2025: docs: Update (72bba37)