Last active
February 14, 2024 05:53
-
-
Save thedude42/c1dee706328a826b96e625e4aefca81d to your computer and use it in GitHub Desktop.
Steps to establish the trust chain for Hashicorp's Vault, including storing the self-signed ROOT on a yubikey in a PIV slot
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
############################################################################### | |
############################################################################### | |
## | |
## Bootstrap a Vault PKI with an offline Root CA | |
## | |
## This document outlines the required steps to establish a PKI starting | |
## with an offline, self-signed root CA. After creating the root CA the next | |
## step establishes the Vault PKI back-end configuration and generates a | |
## signing request for an intermediate CA that is then signed by the root CA. | |
## Finally after the full-chain is uploaded to Vault, we create a Vault PKI | |
## "role" and use that to generate an end-certificate signed by the Vault | |
## intermediate CA. | |
## | |
## The offline root CA is intended to be stored in a secure offline system, | |
## and in this example a Yubikey is used to generate and store the root CA | |
## private and public keys and also self-sign the root CA itself. | |
## | |
## (Optionally there are instructions for usng opensslto generate and sign the | |
## root keys if the user's main goal is just the Vault intermediate CA.) | |
ROOT_CA_PUBKEY_FILE_NAME="rootkey.pub" | |
ROOT_CA_FILE_NAME="RootCA.pem" | |
ROOT_CA_LIFETIME="3650" | |
ROOT_CA_CN='/CN=ROOT_CA/' | |
VAULT_PKI_INSTANCE="vault-pki" | |
VAULT_INTERMEDIATE_CSR_FILENAME="VaultIntermediate.csr" | |
VAULT_INTERMEDIATE_CA_FILENAME="VaultIntermediate.pem" | |
CA_FULLCHAIN="fullchainCA.pem" | |
############################################################################### | |
##### | |
## | |
## Generate Root CA for Yubikey | |
## | |
#### | |
### | |
# Generate ROOT private keys in Yubikey | |
### | |
# generate an EC pub/priv key pair on the yubikey and output the public key to local disk: | |
yubico-piv-tool \ | |
-s 9c \ | |
-a generate \ | |
-k \ | |
--pin-policy=always \ | |
--touch-policy=always \ | |
--algorithm=ECCP256 \ | |
-o ${ROOT_CA_PUBKEY_FILE_NAME} | |
# sign the public key in a certificate with subject defined by the -S option | |
# this signs with SHA256, (using --hash option fails to generate the signed cert) | |
yubico-piv-tool \ | |
-a verify-pin \ | |
-a selfsign-certificate \ | |
-s 9c \ | |
-S ${ROOT_CA_CN} \ | |
--valid-days=${ROOT_CA_LIFETIME} \ | |
-i ${ROOT_CA_PUBKEY_FILE_NAME} \ | |
-o ${ROOT_CA_FILE_NAME} | |
### | |
# Final RootCA step: import signed cert in to Yubikey | |
### | |
yubico-piv-tool \ | |
-k \ | |
-a import-certificate \ | |
-s 9c \ | |
-i ${CA_FILE_NAME} | |
############################################################################### | |
##### | |
# | |
# Create a Vault Intermediate and sign with Yubikey RootCA | |
# | |
#### | |
### | |
# Step 1. Create Vault pki backend instance | |
### | |
# first ensure an existing instance isn't running with the same name | |
vault secrets disable -tls-skip-verify ${VAULT_PKI_INSTANCE} | |
vault secrets enable -tls-skip-verify -path=${VAULT_PKI_INSTANCE} pki | |
vault secrets tune -tls-skip-verify -max-lease-ttl=43800h ${VAULT_PKI_INSTANCE} | |
### | |
# Step 2. Request CSR for intermediate CA and sign using openssl pkcs11 engine | |
# | |
# Note: this is the first step for issuing a new Intermediate CA, i.e. no need to start over from scratch when | |
# the Intermediate CA expires | |
# | |
### | |
vault write -tls-skip-verify \ | |
-format=json \ | |
${VAULT_PKI_INSTANCE}/intermediate/generate/internal \ | |
common_name="dude.home Vault Intermediate CA" | \ | |
jq -r '.data.csr' \ | |
> "${VAULT_INTERMEDIATE_CSR_FILENAME}" | |
# this command should just work, but the tricky bits are: | |
# - MUST have a recent version of no-kidding openssl (libre won't work) | |
# - opensc installed (used homebrew on macos) | |
# - need the pkcs11 library linked in the path openssl is looking: library /usr/local/lib/pkcs11.dylib | |
# - this is because it doesn't seem loading the path from the -extfile config option works. | |
# | |
# This comes from https://github.com/OpenSC/libp11: | |
# | |
# Ensure this line is near the top of the global openssl config: | |
# | |
# openssl_conf = openssl_init | |
# | |
# | |
# The following will configure the pkcs11 engine with opensc and libp11 | |
# | |
# ( This section probably already exists in the global openssl.cfg with something in it, just add the pkcs11 part) | |
# [openssl_init] | |
# engines=engine_section | |
# [engine_section] | |
# pkcs11 = pkcs11_section | |
# [pkcs11_section] | |
# engine_id = pkcs11 | |
# # the following paths worked for macos on apple silicon | |
# dynamic_path = /opt/homebrew//lib/engines-3/pkcs11.dylib | |
# MODULE_PATH = /opt/homebrew//lib/opensc-pkcs11.so | |
# init = 0 | |
# | |
openssl x509 \ | |
-engine pkcs11 \ | |
-CAkeyform engine \ | |
-CAkey slot_0-id_2 \ # this key slot corresponds to slot 9c from the yubico piv tool | |
-sha512 \ | |
-CA ${ROOT_CA_FILE_NAME} \ | |
-req \ | |
-extensions v3 \ | |
-extfile intermediate_ca.conf \ # this file needs to include the section [ v3 ] | |
-days 1460 \ | |
-in ${VAULT_INTERMEDIATE_CSR_FILENAME} \ | |
-out ${VAULT_INTERMEDIATE_CA_FILENAME} | |
# create full CA chain and push it to the Vault intermediate CA setter endpoint | |
cat ${VAULT_INTERMEDIATE_CA_FILENAME} ${ROOT_CA_FILE_NAME} > ${CA_FULLCHAIN} | |
vault write -tls-skip-verify dudehome-pki/intermediate/set-signed certificate=@${CA_FULLCHAIN} | |
############################################################################### | |
##### | |
# | |
# Example: Create an end-server pki role for the Hashicorp Vault service with consul service discovery and issue a cert/key pair | |
# | |
#### | |
vault write -tls-skip-verify dudehome-pki/roles/vault-server \ | |
allowed_domains=vault.service.consul,dockerpi.dude.home,noisydude.dude.home \ | |
allow_subdomains=false \ | |
allow_bare_domains=true \ | |
allow_ip_sans=true \ | |
allow_localhost=true \ | |
organization=dude.home \ | |
country=US \ | |
locality=Seattle \ | |
province=Washington \ | |
key_type=ec \ | |
key_bits=256 \ | |
server_flag=true \ | |
allowed_uri_sans=https://noidsydude.dude.home:8200/*,https://dockerpi.dude.home:8200/* \ | |
max_ttl="4320h" | |
vault write -tls-skip-verify dudehome-pki/issue/vault-server \ | |
common_name=vault.service.consul \ | |
alt_names=noisydude.dude.home,dockerpi.dude.home \ | |
ip_sans=192.168.42.5,192.168.42.3,127.0.0.1 | |
$ vault write -tls-skip-verify dudehome-pki/issue/vault-server common_name=vault.service.consul alt_names=noisydude.dude.home,dockerpi.dude.home ip_sans=192.168.42.5,192.168.42.3,127.0.0.1 | |
Key Value | |
--- ----- | |
ca_chain [-----BEGIN CERTIFICATE----- | |
MIICZjCCAg2gAwIBAgIBAjAKBggqhkjOPQQDBDAdMRswGQYDVQQDDBJkdWRleXVi | |
aTVuZmNSb290Q0EwHhcNMjIwMzI3MTc1MTI2WhcNMjQwMzI2MTc1MTI2WjAqMSgw | |
JgYDVQQDEx9kdWRlLmhvbWUgVmF1bHQgSW50ZXJtZWRpYXRlIENBMIIBIjANBgkq | |
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzbyK6gK+lcx5H9b6eERgQTFe0yAEsDiz | |
PMJP5u4BetmhkI8EED8SxD2E4atXHZnpRS6+aHRQ05ma304z19powMYDYt/xovCa | |
oYNvYCreArkrIxGCuTuKItLWLdkXoybbZGcBc9NjBeGZ+A2L72siB91NW94FtSPJ | |
41MA6wFI+/Hk0q9Gm1OzJRQy4PLfNEAytPa5cSIvAby/V9j//LA4/meoDMga717m | |
tjN42cdqfyWXOp+U1QeVeguprPS5Jy6PyDhGUALXa4hErsp56vvfdCB4FHZe7KTI | |
aB8GXmLhyZlJNaLlnl8/J5lWWEWyXNUHjEgntA7Iv+yqD0Evf5BZfQIDAQABo2Yw | |
ZDASBgNVHRMBAf8ECDAGAQH/AgEBMA4GA1UdDwEB/wQEAwICBDAdBgNVHQ4EFgQU | |
myXN2kS1a3FRSg36Q1CFVJ9r2mUwHwYDVR0jBBgwFoAUA2mKuvD8oJP9CkvWDhxO | |
QvP4SKcwCgYIKoZIzj0EAwQDRwAwRAIgEOlJ/MS3FRbRy06iREbmjvmpFe/LfQeY | |
4ObD4pPGpkgCIEuaS8OF2a427hrmjxMkoKG3htZomPveZ0kj9/1ZWQrl | |
-----END CERTIFICATE----- -----BEGIN CERTIFICATE----- | |
MIIBhDCCASqgAwIBAgIJAPLhQiSwP1LbMAoGCCqGSM49BAMCMB0xGzAZBgNVBAMM | |
EmR1ZGV5dWJpNW5mY1Jvb3RDQTAeFw0yMjAzMjYxNzI3MDZaFw0zMjAzMjYxNzI3 | |
MDZaMB0xGzAZBgNVBAMMEmR1ZGV5dWJpNW5mY1Jvb3RDQTBZMBMGByqGSM49AgEG | |
CCqGSM49AwEHA0IABBouIWr2wMt96EJDN5/75NrlBE598Y/xvsyRmRpsKNEj8yvF | |
AqTyx3qjEiknizNK6SbITc4Yox3tFdSfAtLbbGCjUzBRMB0GA1UdDgQWBBQDaYq6 | |
8Pygk/0KS9YOHE5C8/hIpzAfBgNVHSMEGDAWgBQDaYq68Pygk/0KS9YOHE5C8/hI | |
pzAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0gAMEUCIQDZ0K0CasVswtux | |
g43hmIi1uGT7tyHSvTVLmbNjRpYtGwIgaVya5GSfUt6FX3LN/ql3BD8Y9CSUchW1 | |
C2ERgomqYCE= | |
-----END CERTIFICATE-----] | |
certificate -----BEGIN CERTIFICATE----- | |
MIIDIzCCAgugAwIBAgIUFEqqeM96NunzAbbDhl9QCYhHiCAwDQYJKoZIhvcNAQEL | |
BQAwKjEoMCYGA1UEAxMfZHVkZS5ob21lIFZhdWx0IEludGVybWVkaWF0ZSBDQTAe | |
Fw0yMjAzMjcxODAxNDFaFw0yMjA0MjgxODAyMTFaMGcxCzAJBgNVBAYTAlVTMRMw | |
EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdTZWF0dGxlMRIwEAYDVQQKEwlk | |
dWRlLmhvbWUxHTAbBgNVBAMTFHZhdWx0LnNlcnZpY2UuY29uc3VsMFkwEwYHKoZI | |
zj0CAQYIKoZIzj0DAQcDQgAEhvS9iK0q5EQqHakbErWq1q75njOMg79JZi5xJ5xF | |
QFHmMwyCXDZCckaPBnYkVEivD/SPNy66S/TWcYXxgL9FFKOBzjCByzAOBgNVHQ8B | |
Af8EBAMCA6gwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQW | |
BBS/onEZQgk7M715IuCu/koLY5JFZjAfBgNVHSMEGDAWgBSbJc3aRLVrcVFKDfpD | |
UIVUn2vaZTBaBgNVHREEUzBRghJkb2NrZXJwaS5kdWRlLmhvbWWCE25vaXN5ZHVk | |
ZS5kdWRlLmhvbWWCFHZhdWx0LnNlcnZpY2UuY29uc3VshwTAqCoFhwTAqCoDhwR/ | |
AAABMA0GCSqGSIb3DQEBCwUAA4IBAQAMYZ+7KcjZUgtIJeeP+SHsPatNe1QGCddJ | |
RAd+0VWMks3BulEtQ4dzdbFNHZe5m/OGbjcy6lqc2aKJxUq3ZUMC++gw/4extrn6 | |
7fpSR7CeyfAw4L0WjCpYwk19hgnEOhLJHyOHRbWdUd3x+C8IDCkhhpA9Zvq5/r8U | |
DExWs4EQXXt1gstvl6d99dRoT9E4nyazKvX0p5id7a6leKhYla3W0pw1f6qM6PTF | |
q78hfwhZPTZCwoRh/A/Y1xl8Krl0Cc9fHge1E9v7T3evc6Eb3SZ0REBFGKXIRXuv | |
Qgo+w8PQMxtQNqskWxv9R+SC60La9Kt01A1AQBDVDgk23rkIYmvR | |
-----END CERTIFICATE----- | |
expiration 1651168931 | |
issuing_ca -----BEGIN CERTIFICATE----- | |
MIICZjCCAg2gAwIBAgIBAjAKBggqhkjOPQQDBDAdMRswGQYDVQQDDBJkdWRleXVi | |
aTVuZmNSb290Q0EwHhcNMjIwMzI3MTc1MTI2WhcNMjQwMzI2MTc1MTI2WjAqMSgw | |
JgYDVQQDEx9kdWRlLmhvbWUgVmF1bHQgSW50ZXJtZWRpYXRlIENBMIIBIjANBgkq | |
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzbyK6gK+lcx5H9b6eERgQTFe0yAEsDiz | |
PMJP5u4BetmhkI8EED8SxD2E4atXHZnpRS6+aHRQ05ma304z19powMYDYt/xovCa | |
oYNvYCreArkrIxGCuTuKItLWLdkXoybbZGcBc9NjBeGZ+A2L72siB91NW94FtSPJ | |
41MA6wFI+/Hk0q9Gm1OzJRQy4PLfNEAytPa5cSIvAby/V9j//LA4/meoDMga717m | |
tjN42cdqfyWXOp+U1QeVeguprPS5Jy6PyDhGUALXa4hErsp56vvfdCB4FHZe7KTI | |
aB8GXmLhyZlJNaLlnl8/J5lWWEWyXNUHjEgntA7Iv+yqD0Evf5BZfQIDAQABo2Yw | |
ZDASBgNVHRMBAf8ECDAGAQH/AgEBMA4GA1UdDwEB/wQEAwICBDAdBgNVHQ4EFgQU | |
myXN2kS1a3FRSg36Q1CFVJ9r2mUwHwYDVR0jBBgwFoAUA2mKuvD8oJP9CkvWDhxO | |
QvP4SKcwCgYIKoZIzj0EAwQDRwAwRAIgEOlJ/MS3FRbRy06iREbmjvmpFe/LfQeY | |
4ObD4pPGpkgCIEuaS8OF2a427hrmjxMkoKG3htZomPveZ0kj9/1ZWQrl | |
-----END CERTIFICATE----- | |
private_key -----BEGIN EC PRIVATE KEY----- | |
MHcCAQEEIIbRNmWDjrCHBP1HKf85dgIct1kJJZJroOW3Zh5PTfbjoAoGCCqGSM49 | |
AwEHoUQDQgAEhvS9iK0q5EQqHakbErWq1q75njOMg79JZi5xJ5xFQFHmMwyCXDZC | |
ckaPBnYkVEivD/SPNy66S/TWcYXxgL9FFA== | |
-----END EC PRIVATE KEY----- | |
private_key_type ec | |
serial_number 14:4a:aa:78:cf:7a:36:e9:f3:01:b6:c3:86:5f:50:09:88:47:88:20 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment