pki-migration #12
@@ -105,6 +105,17 @@
|
||||
};
|
||||
};
|
||||
|
||||
# Test ACME certificate issuance from OpenBao PKI
|
||||
# Override the global ACME server (from system/acme.nix) to use OpenBao instead of step-ca
|
||||
security.acme.defaults.server = lib.mkForce "https://vault01.home.2rjus.net:8200/v1/pki_int/acme/directory";
|
||||
|
||||
# Request a certificate for this host
|
||||
# Using HTTP-01 challenge with standalone listener on port 80
|
||||
security.acme.certs."vaulttest01.home.2rjus.net" = {
|
||||
listenHTTP = ":80";
|
||||
enableDebugLogs = true;
|
||||
};
|
||||
|
||||
system.stateVersion = "25.11"; # Did you read the comment?
|
||||
}
|
||||
|
||||
|
||||
@@ -77,8 +77,89 @@ let
|
||||
fi
|
||||
'';
|
||||
};
|
||||
|
||||
bootstrapCertScript = pkgs.writeShellApplication {
|
||||
name = "bootstrap-vault-cert";
|
||||
runtimeInputs = with pkgs; [
|
||||
openbao
|
||||
jq
|
||||
openssl
|
||||
coreutils
|
||||
];
|
||||
text = ''
|
||||
# Bootstrap vault01 with a proper certificate from its own PKI
|
||||
# This solves the chicken-and-egg problem where ACME clients can't trust
|
||||
# vault01's self-signed certificate.
|
||||
|
||||
echo "=== Bootstrapping vault01 certificate ==="
|
||||
|
||||
# Use Unix socket to avoid TLS issues
|
||||
export BAO_ADDR='unix:///run/openbao/openbao.sock'
|
||||
|
||||
# ACME certificate directory
|
||||
CERT_DIR="/var/lib/acme/vault01.home.2rjus.net"
|
||||
|
||||
# Issue certificate for vault01 with vault as SAN
|
||||
echo "Issuing certificate for vault01.home.2rjus.net (with SAN: vault.home.2rjus.net)..."
|
||||
OUTPUT=$(bao write -format=json pki_int/issue/homelab \
|
||||
common_name="vault01.home.2rjus.net" \
|
||||
alt_names="vault.home.2rjus.net" \
|
||||
ttl="720h")
|
||||
|
||||
# Create ACME directory structure
|
||||
echo "Creating ACME certificate directory..."
|
||||
mkdir -p "$CERT_DIR"
|
||||
|
||||
# Extract certificate components to temp files
|
||||
echo "$OUTPUT" | jq -r '.data.certificate' > /tmp/vault01-cert.pem
|
||||
echo "$OUTPUT" | jq -r '.data.private_key' > /tmp/vault01-key.pem
|
||||
echo "$OUTPUT" | jq -r '.data.issuing_ca' > /tmp/vault01-ca.pem
|
||||
|
||||
# Create fullchain (cert + CA)
|
||||
cat /tmp/vault01-cert.pem /tmp/vault01-ca.pem > /tmp/vault01-fullchain.pem
|
||||
|
||||
# Backup old certificates if they exist
|
||||
if [ -f "$CERT_DIR/fullchain.pem" ]; then
|
||||
echo "Backing up old certificate..."
|
||||
cp "$CERT_DIR/fullchain.pem" "$CERT_DIR/fullchain.pem.backup"
|
||||
cp "$CERT_DIR/key.pem" "$CERT_DIR/key.pem.backup"
|
||||
fi
|
||||
|
||||
# Install new certificates
|
||||
echo "Installing new certificate..."
|
||||
mv /tmp/vault01-fullchain.pem "$CERT_DIR/fullchain.pem"
|
||||
mv /tmp/vault01-cert.pem "$CERT_DIR/cert.pem"
|
||||
mv /tmp/vault01-ca.pem "$CERT_DIR/chain.pem"
|
||||
mv /tmp/vault01-key.pem "$CERT_DIR/key.pem"
|
||||
|
||||
# Set proper ownership and permissions (ACME-style)
|
||||
chown -R acme:acme "$CERT_DIR"
|
||||
chmod 750 "$CERT_DIR"
|
||||
chmod 640 "$CERT_DIR"/*.pem
|
||||
|
||||
echo "Certificate installed successfully!"
|
||||
echo ""
|
||||
echo "Certificate details:"
|
||||
openssl x509 -in "$CERT_DIR/cert.pem" -noout -subject -issuer -dates
|
||||
echo ""
|
||||
echo "Subject Alternative Names:"
|
||||
openssl x509 -in "$CERT_DIR/cert.pem" -noout -ext subjectAltName
|
||||
|
||||
echo ""
|
||||
echo "Now restart openbao service:"
|
||||
echo " systemctl restart openbao"
|
||||
echo ""
|
||||
echo "After restart, verify ACME endpoint is accessible:"
|
||||
echo " curl https://vault01.home.2rjus.net:8200/v1/pki_int/acme/directory"
|
||||
echo ""
|
||||
echo "Once working, ACME will automatically manage certificate renewals."
|
||||
'';
|
||||
};
|
||||
in
|
||||
{
|
||||
# Make bootstrap script available as a command
|
||||
environment.systemPackages = [ bootstrapCertScript ];
|
||||
|
||||
services.openbao = {
|
||||
enable = true;
|
||||
|
||||
@@ -101,8 +182,8 @@ in
|
||||
|
||||
systemd.services.openbao.serviceConfig = {
|
||||
LoadCredential = [
|
||||
"key.pem:/var/lib/openbao/key.pem"
|
||||
"cert.pem:/var/lib/openbao/cert.pem"
|
||||
"key.pem:/var/lib/acme/vault01.home.2rjus.net/key.pem"
|
||||
"cert.pem:/var/lib/acme/vault01.home.2rjus.net/fullchain.pem"
|
||||
];
|
||||
# TPM2-encrypted unseal key (created manually, see setup instructions)
|
||||
LoadCredentialEncrypted = [
|
||||
@@ -110,5 +191,16 @@ in
|
||||
];
|
||||
# Auto-unseal on service start
|
||||
ExecStartPost = "${unsealScript}/bin/openbao-unseal";
|
||||
# Add openbao user to acme group to read certificates
|
||||
SupplementaryGroups = [ "acme" ];
|
||||
};
|
||||
|
||||
# ACME certificate management
|
||||
# Bootstrapped with bootstrap-vault-cert, now managed by ACME
|
||||
security.acme.certs."vault01.home.2rjus.net" = {
|
||||
server = "https://vault01.home.2rjus.net:8200/v1/pki_int/acme/directory";
|
||||
listenHTTP = ":80";
|
||||
reloadServices = [ "openbao" ];
|
||||
extraDomainNames = [ "vault.home.2rjus.net" ];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
./packages.nix
|
||||
./nix.nix
|
||||
./root-user.nix
|
||||
./root-ca.nix
|
||||
./pki/root-ca.nix
|
||||
./sops.nix
|
||||
./sshd.nix
|
||||
./vault-secrets.nix
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
certificateFiles = [
|
||||
"${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"
|
||||
./root-ca.crt
|
||||
./vault-root-ca.crt
|
||||
];
|
||||
};
|
||||
}
|
||||
14
system/pki/vault-root-ca.crt
Normal file
14
system/pki/vault-root-ca.crt
Normal file
@@ -0,0 +1,14 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICIjCCAaigAwIBAgIUQ/Bd/4kNvkPjQjgGLUMynIVzGeAwCgYIKoZIzj0EAwMw
|
||||
QDELMAkGA1UEBhMCTk8xEDAOBgNVBAoTB0hvbWVsYWIxHzAdBgNVBAMTFmhvbWUu
|
||||
MnJqdXMubmV0IFJvb3QgQ0EwHhcNMjYwMjAxMjIxODA5WhcNMzYwMTMwMjIxODM5
|
||||
WjBAMQswCQYDVQQGEwJOTzEQMA4GA1UEChMHSG9tZWxhYjEfMB0GA1UEAxMWaG9t
|
||||
ZS4ycmp1cy5uZXQgUm9vdCBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IABH8xhIOl
|
||||
Nd1Yb1OFhgIJQZM+OkwoFenOQiKfuQ4oPMxaF+fnXdKc77qPDVRjeDy61oGS38X3
|
||||
CjPOZAzS9kjo7FmVbzdqlYK7ut/OylF+8MJkCT8mFO1xvuzIXhufnyAD4aNjMGEw
|
||||
DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEimBeAg
|
||||
3JVeF4BqdC9hMZ8MYKw2MB8GA1UdIwQYMBaAFEimBeAg3JVeF4BqdC9hMZ8MYKw2
|
||||
MAoGCCqGSM49BAMDA2gAMGUCMQCvhRElHBra/XyT93SKcG6ZzIG+K+DH3J5jm6Xr
|
||||
zaGj2VtdhBRVmEKaUcjU7htgSxcCMA9qHKYFcUH72W7By763M6sy8OOiGQNDSERY
|
||||
VgnNv9rLCvCef1C8G2bYh/sKGZTPGQ==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -62,6 +62,13 @@ resource "vault_mount" "pki_int" {
|
||||
description = "Intermediate CA"
|
||||
default_lease_ttl_seconds = 157680000 # 5 years
|
||||
max_lease_ttl_seconds = 157680000 # 5 years
|
||||
|
||||
# Required for ACME support - allow ACME-specific response headers
|
||||
allowed_response_headers = [
|
||||
"Replay-Nonce",
|
||||
"Link",
|
||||
"Location"
|
||||
]
|
||||
}
|
||||
|
||||
resource "vault_pki_secret_backend_intermediate_cert_request" "intermediate" {
|
||||
@@ -139,6 +146,33 @@ resource "vault_pki_secret_backend_config_urls" "config_urls" {
|
||||
]
|
||||
}
|
||||
|
||||
# Configure cluster path (required for ACME)
|
||||
resource "vault_pki_secret_backend_config_cluster" "cluster" {
|
||||
backend = vault_mount.pki_int.path
|
||||
path = "${var.vault_address}/v1/${vault_mount.pki_int.path}"
|
||||
aia_path = "${var.vault_address}/v1/${vault_mount.pki_int.path}"
|
||||
}
|
||||
|
||||
# Enable ACME support
|
||||
resource "vault_generic_endpoint" "acme_config" {
|
||||
depends_on = [
|
||||
vault_pki_secret_backend_config_cluster.cluster,
|
||||
vault_pki_secret_backend_role.homelab
|
||||
]
|
||||
|
||||
path = "${vault_mount.pki_int.path}/config/acme"
|
||||
ignore_absent_fields = true
|
||||
disable_read = true
|
||||
disable_delete = true
|
||||
|
||||
data_json = jsonencode({
|
||||
enabled = true
|
||||
allowed_issuers = ["*"]
|
||||
allowed_roles = ["*"]
|
||||
default_directory_policy = "sign-verbatim"
|
||||
})
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Direct Certificate Issuance (Non-ACME)
|
||||
# ============================================================================
|
||||
|
||||
@@ -50,8 +50,8 @@ locals {
|
||||
cpu_cores = 2
|
||||
memory = 2048
|
||||
disk_size = "20G"
|
||||
flake_branch = "vault-bootstrap-integration"
|
||||
vault_wrapped_token = "s.HwNenAYvXBsPs8uICh4CbE11"
|
||||
flake_branch = "pki-migration"
|
||||
vault_wrapped_token = "s.UCpQCOp7cOKDdtGGBvfRWwAt"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user