diff --git a/services/vault/default.nix b/services/vault/default.nix index 36d2101..33b9aa5 100644 --- a/services/vault/default.nix +++ b/services/vault/default.nix @@ -77,8 +77,85 @@ 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 + echo "Issuing certificate for vault01.home.2rjus.net..." + OUTPUT=$(bao write -format=json pki_int/issue/homelab \ + common_name="vault01.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 "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 +178,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,11 +187,14 @@ in ]; # Auto-unseal on service start ExecStartPost = "${unsealScript}/bin/openbao-unseal"; + # Add openbao user to acme group to read certificates + SupplementaryGroups = [ "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" ]; }; }