Skip to content

Instantly share code, notes, and snippets.

@jrx
Created December 15, 2022 07:59
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 jrx/31b391414f2652ceee52acdfc7614442 to your computer and use it in GitHub Desktop.
Save jrx/31b391414f2652ceee52acdfc7614442 to your computer and use it in GitHub Desktop.

Demo: CI/CD with Vault AppRole

Recommended Pattern for Vault AppRole Use

This demo aims to demonstrate how a CI/CD tool like GitLab or Jenkins could be used to broker trust for Vault by providing role IDs and wrapped secret IDs for the "build job" to consume. You can find the described pattern in the documentation .

Create AppRoles

Vault needs to be configured to create the AppRoles needed.

Create a policy for the CI Controller:

cat <<EOF > ci-control-policy.hcl
# Allow CI to read from the secret KV store
path "secret/*" {
  capabilities = ["read", "list"]
}
# Allow CI to create wrapped secret-ids
path "auth/approle/role/app1/*" {
  capabilities = [ "create", "read", "update", "delete", "sudo" ]
}
EOF

vault policy write ci-control ci-control-policy.hcl

Configure the CI Controller AppRole:

vault auth enable approle
vault write auth/approle/role/ci-control \
    token_num_uses=0 \
    token_ttl=0 \
    token_max_ttl=0 \
    secret_id_num_uses=0 \
    token_policies="ci-control"

# Fetch the RoleId of the AppRole
vault read auth/approle/role/ci-control/role-id \
    --format=json | jq -r .data.role_id > ./ci-control-approle-role-id

# Get a SecretID issued against the AppRole
vault write -f auth/approle/role/ci-control/secret-id \
    --format=json | jq -r .data.secret_id > ./ci-control-approle-secret-id

Create a policy for the CI App1 build job:

cat <<EOF > app1_policy.hcl
# Allow app1 to retrieve secret from the secret KV store
path "secret/data/dev" {
  capabilities = ["read"]
}
EOF

vault policy write app1 app1_policy.hcl

Configure the CI App1 build job AppRole:

# Write some test data at secret/dev that the wrapped secretID will allow access to
vault secrets enable -path=secret kv-v2
vault kv put secret/dev username="webapp" password="my-long-password"

# Create AppRole for app1_policy
vault write auth/approle/role/app1 \
    secret_id_ttl=10m \
    token_num_uses=2 \
    token_ttl=20m \
    token_max_ttl=30m \
    secret_id_num_uses=1 \
    token_policies="app1"

Pipeline Steps

CI Controller authenticates to Vault and Vault returns a token:

vault write auth/approle/login \
    role_id=$(cat ci-control-approle-role-id) \
    secret_id=$(cat ci-control-approle-secret-id) \
    --format=json | jq -r .auth.client_token > ./ci-control-token

Controller uses token to retrieve the RoleID of the CI job it will spawn:

export VAULT_TOKEN=$(cat ci-control-token)
vault read auth/approle/role/app1/role-id \
    --format=json | jq -r .data.role_id > ./app1-approle-role-id

Controller uses token to retrieve a wrapped SecretID:

export VAULT_TOKEN=$(cat ci-control-token)
vault write -wrap-ttl=60m -f auth/approle/role/app1/secret-id \
    --format=json | jq -r .wrap_info.token > ./wrapping-token

Controller spawns the CI build job and passes the wrapped SecretID as a variable to the job and the build job requests to unwrap the SecretID:

# Attempting to unwrap secret ID from wrapping token'
export VAULT_ADDR=http://127.0.0.1:8200
export VAULT_TOKEN=$(cat wrapping-token)
vault unwrap \
    --format=json | jq -r .data.secret_id > ./app1-approle-secret-id

Build job uses RoleID and SecretID to authenticate to Vault and Vault returns a token with policies that allow read of the required secrets:

vault write auth/approle/login \
    role_id=$(cat app1-approle-role-id) \
    secret_id=$(cat app1-approle-secret-id) \
    --format=json | jq -r .auth.client_token > ./app1-approle-token

The build job uses the token to get secrets from Vault:

VAULT_TOKEN=$(cat app1-approle-token) vault read secret/data/dev
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment