Skip to content

Instantly share code, notes, and snippets.

@111a5ab1
Last active July 16, 2024 22:49
Show Gist options
  • Save 111a5ab1/aa5960d9a6a26a89e95385afbf504b8a to your computer and use it in GitHub Desktop.
Save 111a5ab1/aa5960d9a6a26a89e95385afbf504b8a to your computer and use it in GitHub Desktop.

!! INSECURE - DO NOT USE THIS IN PRODUCTION !!

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.

Cert

  1. Create temporary directory

    $ export VAULT_RAFT_PATH="$(mktemp --tmpdir="/tmp" --directory "vault.XXXXXXXX")"
  2. 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 &
  3. Set environment variables

    $ export VAULT_ADDR="unix:///${VAULT_RAFT_PATH}/vault.sock"
  4. 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; }')
  5. Uneal Vault

    $ vault operator unseal "${VAULT_UNSEAL}"
  6. Set Vault Root Token

    $ export VAULT_TOKEN=$(printf "${VAULT_INIT}" | grep "Root" | awk '{print $NF; }')
  7. 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
  8. Apply Terraform

    $ terraform -chdir="${VAULT_RAFT_PATH}" init \
        && VAULT_ADDR="http://127.0.0.1:8200" \
        && terraform -chdir="${VAULT_RAFT_PATH}" apply -auto-approve
  9. 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"
  10. Stop Vault

    $ pkill vault
  11. 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 &
  12. Uneal Vault

    $ vault operator unseal "${VAULT_UNSEAL}"
  13. 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"
  14. 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment