An EXTREMELY INSECURE example to demonstrate using Cert based Auto Auth method with Vault Agent where client authentication (mTLS) is required to communicate with Vault Server (tls_require_and_verify_client_cert = true
).
A work-around is needed due to client_cert
and client_key
files in the vault
stanza not being reloaded from disk when sending a SIGHUP to Vault Agent. This requires killing and restarting the Vault Agent in order to load the new Client certificate.
-
Create temporary directory
$ export VAULT_RAFT_PATH="$(mktemp --tmpdir="/tmp" --directory "vault.XXXXXXXX")"
-
Start Vault with TLS disabled
$ VAULT_CONFIG=$(cat <<-CONFIG pid_file = "${VAULT_RAFT_PATH}/vault.pid" api_addr = "http://127.0.0.1:8200" cluster_addr = "https://127.0.0.1:8201" storage "raft" { node_id = "dev" } listener "unix" { address = "${VAULT_RAFT_PATH}/vault.sock" } listener "tcp" { address = "127.0.0.1:8200" tls_disable = true } CONFIG ) \ && vault server -config <(printf "${VAULT_CONFIG}") > /dev/null 2>& 1 &
-
Set environment variables
$ export VAULT_ADDR="unix:///${VAULT_RAFT_PATH}/vault.sock"
-
Initialise Vault
$ VAULT_INIT=$(vault operator init -key-shares=1 -key-threshold=1 -format=table) \ && VAULT_UNSEAL=$(printf "${VAULT_INIT}" | grep "Unseal" | awk '{print $NF; }')
-
Uneal Vault
$ vault operator unseal "${VAULT_UNSEAL}"
-
Set Vault Root Token
$ export VAULT_TOKEN=$(printf "${VAULT_INIT}" | grep "Root" | awk '{print $NF; }')
-
Create Terraform file
$ cat > "${VAULT_RAFT_PATH}/main.tf" <<CONFIG resource "vault_mount" "tls" { path = "pki_tls" type = "pki" } resource "vault_pki_secret_backend_root_cert" "tls" { backend = vault_mount.tls.path type = "internal" common_name = "Vault TLS CA" } resource "vault_pki_secret_backend_role" "tls" { backend = vault_mount.tls.path name = "tls" key_type = "ec" key_bits = 384 allow_any_name = true allow_bare_domains = true enforce_hostnames = false } resource "local_file" "tls" { content = vault_pki_secret_backend_root_cert.tls.certificate filename = "\${path.module}/tls-ca.pem" } resource "vault_mount" "client" { path = "pki_client" type = "pki" } resource "vault_pki_secret_backend_root_cert" "client" { backend = vault_mount.client.path type = "internal" common_name = "Vault Client CA" } resource "vault_pki_secret_backend_role" "client" { backend = vault_mount.client.path name = "client" key_type = "ec" key_bits = 384 allow_any_name = true allow_bare_domains = true enforce_hostnames = false } resource "local_file" "client" { content = vault_pki_secret_backend_root_cert.client.certificate filename = "\${path.module}/client-ca.pem" } resource "vault_policy" "this" { name = "sudo" policy = <<-EOT path "*" { capabilities = [ "create", "read", "update", "delete", "list", "sudo" ] } EOT } resource "vault_auth_backend" "cert" { path = "cert" type = "cert" } resource "vault_cert_auth_backend_role" "cert" { name = "vault-agent" certificate = file("${VAULT_RAFT_PATH}/client-ca.pem") backend = vault_auth_backend.cert.path allowed_common_names = ["Vault Agent"] token_ttl = 300 token_max_ttl = 600 token_policies = ["sudo"] } CONFIG
-
Apply Terraform
$ terraform -chdir="${VAULT_RAFT_PATH}" init \ && VAULT_ADDR="http://127.0.0.1:8200" \ && terraform -chdir="${VAULT_RAFT_PATH}" apply -auto-approve
-
Issue Vault TLS Certificate
$ VAULT_ISSUE_TLS=$(vault write pki_tls/issue/tls common_name="Vault TLS" ip_sans="127.0.0.1" ttl="8h") \ && printf "${VAULT_ISSUE_TLS//$'\n'/\\\n}" \ | grep -oE 'certificate {9}\-{5}BEGIN CERTIFICATE\-{5}[a-zA-Z0-9+=/\\]*\-{5}END CERTIFICATE\-{5}' \ | grep -oE '\-.*\-' | sed 's/\\n/\'$'\n''/g' \ > "${VAULT_RAFT_PATH}/cert.pem" \ && printf "${VAULT_ISSUE_TLS//$'\n'/\\\n}" \ | grep -oE 'ca_chain.*\[.*\]' \ | grep -oE '\-.*\-' | sed 's/\\n/\'$'\n''/g' \ >> "${VAULT_RAFT_PATH}/cert.pem" \ && printf "${VAULT_ISSUE_TLS//$'\n'/\\\n}" \ | grep -oE 'private_key {9}\-{5}BEGIN [A-Z ]*KEY\-{5}[a-zA-Z0-9+=/\\]*\-{5}END [A-Z ]*KEY\-{5}' \ | grep -oE '\-.*\-' | sed 's/\\n/\'$'\n''/g' \ > "${VAULT_RAFT_PATH}/key.pem"
-
Stop Vault
$ pkill vault
-
Start Vault with TLS and verification of client certificates
$ VAULT_CONFIG=$(cat <<-CONFIG api_addr = "https://127.0.0.1:8200" cluster_addr = "https://127.0.0.1:8201" storage "raft" { node_id = "dev" } listener "unix" { address = "${VAULT_RAFT_PATH}/vault.sock" } listener "tcp" { address = "127.0.0.1:8200" tls_cert_file = "${VAULT_RAFT_PATH}/cert.pem" tls_key_file = "${VAULT_RAFT_PATH}/key.pem" tls_min_version = "tls13" tls_client_ca_file = "${VAULT_RAFT_PATH}/client-ca.pem" tls_require_and_verify_client_cert = true } CONFIG ) \ && vault server -config <(printf "${VAULT_CONFIG}") > /dev/null 2>& 1 &
-
Uneal Vault
$ vault operator unseal "${VAULT_UNSEAL}"
-
Issue Vault Client Certificate
$ VAULT_ISSUE_CLIENT=$(vault write pki_client/issue/client common_name="Vault Agent" ttl="1m") \ && printf "${VAULT_ISSUE_CLIENT//$'\n'/\\\n}" \ | grep -oE 'certificate {9}\-{5}BEGIN CERTIFICATE\-{5}[a-zA-Z0-9+=/\\]*\-{5}END CERTIFICATE\-{5}' \ | grep -oE '\-.*\-' | sed 's/\\n/\'$'\n''/g' \ > "${VAULT_RAFT_PATH}/client-cert.pem" \ && printf "${VAULT_ISSUE_CLIENT//$'\n'/\\\n}" \ | grep -oE 'ca_chain.*\[.*\]' \ | grep -oE '\-.*\-' | sed 's/\\n/\'$'\n''/g' \ >> "${VAULT_RAFT_PATH}/client-cert.pem" \ && printf "${VAULT_ISSUE_CLIENT//$'\n'/\\\n}" \ | grep -oE 'private_key {9}\-{5}BEGIN [A-Z ]*KEY\-{5}[a-zA-Z0-9+=/\\]*\-{5}END [A-Z ]*KEY\-{5}' \ | grep -oE '\-.*\-' | sed 's/\\n/\'$'\n''/g' \ > "${VAULT_RAFT_PATH}/client-key.pem"
-
Vault Agent
$ unset VAULT_ADDR \ && VAULT_AGENT_CONFIG=$(cat <<-CONFIG pid_file = "${VAULT_RAFT_PATH}/agent.pid" vault { address = "https://127.0.0.1:8200" ca_cert = "${VAULT_RAFT_PATH}/tls-ca.pem" client_cert = "${VAULT_RAFT_PATH}/client-cert.pem" client_key = "${VAULT_RAFT_PATH}/client-key.pem" } auto_auth { method "cert" { name = "vault-agent" ca_cert = "${VAULT_RAFT_PATH}/tls-ca.pem" client_cert = "${VAULT_RAFT_PATH}/client-cert.pem" client_key = "${VAULT_RAFT_PATH}/client-key.pem" reload = true } } template { contents = <<-EOT {{- with pkiCert "pki_client/issue/client" "common_name=Vault Agent" "ttl=1m" -}} {{- .Data.Cert -}} {{- if .Data.Key -}} {{- .Data.Key | writeToFile "${VAULT_RAFT_PATH}/client-key.pem" "$(id -u)" "$(id -g)" "0600" -}} {{- end -}} {{- end -}} {{- with secret "pki_client/cert/ca_chain" -}} {{- .Data.ca_chain -}} {{- end -}} EOT destination = "${VAULT_RAFT_PATH}/client-cert.pem" backup = false exec { command = ["bash", "-c", "kill \$(cat ${VAULT_RAFT_PATH}/agent.pid)"] } } CONFIG ) \ && while true; do vault agent -config <(printf "${VAULT_AGENT_CONFIG}"); done