hashicorp / vault-plugin-secrets-gcp

Mozilla Public License 2.0
52 stars 26 forks source link

FR: add support for google OIDC tokens #46

Open salrashid123 opened 5 years ago

salrashid123 commented 5 years ago

feature request to add support for providing google id_tokens through vault.

These tokens can be derived from service accounts or GCE metadata server that can then be used to authenticate against a users service on Google Cloud Run, cloud functions, endpoints, IAP. For more info on usecases see Authenticating using Google OpenID Connect Tokens


I put together a prototype of secret_type=id_token by directly copying the access_token implementation code, then adding an additiona flag for audience:

vault write gcp/roleset/my-idtoken-roleset    \
   project="clamav-241815"   \
   secret_type="id_token"  \
   audience="https://foo.bar"   \
   bindings=@fakebindings.hcl

at that point, just read the id_token back

vault read gcp/idtoken/my-idtoken-roleset

Key                   Value
---                   -----
expires_at_seconds    1566157805
id_token              eyJhbGciOiJSUzI1NiIsImtpZCI6IjYwZjQwNjBlNThkNzVmZDNmNzBiZWZmODhjNzk0YTc3NTMyN2FhMzEiLCJ0eXAiOiJKV1QifQ.eyJpc3M-redacted
token_ttl             59m59s

which includes claims:

{
  "iss": "https://accounts.google.com",
  "aud": "https://foo.bar",
  "azp": "vaultmy-idtoken-rol-1566154197@clamav-241815.iam.gserviceaccount.com",
  "sub": "113417701541749300799",
  "email": "vaultmy-idtoken-rol-1566154197@clamav-241815.iam.gserviceaccount.com",
  "email_verified": true,
  "iat": 1566154206,
  "exp": 1566157806
}

Couple of notes:

jefferai commented 5 years ago

Doesn't seem like a custom type should be necessary if they're really OIDC tokens as google claims.

salrashid123 commented 5 years ago

@jefferai Could you elaborate a bit more on that?

emilymye commented 5 years ago

I think what @jefferai means is that instead of having a new id_token secret type we could just output both access_token + id_token via the same access token endpoint or add a flag to only output id token in the response if we're worried about giving people the access token

salrashid123 commented 5 years ago

