Authenticate to Vault using the SPIFFE auth method with SPIRE
Enterprise
Appropriate Vault Enterprise license required
You can authenticate to Vault using the SPIFFE auth method with SPIRE (SPIFFE Runtime Environment), a production-ready implementation of the full SPIFFE framework and set of standards for identifying and securing communications between application services.
If you are not familiar with SPIFFE, refer to the SPIFFE overview for information about how SPIFFE authentication works in Vault.
Follow these steps as written. Running them on production hosts changes their configuration. Refer to the setup guide for general configuration instructions.
Requirements
- An active Vault Enterprise license.
- Vault Enterprise installed.
- SPIRE server installed.
- SPIRE agent installed.
- A Linux server or instance on which to run this walkthrough.
Set up Vault and SPIRE
This section walks through the minimum configuration needed to get a workload authenticating to Vault using SPIRE. This section does not cover SPIRE installation or hardening. Refer to the SPIRE documentation for more information.
Set up the SPIRE server
Set up a SPIRE server. A SPIRE agent connects to the server to issue SVIDs to workloads.
Create a working directory for the SPIRE server.
$ mkdir ~/spire-server && cd ~/spire-serverThis step is necessary for the minimal setup shown in this doc. Typically the SPIRE Server and SPIRE Agent run on different nodes. You are isolating the configuration and data directory here to avoid conflicts.
Create a minimal SPIRE server config.
$ tee spire-server.conf <<EOF # spire-server.conf server { trust_domain = "example.org" bind_address = "0.0.0.0" bind_port = "8081" data_dir = "./.data" federation { bundle_endpoint { address = "0.0.0.0" port = 8443 profile "https_spiffe" {} } } } plugins { DataStore "sql" { plugin_data { database_type = "sqlite3" connection_string = "./.data/datastore.sqlite3" } } NodeAttestor "join_token" { plugin_data {} } KeyManager "disk" { plugin_data { keys_path = "./.data/keys.json" } } } EOFStart the SPIRE server.
$ spire-server run -config ./spire-server.conf &Create a one-time join token for the SPIRE agent to connect to.
$ JOIN_TOKEN=$(spire-server token generate -spiffeID spiffe://example.org/agent/example-node | sed 's/^Token: //')This example uses join-token node attestation. A join token is single-use, similar to a Vault wrapping token. It bootstraps exactly one agent and is then no longer valid. Production deployments should use a platform-specific node attestor (
aws_iid,gcp_iit,k8s_psat,x509pop, or another supported attestor) instead of shared join tokens.
Set up the SPIRE agent
The agent is what actually issues SVIDs to workloads. The SPIRE server and a registration entry alone do not enable authentication.
Create a working directory for the SPIRE agent.
$ mkdir ~/spire-agent && cd ~/spire-agentGet the trust bundle from the SPIRE server and save it to a file.
$ spire-server bundle show > initial_bundle.crtThe SPIRE Agent will need this when you start the agent.
Create a minimal SPIRE agent config.
$ tee spire-agent.conf <<EOF # agent.conf agent { data_dir = "./.data" server_address = "127.0.0.1" server_port = "8081" socket_path = "/tmp/spire-agent/public/api.sock" trust_bundle_path = "./initial_bundle.crt" trust_domain = "example.org" } plugins { NodeAttestor "join_token" { plugin_data {} } KeyManager "disk" { plugin_data { directory = "./.data" } } WorkloadAttestor "unix" { plugin_data {} } } EOFThe
trust_bundle_pathrequires manually copying the server's initial trust bundle onto the node before the agent's first start. In a production environment, provision this file through your existing configuration management and secrets injection workflow at provisioning time. Alternatively, usetrust_bundle_urlto fetch the bundle. Refer to SPIRE's agent configuration reference for both options.Start the agent with the join token from the server configuration section.
$ spire-agent run -config spire-agent.conf -joinToken $JOIN_TOKEN &
Register a workload
Register a workload on the SPIRE server. The selector used when registering the workload must match the agent configuration.
$ spire-server entry create \ -parentID spiffe://example.org/agent/example-node \ -spiffeID spiffe://example.org/ns/prod/sa/payment-service \ -selector unix:uid:$(id -u)The
WorkloadAttestorunixplugin in the agent configuration matches theunix:uid:...selector. Replace both together if you are attesting workloads a different way (Kubernetes, Docker, or another supported platform). The example command uses$(id -u)to capture your own UID at run time. This works as long as you are the one both registering the entry and later fetching the SVID. In a real deployment where an operator registers entries for a separate service account, substitute that account's UID explicitly.$(id -u)captures the operator's UID, not the workload's.Request a workload SVID.
$ spire-agent api fetch x509 -write ~/spire-agentThis writes
~/spire-agent/svid.0.pemand~/spire-agent/svid.0.key.Manually fetching and writing an SVID to disk confirms the setup works, but it does not rotate or renew the SVID. Production workloads should call the Workload API directly using a SPIFFE SDK, or use SPIFFE Helper.
Configure the Vault auth method
Configure Vault with the SPIFFE auth method to match the SPIRE configuration.
Create a working directory for the Vault server.
$ mkdir ~/vault-dev && cd ~/vault-devExport your Vault Enterprise license as an environment variable.
$ export VAULT_LICENSE=C10WMSH0W...snip...S3ASM3STR33TStart a Vault dev mode server.
$ vault server -dev -dev-tls -dev-root-token-id root &The dev server runs completely in memory and listens on
localhoston TCP port 8200 with TLS enabled. At runtime, the dev server also automatically unseals and prints the unseal key and initial root token values to stdout.Copy the environment variables for the Vault dev mode server.
Export the required Vault environment variables.
$ export VAULT_TOKEN=root VAULT_ADDR=https://127.0.0.1:8200 VAULT_CACERT='/path/from/stdout'Request the trust bundle for Vault.
$ spire-server bundle show -format spiffe > initial_bundle.jwksEnable the SPIFFE auth method.
$ vault auth enable \ -passthrough-request-headers="Authorization" \ spiffeWrite the SPIFFE auth method configuration.
$ vault write auth/spiffe/config \ trust_domain="example.org" \ profile="https_spiffe_bundle" \ bundle=@initial_bundle.jwks \ endpoint_url="https://127.0.0.1:8443" \ endpoint_spiffe_id="spiffe://example.org/spire/server" \ audience="vault"audienceis mount-wide, not per-role. Every role on this mount shares this same JWT audience allow-list. X.509-SVIDs carry noaudclaim, so X.509-SVID auth is unaffected by this setting.Create a role for the workload.
$ vault write auth/spiffe/role/payment-role \ workload_id_patterns="ns/prod/sa/payment-service" \ token_policies="payment-vault-policy" \ token_ttl="1h"workload_id_patternsmatches on the workload ID — the SPIFFE ID with thespiffe://<trust_domain>/prefix stripped, not the full URI. Supports*(prefix) and+(single path segment) wildcards.
Authenticate a workload to Vault
Production services use a SPIFFE SDK (go-spiffe for Go, py-spiffe for Python, java-spiffe for Java, or another SPIFFE SDK implementation) to call the Workload API directly.
This walkthrough uses the spire-agent CLI and curl to authenticate to Vault.
Use
curlto authenticate to Vault.$ curl \ --cacert "$VAULT_CACERT" \ --cert ~/spire-agent/svid.0.pem \ --key ~/spire-agent/svid.0.key \ --request POST \ --data '{"role": "payment-role"}' \ $VAULT_ADDR/v1/auth/spiffe/login | jqExample output:
{ "request_id": "0f7905fb-6194-c4c7-5f0a-5c5bf4f042c5", "lease_id": "", "renewable": false, "lease_duration": 0, "data": null, "wrap_info": null, "warnings": null, "auth": { "client_token": "hvs.CAESID_Uge-45...example...WRzUmdicTJ3UEpVZ2o", "accessor": "MTBqnsBvoRuhqMN3kYFt0iRS", "policies": [ "default", "payment-vault-policy" ], "token_policies": [ "default", "payment-vault-policy" ], "metadata": { "role": "payment-role", "spiffe_id": "spiffe://example.org/ns/prod/sa/payment-service", "trust_domain": "example.org" }, "lease_duration": 3600, "renewable": true, "entity_id": "707d32fd-8021-7fc7-9d08-c3c9a7ae7374", "token_type": "service", "orphan": true, "mfa_requirement": null, "num_uses": 0 }, "mount_type": "" }Optionally set
"type"in the request body (auto,cert, orjwt) to force which SVID source Vault should use.auto(the default) prefers a JWT-SVID if present, falling back to the peer X.509 certificate.After successful validation, Vault returns a client token bound to the role's policies.
SPIFFE plugin API
The SPIFFE auth method has a full HTTP API. Refer to the SPIFFE auth API documentation for additional information.
Terraform
You can use the vault_auth_backend resource to enable the SPIFFE auth method
and the vault_spiffe_auth_backend_config to manage the configuration.