Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion iterative/gcp/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,27 @@ func getProjectService() (string, *gcp_compute.Service, error) {
}

if credentials.ProjectID == "" {
return "", nil, errors.New("Couldn't extract the project identifier from the given credentials!")
// Coerce Credentials to handle GCP OIDC auth
// Common ProjectID ENVs:
// https://github.com/google-github-actions/auth/blob/b05f71482f54380997bcc43a29ef5007de7789b1/src/main.ts#L187-L191
// https://github.com/hashicorp/terraform-provider-google/blob/d6734812e2c6a679334dcb46932f4b92729fa98c/google/provider.go#L64-L73
coercedProjectID := utils.MultiEnvLoadFirst([]string{
"CLOUDSDK_CORE_PROJECT",
"CLOUDSDK_PROJECT",
"GCLOUD_PROJECT",
"GCP_PROJECT",
"GOOGLE_CLOUD_PROJECT",
"GOOGLE_PROJECT",
})
if coercedProjectID == "" {
// last effort to load
fromCredentialsID, err := utils.GCPCoerceOIDCCredentials(credentials.JSON)
if err != nil {
return "", nil, fmt.Errorf("Couldn't extract the project identifier from the given credentials!: [%w]", err)
}
coercedProjectID = fromCredentialsID
}
credentials.ProjectID = coercedProjectID
}

os.Setenv("GOOGLE_APPLICATION_CREDENTIALS_DATA", string(credentials.JSON))
Expand Down
34 changes: 34 additions & 0 deletions iterative/utils/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package utils

import (
"context"
"encoding/json"
"errors"
"fmt"
"os"
"strings"
Expand Down Expand Up @@ -89,6 +91,38 @@ func SetId(d *schema.ResourceData) {
}
}

func MultiEnvLoadFirst(envs []string) string {
for _, val := range envs {
if env_value := os.Getenv(val); env_value != "" {
return env_value
}
}
return ""
}

func GCPCoerceOIDCCredentials(rawCreds []byte) (string, error) {
hack := make(map[string]interface{})
err := json.Unmarshal(rawCreds, &hack)
if err != nil {
return "", err
}
saString := fmt.Sprint(hack["service_account_impersonation_url"])
// saString example: "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/[email protected]:generateAccessToken"
if saString == "" {
return "", errors.New("[GCP OIDC] Unable to load service_account_impersonation_url")
}
// from saString, yank this
// -----------------------v.........v----------------------
// (...serviceAccounts/[email protected]:...)
atIndex := strings.Index(saString, "@") + 1
iamIndex := strings.Index(saString, ".iam.")
if atIndex == -1 || iamIndex == -1 {
return "", errors.New("[GCP OIDC] Failed to get Project ID from service_account_impersonation_url")
}
projectID := saString[atIndex:iamIndex]
return projectID, nil
}

func LoadGCPCredentials() string {
credentialsData := os.Getenv("GOOGLE_APPLICATION_CREDENTIALS_DATA")
if len(credentialsData) == 0 {
Expand Down