ok, we'd def want to apply selective acls to both token types access_token and id_token carry different capabilities (the latter is identity). To me, they make more sense as different types vs overloading one type with arguments that dont' apply to the other (eg, the audience="https://foo.bar" doesn't even mean anything to access_token while bindings= doesn't mean anything to id_token

tonglil commented 3 years ago

Is there any way to prioritize this work to support generating tokens for IAP authentication?

salrashid123 commented 3 years ago

was looking at this for a diff reason today and decided to update it with HEAD. attached are the modifications and the working usage for id_token and jwt_access_token. The id_token capability shoudl work for iap if you set the audience value correctly

if there is interest in having additional secret types based on the existing way to get access and service account jwt, the files attached to this issue at the bottom could be used as working start point (i'd submit it fully but don't know how to writeup the testcases at all)

  1. Compile
export GOBIN=`pwd`/bin
make fmt
make dev

vault server -dev -dev-plugin-dir=./bin --log-level=debug
  1. New window

load plugin

export VAULT_ADDR='http://localhost:8200'

export SHASUM=$(shasum -a 256 "bin/vault-plugin-secrets-gcp" | cut -d " " -f1)

vault plugin register \
    -sha256="${SHASUM}" \
    -command="vault-plugin-secrets-gcp" \
    secret vault-plugin-secrets-gcp

vault secrets enable --plugin-name='vault-plugin-secrets-gcp' --path="gcp" plugin

OIDC Token

Create Roleset

vault write gcp/roleset/my-idtoken-roleset    \
   project="pubsub-msg"   \
   secret_type="id_token"  \
   audience="https://foo.bar"   \
   bindings=-<<EOF
resource "//cloudresourcemanager.googleapis.com/projects/pubsub-msg" {
    roles = []  
}
EOF

Create VAULT_TOKEN with policy

vault policy write idtoken-policy -<<EOF
path "gcp/idtoken/my-idtoken-roleset" {
    capabilities = ["read"]
}
EOF

vault token create -policy=idtoken-policy

Copy VAULT_TOKEN to new window and access secret

export VAULT_ADDR='http://localhost:8200'
export VAULT_TOKEN=s.gSREOoTDI5vGZwHQKW1w43Fl
vault read gcp/idtoken/my-idtoken-roleset

vault read gcp/idtoken/my-idtoken-roleset
Key                   Value
---                   -----
expires_at_seconds    1626814203
id_token              eyJhbGciOiJSUzI1NiIsImtpZCI6IjdmNTQ4ZjY3MDg2OTBjMjExMjBiMGFiNjY4Y2FhMDc5YWNiYzJiMmYiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJodHRwczovL2Zvby5iYXIiLCJhenAiOiJ2YXVsdG15LWlkdG9rZW4tcm9sLTE2MjY4MTAyMjZAcHVic3ViLW1zZy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImVtYWlsIjoidmF1bHRteS1pZHRva2VuLXJvbC0xNjI2ODEwMjI2QHB1YnN1Yi1tc2cuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiZXhwIjoxNjI2ODE0MjAzLCJpYXQiOjE2MjY4MTA2MDMsImlzcyI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbSIsInN1YiI6IjExNDQ2ODQ5MDY4NDEwMzk1MjMzNCJ9.kXAtujjYBfheS2-kNytjHVnn4s0-xtS2FtRGcZXlhbv54zastjKmVQTa0BeH3F4MJd2JPbT30J9ioucf0c5y516DvX3ot70ktcbq9b4-93jYnK9sotJX-1iucSk108kzplcKESTcxUAO_I5EAhvUkQfiFbsseF6eoPK7jN3SKD5KiZYgKKHgVHyuUcwLcHoo5-RTa3RguhBrLVugw9LTHZkcS7EFhR08d0VS2gdrTQGAjMS7uB-lRHdz7VQVXxVeX-teYbk8ln5XCh6OTozFRg5ENwp6EL3IH8flZUi7GHCkfXjGcMNqJR8vaN5yN68coZJJuiEh4S6waCrj4cnBhQ
token_ttl             59m59s

gives an id_token with

{
  "aud": "https://foo.bar",
  "azp": "vaultmy-idtoken-rol-1626810226@pubsub-msg.iam.gserviceaccount.com",
  "email": "vaultmy-idtoken-rol-1626810226@pubsub-msg.iam.gserviceaccount.com",
  "email_verified": true,
  "exp": 1626814203,
  "iat": 1626810603,
  "iss": "https://accounts.google.com",
  "sub": "114468490684103952334"
}

JWTAccessToken

vault write gcp/roleset/my-jwttoken-roleset    \
   project="pubsub-msg"   \
   secret_type="jwt_access_token"  \
   audience="https://pubsub.googleapis.com/google.pubsub.v1.Publisher"   \
   bindings=-<<EOF
resource "projects/pubsub-msg" {
    roles = ["roles/pubsub.admin"]  
}
EOF

vault policy write jwttoken-policy -<<EOF
path "gcp/jwtaccess/my-jwttoken-roleset" {
    capabilities = ["read"]
}
EOF

vault token create -policy=jwttoken-policy

copy VAULT_TOKEN to new window

export VAULT_ADDR='http://localhost:8200'
export VAULT_TOKEN=s.W73ewt7HJ8JEClRUYkx4UxaW

$ vault read gcp/jwtaccess/my-jwttoken-roleset
Key                   Value
---                   -----
expires_at_seconds    1626814668
jwt_access_token      eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjZkZTBlZDI0Mzc5MmQ2MjVmNjM2MzllMzU0Njg4NDIyM2JmZGUxZmUifQ.eyJpc3MiOiJ2YXVsdG15LWp3dHRva2VuLXJvLTE2MjY4MTA3NTJAcHVic3ViLW1zZy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImF1ZCI6Imh0dHBzOi8vZm9vLmJhciIsImV4cCI6MTYyNjgxNDY2OCwiaWF0IjoxNjI2ODExMDY4LCJzdWIiOiJ2YXVsdG15LWp3dHRva2VuLXJvLTE2MjY4MTA3NTJAcHVic3ViLW1zZy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9.euCJI5w0_nwBICRCoyQZvKc03CxaXXbRdcLH0I_uJJj8oLsLIUITLOlkHkvZiPgcwvY5OELaWt4i04MkaY3ou6ObSp7UcxIeYqVBtPc-4gIX6sm-wHHFRT5EXHXkEX4wD8FXhxiBDduLYtoZP_Njx1IV0B1que5njN8hqgPsn917KwzuWH_7GZA1UcYxkX5Gq3O13UMk9H8-O-djM-mIaF75juiVAo77EiWfcdiDuHzgyrSWNZ0NeusGrhc9V8ZGTs28reFotnrMjMiH0Nygdd1syTJBKdgoNpN_9VOoLViXv5pGrDf5-GUXUjTyDwEUaNBJ1BV7vbLNXLvG5HsHfQ
token_ttl             59m59s

gives JWTAccessToken of form

{
  "iss": "vaultmy-jwttoken-ro-1626810752@pubsub-msg.iam.gserviceaccount.com",
  "aud": "https://pubsub.googleapis.com/google.pubsub.v1.Publisher",
  "exp": 1626814668,
  "iat": 1626811068,
  "sub": "vaultmy-jwttoken-ro-1626810752@pubsub-msg.iam.gserviceaccount.com"
}

fr46.tar.gz