I want to use GitHub Actions to use the Terraform Vault Provider to apply changes to my Vault instance. In order to do this, I need some sort of Vault authentication method. I have set up a JWT auth method in vault:
$ vault read auth/jwt/role/github-admin-role
Key Value
--- -----
allowed_redirect_uris <nil>
bound_audiences [https://github.com/bby-corp]
bound_claims map[]
bound_claims_type glob
bound_subject repo:bby-corp/atat-vault-terraform:pull_request
...
Then I define the terraform provider like:
provider "vault" {
address = "https://vault.company.com"
auth_login_jwt {
role = "github-admin-role"
}
}
So far so good. In my GitHub action pipeline, I can successfully grab a JWT token and log in using curl:
- name: Set JWT Auth Token
id: auth-token
run: |
export TOKEN=$(curl -sSL -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" "$ACTIONS_ID_TOKEN_REQUEST_URL")
echo $TOKEN | jq .value | base64
echo "token=$(echo $TOKEN)" >> $GITHUB_OUTPUT
- name: Troubleshoot Token
run: |
export TOKEN_JSON=$(echo $GITHUB_OIDC_TOKEN | jq "{ jwt: .value, role: \"$VAULT_ROLE\" }")
echo $TOKEN_JSON | jq -r '.jwt | split(".") | .[1] | @base64d' | jq
echo $TOKEN_JSON | curl -sSLf -X PUT -H "Content-Type: application/json" --data @- $VAULT_URL/v1/auth/jwt/login
env:
VAULT_ROLE: "github-admin-role"
VAULT_URL: "https://vault.company.com"
GITHUB_OIDC_TOKEN: ${{ steps.auth-token.outputs.token }}
This succeeds. The echo of the token in the “set token” step gives a seemlingly good looking base64 token. The more complex jq breakdown in the “troubleshoot” step gives a valid json that holds all the token’s claims, as expected, eg:
{
"jti": "4b8a5aa4-0fd4-4f57-b31c-81cbf42f90b1",
"sub": "repo:company/vault-terraform:pull_request",
"aud": "https://github.com/company",
...
}
The curl command gives the following response:
{"request_id":"2692e08e-8445-1c3f-0c0c-486b253e8f18","lease_id":"","renewable":false,"lease_duration":0,"data":null,"wrap_info":null,"warnings":["TTL of \"768h\" exceeded the effective max_ttl of \"1m40s\"; TTL value is capped accordingly"],"auth":{"client_token":"hvs.CAESIF2RcSztn688v8iMo-okYYYu9-4mM4cxFD-PyN0XM1CSGh4KHGh2cy5YckNGamJsSHI1bGtiekNRbmVDdjMyV3M","accessor":"Drl6JWqS71GwzNIT4uvjMuuB","policies":["admin","default"],"token_policies":["admin","default"],"metadata":{"role":"github-admin-role"},"lease_duration":100,"renewable":true,"entity_id":"17689fc9-2c60-fb13-5c3e-3b725976e5c1","token_type":"service","orphan":true,"mfa_requirement":null,"num_uses":0}}
So far so good! Login succeeds and I get a token with the desired role. But then I go to run a terraform plan in a follow on step and this is what happens:
- name: Plan Terraform
run: |
export TERRAFORM_VAULT_AUTH_JWT=$(echo $GITHUB_OIDC_TOKEN | jq .value)
TF_LOG=debug terraform plan -input=false -no-color -out=tfplan
env:
GITHUB_OIDC_TOKEN: ${{ steps.auth-token.outputs.token }}
Error message:
Error: Error making API request.
URL: PUT https://vault.company.com/v1/auth/jwt/login
Code: 400. Errors:
* error validating token: error verifying token signature: oidc: malformed jwt: illegal base64 data at input byte 0
I try to correct this by encoding the token that I am saving to the ENV variable in base64:
export TERRAFORM_VAULT_AUTH_JWT=$(echo $GITHUB_OIDC_TOKEN | jq .value | base64)
and I get
* error validating token: error verifying token signature: oidc: malformed jwt: square/go-jose: compact JWS format must have three parts
I am doing something wrong with the handling of the JWT token when I pass it to the provider (via env variable), but I cannot figure out what. The same post to the same URL with the “same” data is yielding a successful login, when I create my own JSON value with jq in the shell.
Does anyone have any idea what the terraform vault provider could be doing that is messing me up here? Or at the very least, does anyone know where I can look in the code base to try to figure that out?