HashiCorp Vault is a popular open source tool for secret management, which allows a developer to store, manage and control access to tokens, passwords, certificates, API keys and other secrets. Vault has many options for authentication, called authentication backends. These allow developers to use many kinds of identities to access Vault, including tokens, or usernames and passwords. As the number of developers on a team grows, these kinds of authentication options become impractical; and in enterprise scenarios, managing and auditing these identities becomes burdensome.
Today, we are pleased to announce a Google Cloud Platform IAM authentication backend for Vault. This allows a developer to use an existing IAM identity to authenticate to Vault. Using a service account, you can sign a JWT to show it came from a particular account, and use that to authenticate to Vault. Learn more in the documentation.
The following example in Go shows how a user can authenticate with Vault using this backend. This example assumes the Vault server has already been mounted at auth/gcp and configured.
package main import ( ... vaultapi "github.com/hashicorp/vault/api" "golang.org/x/oauth2" "golang.org/x/oauth2/google" "google.golang.org/api/iam/v1" ... ) func main() { // Start [PARAMS] project := "project-123456" serviceAccount := "[email protected]" credsPath := "path/to/creds.json" os.Setenv("VAULT_ADDR", "https://vault.mycompany.com") defer os.Setenv("VAULT_ADDR", "") // End [PARAMS] // Start [GCP IAM Setup] jsonBytes, err := ioutil.ReadFile(credsPath) if err != nil { log.Fatal(err) } config, err := google.JWTConfigFromJSON(jsonBytes, iam.CloudPlatformScope) if err != nil { log.Fatal(err) } httpClient := config.Client(oauth2.NoContext) iamClient, err := iam.New(httpClient) if err != nil { log.Fatal(err) } // End [GCP IAM Setup] // 1. Generate signed JWT using IAM. resourceName := fmt.Sprintf("projects/%s/serviceAccounts/%s", project, serviceAccount) jwtPayload := map[string]interface{}{ "aud": "auth/gcp/login", "sub": serviceAccount, "exp": time.Now().Add(time.Minute * 10).Unix(), } payloadBytes, err := json.Marshal(jwtPayload) if err != nil { log.Fatal(err) } signJwtReq := &iam.SignJwtRequest{ Payload: string(payloadBytes), } resp, err := iamClient.Projects.ServiceAccounts.SignJwt( resourceName, signJwtReq).Do() if err != nil { log.Fatal(err) } // 2. Send signed JWT in login request to Vault. vaultClient, err := vaultapi.NewClient(vaultapi.DefaultConfig()) if err != nil { log.Fatal(err) } vaultResp, err := vaultClient.Logical().Write( "auth/gcp/login", map[string]interface{}{ "role": "test", "jwt": resp.SignedJwt, }) if err != nil { log.Fatal(err) } // 3. Use auth token from response. log.Println("Access token %s", vaultResp.Auth.ClientToken) vaultClient.SetToken(vaultResp.Auth.ClientToken) // ... }
Vault is just one way of managing secrets in development. For further reading on choosing a solution that’s right for you, see Google Cloud Platform’s documentation on Secret Management.
By Emily Ye, Software Engineer