The gcp auth method allows Google Cloud Platform entities to authenticate to
Vault. Vault treats Google Cloud as a trusted third party and verifies
authenticating entities against the Google Cloud APIs. This backend allows for
authentication of:
Google Cloud IAM service accounts
Google Compute Engine (GCE) instances
This backend focuses on identities specific to Google Cloud and does not
support authenticating arbitrary Google or Google Workspace users or generic OAuth
against Google.
This plugin is developed in a separate GitHub repository at
hashicorp/vault-plugin-auth-gcp,
but is automatically bundled in Vault releases. Please file all feature
requests, bugs, and pull requests specific to the GCP plugin under that
repository.
Auth methods must be configured in advance before users or machines can
authenticate. These steps are usually completed by an operator or configuration
management tool.
If you are using instance credentials or want to specify credentials via
an environment variable, you can skip this step. To learn more, see the
Google Cloud Credentials section below.
Note: If you're using a Private Google Access
environment, you will additionally need to configure your environment’s custom endpoints
via the custom_endpoint configuration parameter.
The Google Cloud Vault auth method uses the official Google Cloud Golang SDK.
This means it supports the common ways of providing credentials to Google
Cloud.
The environment variable GOOGLE_APPLICATION_CREDENTIALS. This is specified
as the path to a Google Cloud credentials file, typically for a service
account. If this environment variable is present, the resulting credentials are
used. If the credentials are invalid, an error is returned.
Default instance credentials. When no environment variable is present, the
default service account credentials are used.
Note that the previously mentioned permissions are given to the Vault servers.
The IAM service account or GCE instance that is authenticating against Vault
must have the following role:
roles/iam.serviceAccountTokenCreator
roles/iam.serviceAccountTokenCreator
WARNING: Make sure this role is only applied so your service account can
impersonate itself. If this role is applied GCP project-wide, this will allow the service
account to impersonate any service account in the GCP project where it resides.
See Managing service account impersonation
for more information.
As of Vault 1.0, roles can specify an add_group_aliases boolean parameter
that adds group aliases to the auth response. These
aliases can aid in building reusable policies since they are available as
interpolated values in Vault's policy engine. Once enabled, the auth response
will include the following aliases:
This section describes the implementation details for how Vault communicates
with Google Cloud to authenticate and authorize JWT tokens. This information is
provided for those who are curious, but these details are not
required knowledge for using the auth method.
The client sends this signed JWT to Vault along with a role name.
Vault extracts the kid header value, which contains the ID of the
key-pair used to generate the JWT, and the sub ID/email to find the service
account key. If the service account does not exist or the key is not linked to
the service account, Vault denies authentication.
Vault authorizes the confirmed service account against the given role. If
that is successful, a Vault token with the proper policies is returned.
GCE login only applies to roles of type gce and must be completed on an
instance running in GCE. These steps will not work from your local laptop or
another cloud provider.
The client sends this JWT to Vault along with a role name.
Vault extracts the kid header value, which contains the ID of the
key-pair used to generate the JWT, to find the OAuth2 public cert to verify
this JWT.
Vault authorizes the confirmed instance against the given role, ensuring
the instance matches the bound zones, regions, or instance groups. If that is
successful, a Vault token with the proper policies is returned.
This describes how to use the GCP Service Account Credentials API method
directly to generate the signed JWT with the claims that Vault expects. Note the CLI
does this process for you and is much easier, and that there is very little
reason to do this yourself.
For the API method, providing the expiration claim exp is required. If it is omitted,
it will not be added automatically and Vault will deny authentication. Expiration must
be specified as a NumericDate value
(seconds from Epoch). This value must be before the max JWT expiration allowed for a
role. This defaults to 15 minutes and cannot be more than 1 hour.
One you have all this information, the JWT token can be signed using curl and
oauth2l:
You can also do this through the (currently beta) gcloud command. Note that you will
be required to provide the expiration claim exp as a part of the JWT input to the
command.
$gcloud beta iam service-accounts sign-jwt $INPUT_JWT_CLAIMS$OUTPUT_JWT_FILE\ --iam-account=service-account@my-project.iam.gserviceaccount.com \ --project=my-project
$gcloud beta iam service-accounts sign-jwt $INPUT_JWT_CLAIMS$OUTPUT_JWT_FILE\ --iam-account=service-account@my-project.iam.gserviceaccount.com \ --project=my-project
The following example demonstrates the Google Cloud auth method to authenticate
with Vault.
Go
Go
C#
package main
import("context""fmt""os"
vault "github.com/hashicorp/vault/api"
auth "github.com/hashicorp/vault/api/auth/gcp")// Fetches a key-value secret (kv-v2) after authenticating to Vault// via GCP IAM, one of two auth methods used to authenticate with// GCP (the other is GCE auth).funcgetSecretWithGCPAuthIAM()(string,error){
config := vault.DefaultConfig()// modify for more granular configuration
client, err := vault.NewClient(config)if err !=nil{return"", fmt.Errorf("unable to initialize Vault client: %w", err)}// For IAM-style auth, the environment variable GOOGLE_APPLICATION_CREDENTIALS// must be set with the path to a valid credentials JSON file, otherwise// Vault will fall back to Google's default instance credentials.// Learn about authenticating to GCS with service account credentials at https://cloud.google.com/docs/authentication/productionif pathToCreds := os.Getenv("GOOGLE_APPLICATION_CREDENTIALS"); pathToCreds ==""{
fmt.Printf("WARNING: Environment variable GOOGLE_APPLICATION_CREDENTIALS was not set. IAM client for JWT signing and Vault server IAM client will both fall back to default instance credentials.\n")}
svcAccountEmail := fmt.Sprintf("%s@%s.iam.gserviceaccount.com", os.Getenv("GCP_SERVICE_ACCOUNT_NAME"), os.Getenv("GOOGLE_CLOUD_PROJECT"))// We pass the auth.WithIAMAuth option to use the IAM-style authentication// of the GCP auth backend. Otherwise, we default to using GCE-style// authentication, which gets its credentials from the metadata server.
gcpAuth, err := auth.NewGCPAuth("dev-role-iam",
auth.WithIAMAuth(svcAccountEmail),)if err !=nil{return"", fmt.Errorf("unable to initialize GCP auth method: %w", err)}
authInfo, err := client.Auth().Login(context.TODO(), gcpAuth)if err !=nil{return"", fmt.Errorf("unable to login to GCP auth method: %w", err)}if authInfo ==nil{return"", fmt.Errorf("login response did not return client token")}// get secret from the default mount path for KV v2 in dev mode, "secret"
secret, err := client.KVv2("secret").Get(context.Background(),"creds")if err !=nil{return"", fmt.Errorf("unable to read secret: %w", err)}// data map can contain more than one key-value pair,// in this case we're just grabbing one of them
value, ok := secret.Data["password"].(string)if!ok {return"", fmt.Errorf("value type assertion failed: %T %#v", secret.Data["password"], secret.Data["password"])}return value,nil}
package main
import("context""fmt""os" vault "github.com/hashicorp/vault/api" auth "github.com/hashicorp/vault/api/auth/gcp")// Fetches a key-value secret (kv-v2) after authenticating to Vault// via GCP IAM, one of two auth methods used to authenticate with// GCP (the other is GCE auth).funcgetSecretWithGCPAuthIAM()(string,error){ config := vault.DefaultConfig()// modify for more granular configuration client, err := vault.NewClient(config)if err !=nil{return"", fmt.Errorf("unable to initialize Vault client: %w", err)}// For IAM-style auth, the environment variable GOOGLE_APPLICATION_CREDENTIALS// must be set with the path to a valid credentials JSON file, otherwise// Vault will fall back to Google's default instance credentials.// Learn about authenticating to GCS with service account credentials at https://cloud.google.com/docs/authentication/productionif pathToCreds := os.Getenv("GOOGLE_APPLICATION_CREDENTIALS"); pathToCreds ==""{ fmt.Printf("WARNING: Environment variable GOOGLE_APPLICATION_CREDENTIALS was not set. IAM client for JWT signing and Vault server IAM client will both fall back to default instance credentials.\n")} svcAccountEmail := fmt.Sprintf("%s@%s.iam.gserviceaccount.com", os.Getenv("GCP_SERVICE_ACCOUNT_NAME"), os.Getenv("GOOGLE_CLOUD_PROJECT"))// We pass the auth.WithIAMAuth option to use the IAM-style authentication// of the GCP auth backend. Otherwise, we default to using GCE-style// authentication, which gets its credentials from the metadata server. gcpAuth, err := auth.NewGCPAuth("dev-role-iam", auth.WithIAMAuth(svcAccountEmail),)if err !=nil{return"", fmt.Errorf("unable to initialize GCP auth method: %w", err)} authInfo, err := client.Auth().Login(context.TODO(), gcpAuth)if err !=nil{return"", fmt.Errorf("unable to login to GCP auth method: %w", err)}if authInfo ==nil{return"", fmt.Errorf("login response did not return client token")}// get secret from the default mount path for KV v2 in dev mode, "secret" secret, err := client.KVv2("secret").Get(context.Background(),"creds")if err !=nil{return"", fmt.Errorf("unable to read secret: %w", err)}// data map can contain more than one key-value pair,// in this case we're just grabbing one of them value, ok := secret.Data["password"].(string)if!ok {return"", fmt.Errorf("value type assertion failed: %T %#v", secret.Data["password"], secret.Data["password"])}return value,nil}
usingSystem;usingSystem.Collections.Generic;usingSystem.IO;usingSystem.Threading.Tasks;usingGoogle.Apis.Auth.OAuth2;usingGoogle.Apis.Services;usingGoogle.Apis.Iam.v1;usingNewtonsoft.Json;usingVaultSharp;usingVaultSharp.V1.AuthMethods;usingVaultSharp.V1.AuthMethods.GoogleCloud;usingVaultSharp.V1.Commons;usingData=Google.Apis.Iam.v1.Data;namespaceExamples{publicclassGCPAuthExample{/// <summary>/// Fetches a key-value secret (kv-v2) after authenticating to Vault via GCP IAM,/// one of two auth methods used to authenticate with GCP (the other is GCE auth)./// </summary>publicstringGetSecretGcp(){var vaultAddr = Environment.GetEnvironmentVariable("VAULT_ADDR");if(String.IsNullOrEmpty(vaultAddr)){thrownewSystem.ArgumentNullException("Vault Address");}var roleName = Environment.GetEnvironmentVariable("VAULT_ROLE");if(String.IsNullOrEmpty(roleName)){thrownewSystem.ArgumentNullException("Vault Role Name");}// Learn about authenticating to GCS with service account credentials at https://cloud.google.com/docs/authentication/productionif(String.IsNullOrEmpty(Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS"))){
Console.WriteLine("WARNING: Environment variable GOOGLE_APPLICATION_CREDENTIALS was not set. IAM client for JWT signing will fall back to default instance credentials.");}var jwt =SignJWT();IAuthMethodInfo authMethod =newGoogleCloudAuthMethodInfo(roleName, jwt);var vaultClientSettings =newVaultClientSettings(vaultAddr, authMethod);IVaultClient vaultClient =newVaultClient(vaultClientSettings);// We can retrieve the secret after creating our VaultClient objectSecret<SecretData> kv2Secret =null;
kv2Secret = vaultClient.V1.Secrets.KeyValue.V2.ReadSecretAsync(path:"/creds").Result;var password = kv2Secret.Data.Data["password"];return password.ToString();}/// <summary>/// Generate signed JWT from GCP IAM/// </summary>privatestringSignJWT(){var roleName = Environment.GetEnvironmentVariable("GCP_ROLE");var svcAcctName = Environment.GetEnvironmentVariable("GCP_SERVICE_ACCOUNT_NAME");var gcpProjName = Environment.GetEnvironmentVariable("GOOGLE_CLOUD_PROJECT");IamService iamService =newIamService(newBaseClientService.Initializer{
HttpClientInitializer =GetCredential(),
ApplicationName ="Google-iamSample/0.1",});string svcEmail =$"{svcAcctName}@{gcpProjName}.iam.gserviceaccount.com";string name =$"projects/-/serviceAccounts/{svcEmail}";TimeSpan currentTime =(DateTime.UtcNow -newDateTime(1970,1,1));int expiration =(int)(currentTime.TotalSeconds)+900;Data.SignJwtRequest requestBody =newData.SignJwtRequest();
requestBody.Payload = JsonConvert.SerializeObject(newDictionary<string,object>(){{"aud",$"vault/{roleName}"},{"sub", svcEmail },{"exp", expiration }});ProjectsResource.ServiceAccountsResource.SignJwtRequest request = iamService.Projects.ServiceAccounts.SignJwt(requestBody, name);Data.SignJwtResponse response = request.Execute();return JsonConvert.SerializeObject(response.SignedJwt).Replace("\"","");}publicstaticGoogleCredentialGetCredential(){GoogleCredential credential = Task.Run(()=> GoogleCredential.GetApplicationDefaultAsync()).Result;if(credential.IsCreateScopedRequired){
credential = credential.CreateScoped("https://www.googleapis.com/auth/cloud-platform");}return credential;}}}
usingSystem;usingSystem.Collections.Generic;usingSystem.IO;usingSystem.Threading.Tasks;usingGoogle.Apis.Auth.OAuth2;usingGoogle.Apis.Services;usingGoogle.Apis.Iam.v1;usingNewtonsoft.Json;usingVaultSharp;usingVaultSharp.V1.AuthMethods;usingVaultSharp.V1.AuthMethods.GoogleCloud;usingVaultSharp.V1.Commons;usingData=Google.Apis.Iam.v1.Data;namespaceExamples{publicclassGCPAuthExample{/// <summary>/// Fetches a key-value secret (kv-v2) after authenticating to Vault via GCP IAM,/// one of two auth methods used to authenticate with GCP (the other is GCE auth)./// </summary>publicstringGetSecretGcp(){var vaultAddr = Environment.GetEnvironmentVariable("VAULT_ADDR");if(String.IsNullOrEmpty(vaultAddr)){thrownewSystem.ArgumentNullException("Vault Address");}var roleName = Environment.GetEnvironmentVariable("VAULT_ROLE");if(String.IsNullOrEmpty(roleName)){thrownewSystem.ArgumentNullException("Vault Role Name");}// Learn about authenticating to GCS with service account credentials at https://cloud.google.com/docs/authentication/productionif(String.IsNullOrEmpty(Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS"))){ Console.WriteLine("WARNING: Environment variable GOOGLE_APPLICATION_CREDENTIALS was not set. IAM client for JWT signing will fall back to default instance credentials.");}var jwt =SignJWT();IAuthMethodInfo authMethod =newGoogleCloudAuthMethodInfo(roleName, jwt);var vaultClientSettings =newVaultClientSettings(vaultAddr, authMethod);IVaultClient vaultClient =newVaultClient(vaultClientSettings);// We can retrieve the secret after creating our VaultClient objectSecret<SecretData> kv2Secret =null; kv2Secret = vaultClient.V1.Secrets.KeyValue.V2.ReadSecretAsync(path:"/creds").Result;var password = kv2Secret.Data.Data["password"];return password.ToString();}/// <summary>/// Generate signed JWT from GCP IAM/// </summary>privatestringSignJWT(){var roleName = Environment.GetEnvironmentVariable("GCP_ROLE");var svcAcctName = Environment.GetEnvironmentVariable("GCP_SERVICE_ACCOUNT_NAME");var gcpProjName = Environment.GetEnvironmentVariable("GOOGLE_CLOUD_PROJECT");IamService iamService =newIamService(newBaseClientService.Initializer{ HttpClientInitializer =GetCredential(), ApplicationName ="Google-iamSample/0.1",});string svcEmail =$"{svcAcctName}@{gcpProjName}.iam.gserviceaccount.com";string name =$"projects/-/serviceAccounts/{svcEmail}";TimeSpan currentTime =(DateTime.UtcNow -newDateTime(1970,1,1));int expiration =(int)(currentTime.TotalSeconds)+900;Data.SignJwtRequest requestBody =newData.SignJwtRequest(); requestBody.Payload = JsonConvert.SerializeObject(newDictionary<string,object>(){{"aud",$"vault/{roleName}"},{"sub", svcEmail },{"exp", expiration }});ProjectsResource.ServiceAccountsResource.SignJwtRequest request = iamService.Projects.ServiceAccounts.SignJwt(requestBody, name);Data.SignJwtResponse response = request.Execute();return JsonConvert.SerializeObject(response.SignedJwt).Replace("\"","");}publicstaticGoogleCredentialGetCredential(){GoogleCredential credential = Task.Run(()=> GoogleCredential.GetApplicationDefaultAsync()).Result;if(credential.IsCreateScopedRequired){ credential = credential.CreateScoped("https://www.googleapis.com/auth/cloud-platform");}return credential;}}}