Skip to content

Instantly share code, notes, and snippets.

@thedude42
Last active February 14, 2024 05:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thedude42/c1dee706328a826b96e625e4aefca81d to your computer and use it in GitHub Desktop.
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
###############################################################################
###############################################################################
##
## 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