Open6
Google Admin API の Go クライントの利用は SA の JSON Key 必須であるかの調査
Google Admin API は Subject を上書きして impersonate する必要があり、しばらく前は以下の形で google.config を生成後に Subject を上書きするため GOOGLE_APPLICATION_CREDENTIALS
で使われる Service Account の JSON Key を利用(GAE や Run の場合は Secret Manager から JSON を取得)する必要があった。
SA Key への依存をなくせるかの再調査を行う。
import (
"context"
"fmt"
"golang.org/x/oauth2/google"
admin "google.golang.org/api/admin/directory/v1"
"google.golang.org/api/googleapi"
"google.golang.org/api/option"
)
...
jsonCredentials, _ := ioutil.ReadFile(os.Getenv("GOOGLE_APPLICATION_CREDENTIALS"))
config, _ := google.JWTConfigFromJSON(jsonCredentials, scopes...)
config.Subject = userEmail // impersonating
ts := config.TokenSource(ctx)
srv, _ := admin.NewService(ctx, option.WithTokenSource(ts))
srv.Groups.List()
以下の形で途中で config を挟まなくても Subject の上書きが可能になっている。
// "golang.org/x/oauth2/google"
credentials, err := google.FindDefaultCredentialsWithParams(ctx, google.CredentialsParams{
Scopes: scopes,
Subject: subject,
})
srv, err := admin.NewService(ctx, option.WithCredentials(credentials))
ローカルの場合は CredentialsParams が仕事をするが、Cloud Run や GCE 環境の場合は params の Subject は利用されていないため FindDefaultCredentialsWithParams を用いる形では通用しない、、、
func FindDefaultCredentialsWithParams(ctx context.Context, params CredentialsParams) (*Credentials, error) {
const envVar = "GOOGLE_APPLICATION_CREDENTIALS"
if filename := os.Getenv(envVar); filename != "" {// ローカル
creds, err := readCredentialsFile(ctx, filename, params)
if err != nil {
return nil, fmt.Errorf("google: error getting credentials using %v environment variable: %v", envVar, err)
}
return creds, nil
}
......
// Fourth, if we're on Google Compute Engine, an App Engine standard second generation runtime,
// or App Engine flexible, use the metadata server.
if metadata.OnGCE() { // Cloud Run の場合
id, _ := metadata.ProjectID()
return &DefaultCredentials{
ProjectID: id,
TokenSource: ComputeTokenSource("", params.Scopes...),
}, nil
}
Python だと上手くやっていそう
jwt.Config は基本的に File からしか作れない。直接作るにしても SecretKey などはファイルにある
func (f *credentialsFile) jwtConfig(scopes []string, subject string) *jwt.Config {
CredentialsConfig の Subject を与えたものを試したが権限で落ちた。SA に Service Account Token Creator
を与えるだけで良いと思ったがなにか足りない?
Failed to list group: Get "https://admin.googleapis.com/admin/directory/v1/groups?alt=json&domain=***&prettyPrint=false": impersonate: unable to sign JWT: Post "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/SA:signJwt": oauth2: cannot fetch token: 401 Unauthorized
Response: {
"error": "unauthorized_client",
"error_description": "Client is unauthorized to retrieve access tokens using this method, or client not authorized for any of the scopes requested."
}