About Vault OpenID Connect
Use Vault OpenID Connect (OIDC) with SPIRE to securely authenticate workloads. Vault uses SPIRE as a trusted OIDC provider to validate workload identities. This configuration enables workloads to receive short-lived tokens to access secrets and perform actions within Vault.
Installing Vault
Install HashiCorp Vault to serve as an OpenID Connect (OIDC) provider. This establishes the necessary infrastructure to manage workload identities securely in your Zero Trust Workload Identity Manager environment.
-
Configure a route. For more information, see Configuring routes
-
Helm is installed.
-
A command-line JSON processor for easily reading the output from the Vault API.
-
A HashiCorp Helm repository is added.
-
Create the
vault-helm-value.yamlfile.global: enabled: true openshift: true tlsDisable: true injector: enabled: false server: ui: enabled: true image: repository: docker.io/hashicorp/vault tag: "1.19.0" dataStorage: enabled: true size: 1Gi standalone: enabled: true config: | listener "tcp" { tls_disable = 1 address = "[::]:8200" cluster_address = "[::]:8201" } storage "file" { path = "/vault/data" } extraEnvironmentVars: {}-
The
openshiftfield optimizes the deployment for OpenShift-specific security contexts. -
The
tlsDisablefield disables TLS for Kubernetes objects created by the chart. -
The
datastorage.enabledfield creates a 1Gi persistent volume to store Vault data. -
The
standalone.enabledfield deploys a single Vault pod. -
The
tls_disabledfield tells the Vault server to not use TLS.
-
-
Run the
helm installcommand:$ helm install vault hashicorp/vault \ --create-namespace -n vault \ --values ./vault-helm-value.yaml -
Expose the Vault service by running the following command:
$ oc expose service vault -n vault -
Set the
VAULT_ADDRenvironment variable to retrieve the hostname from the new route and then export it by running the following command:$ export VAULT_ADDR="http://$(oc get route vault -n vault -o jsonpath='{.spec.host}')"http://is prepended because TLS is disabled.
-
To ensure your Vault instance is running, run the following command:
$ curl -s $VAULT_ADDR/v1/sys/health | jqExample output{ "initialized": true, "sealed": true, "standby": true, "performance_standby": false, "replication_performance_mode": "disabled", "replication_dr_mode": "disabled", "server_time_utc": 1663786574, "version": "1.19.0", "cluster_name": "vault-cluster-a1b2c3d4", "cluster_id": "5e6f7a8b-9c0d-1e2f-3a4b-5c6d7e8f9a0b" }
Initializing and unsealing Vault
To prepare a newly installed Vault server for operation, initialize and unseal it. This process loads the primary encryption key into memory so that Vault can decrypt data and protect other encryption keys.
The steps to initialize a Vault server are:
-
Initialize and unseal Vault
-
Enable the key-value (KV) secrets engine and store a test secret
-
Configure JSON Web Token (JWT) authentication with SPIRE
-
Deploy a demonstration application
-
Authenticate and retrieve the secret
-
Ensure that Vault is running.
-
Ensure that Vault is not initialized. You can only initialize a Vault server once.
-
Open a remote shell into the
vaultpod by running the following command:$ oc rsh -n vault statefulset/vault -
Initialize Vault to get your unseal key and root token by running the following command:
$ vault operator init -key-shares=1 -key-threshold=1 -format=json -
Export the unseal key and root token you received from the earlier command by running the following commands:
$ export UNSEAL_KEY=<Your-Unseal-Key>$ export ROOT_TOKEN=<Your-Root-Token> -
Unseal Vault using your unseal key by running the following command:
$ vault operator unseal -format=json $UNSEAL_KEY -
Exit the pod by entering
exit.
-
To verify that the Vault pod is ready, run the following command:
$ oc get pod -n vaultExample outputNAME READY STATUS RESTARTS AGE vault-0 1/1 Running 0 65d
Enabling the key-value secrets engine and store a test secret
Enable the key-value secrets engine to create a secure, centralized location for managing credentials. You can also store a test secret to verify that the engine is working.
-
Make sure that Vault is initialized and unsealed.
-
Open another shell session in the
Vaultpod by running the following command:$ oc rsh -n vault statefulset/vault -
Export your root token again within this new session and log in by running the following command:
$ export ROOT_TOKEN=<Your-Root-Token>$ vault login "${ROOT_TOKEN}" -
Enable the KV secrets engine at the
secret/path and create a test secret by running the following commands:$ export NAME=ztwim$ vault secrets enable -path=secret kv$ vault kv put secret/$NAME version=v0.1.0
-
To verify that the secret is stored correctly, run the following command:
$ vault kv get secret/$NAME
Configuring JSON Web Token authentication with SPIRE
To help your applications securely log in to Vault using SPIFFE identities, configure JSON Web Token (JWT) authentication.
-
Make sure that Vault is initialized and unsealed.
-
Ensure that a test secret is stored in the key-value secrets engine.
-
On your local machine, retrieve the SPIRE Certificate Authority (CA) bundle and save it to a file by running the following command:
$ oc get cm -n zero-trust-workload-identity-manager spire-bundle -o jsonpath='{ .data.bundle\.crt }' > oidc_provider_ca.pem -
Back in the Vault pod shell, create a temporary file and paste the contents of
oidc_provider_ca.peminto it by running the following command:$ cat << EOF > /tmp/oidc_provider_ca.pem -----BEGIN CERTIFICATE----- <Paste-Your-Certificate-Content-Here> -----END CERTIFICATE----- EOF> -
Set up the necessary environment variables for the JWT configuration by running the following commands:
$ export APP_DOMAIN=<Your-App-Domain>$ export JWT_ISSUER_ENDPOINT="oidc-discovery.$APP_DOMAIN"$ export OIDC_URL="https://$JWT_ISSUER_ENDPOINT"$ export OIDC_CA_PEM="$(cat /tmp/oidc_provider_ca.pem)" -
Crate a new environment variable by running the following command:
$ export ROLE="${NAME}-role" -
Enable the JWT authentication method by running the following command:
$ vault auth enable jwt -
Configure you ODIC authentication method by running the following command:
$ vault write auth/jwt/config \ oidc_discovery_url=$OIDC_URL \ oidc_discovery_ca_pem="$OIDC_CA_PEM" \ default_role=$ROLE -
Create a policy named
ztwim-policyby running the following command:$ export POLICY="${NAME}-policy" -
Grant read access to the secret you created earlier by running the following command:
$ vault policy write $POLICY -<<EOF path "secret/$NAME" { capabilities = ["read"] } EOF -
Create the following environment variables by running the following commands:
$ export APP_NAME=client$ export APP_NAMESPACE=demo$ export AUDIENCE=$APP_NAME -
Create a JWT role that binds the policy to workload with a specific SPIFFE ID by running the following command:
$ vault write auth/jwt/role/$ROLE -<<EOF { "role_type": "jwt", "user_claim": "sub", "bound_audiences": "$AUDIENCE", "bound_claims_type": "glob", "bound_claims": { "sub": "spiffe://$APP_DOMAIN/ns/$APP_NAMESPACE/sa/$APP_NAME" }, "token_ttl": "24h", "token_policies": "$POLICY" } EOF
Deploying a demonstration application
Deploy a demonstration application to create a simple client that uses its SPIFFE identity to authenticate with Vault. By doing this you can verify that the client can successfully authenticate using the configured identity.
-
On your local machine, set the environment variables for your application by running the following commands:
$ export APP_NAME=client$ export APP_NAMESPACE=demo$ export AUDIENCE=$APP_NAME -
Apply the Kubernetes manifest to create the namespace, service account, and deployment for the demo app by running the following command. This deployment mounts the SPIFFE CSI driver socket.
$ oc apply -f - <<EOF # ... (paste the full YAML from your provided code here) ... EOF>>
-
Verify that the client deployment is ready by running the following command:
$ oc get deploy -n $APP_NAMESPACEExample outputNAME READY UP-TO-DATE AVAILABLE AGE frontend-app 2/2 2 2 120d backend-api 3/3 3 3 120d
Authenticating and retrieving the secret
Use the demonstration application to fetch a JWT token from the SPIFFE Workload API. Use the token to authenticate with Vault so that you can securely retrieve the secret and verify the workflow.
-
Fetch a JWT-SVID by running the following command inside the running client pod:
$ oc -n $APP_NAMESPACE exec -it $(oc get pod -o=jsonpath='{.items[*].metadata.name}' -l app=$APP_NAME -n $APP_NAMESPACE) \ -- /opt/spire/bin/spire-agent api fetch jwt \ -socketPath /run/spire/sockets/spire-agent.sock \ -audience $AUDIENCE -
Copy the token from the output and export it as an environment variable on your local machine by running the following command:
$ export IDENTITY_TOKEN=<Your-JWT-Token> -
Crate a new environment variable by running the following command:
$ export ROLE="${NAME}-role" -
Use
curlto send the JWT token to the Vault login endpoint to get a Vault client token by running the following command:$ VAULT_TOKEN=$(curl -s --request POST --data '{ "jwt": "'"${IDENTITY_TOKEN}"'", "role": "'"${ROLE}"'"}' "${VAULT_ADDR}"/v1/auth/jwt/login | jq -r '.auth.client_token')
-
Use the newly acquired Vault token to read the secret from the KV store by running the following command:
$ curl -s -H "X-Vault-Token: $VAULT_TOKEN" $VAULT_ADDR/v1/secret/$NAME | jqYou should see the contents of the secret (
"version": "v0.1.0") in the output, confirming the entire workflow is successful