From e62a924de7ddf96feed4a3f7649da4f1f5ac62ba Mon Sep 17 00:00:00 2001 From: srinandan <13950006+srinandan@users.noreply.github.com> Date: Tue, 17 Oct 2023 13:22:59 -0700 Subject: [PATCH 1/3] feat: adds support for GDAC #317 --- cmd/root.go | 27 ++++++++++++++++++++------- go.mod | 1 + go.sum | 2 ++ internal/apiclient/token.go | 17 +++++++++++++++++ 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index f53a52bc9..3069720fa 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -63,6 +63,12 @@ var RootCmd = &cobra.Command{ Short: "Utility to work with Apigee APIs.", Long: "This command lets you interact with Apigee APIs.", PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + if metadataToken && defaultToken { + return fmt.Errorf("metadata-token and default-token cannot be used together") + } + if defaultToken && (serviceAccount != "" || accessToken != "") { + return fmt.Errorf("default-token cannot be used with token or account flags") + } if metadataToken && (serviceAccount != "" || accessToken != "") { return fmt.Errorf("metadata-token cannot be used with token or account flags") } @@ -71,11 +77,6 @@ var RootCmd = &cobra.Command{ return fmt.Errorf("token and account flags cannot be used together") } - if !metadataToken { - apiclient.SetServiceAccount(serviceAccount) - apiclient.SetApigeeToken(accessToken) - } - if !disableCheck { if ok, _ := apiclient.TestAndUpdateLastCheck(); !ok { latestVersion, _ := getLatestVersion() @@ -88,7 +89,16 @@ var RootCmd = &cobra.Command{ } } + if !metadataToken && !defaultToken { + apiclient.SetServiceAccount(serviceAccount) + apiclient.SetApigeeToken(accessToken) + } + if metadataToken { + return apiclient.GetMetadataAccessToken() + } + + if defaultToken { return apiclient.GetDefaultAccessToken() } @@ -107,8 +117,8 @@ func Execute() { } var ( - accessToken, serviceAccount string - disableCheck, printOutput, noOutput, metadataToken bool + accessToken, serviceAccount string + disableCheck, printOutput, noOutput, metadataToken, defaultToken bool ) const ENABLED = "true" @@ -134,6 +144,9 @@ func init() { RootCmd.PersistentFlags().BoolVarP(&metadataToken, "metadata-token", "", false, "Metadata OAuth2 access token") + RootCmd.PersistentFlags().BoolVarP(&defaultToken, "default-token", "", + false, "Use Google defalt application credentials access token") + RootCmd.AddCommand(apis.Cmd) RootCmd.AddCommand(org.Cmd) RootCmd.AddCommand(sync.Cmd) diff --git a/go.mod b/go.mod index 9f2348ae7..fd41a131a 100644 --- a/go.mod +++ b/go.mod @@ -24,6 +24,7 @@ require ( ) require ( + cloud.google.com/go/compute/metadata v0.2.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/getkin/kin-openapi v0.115.0 // indirect diff --git a/go.sum b/go.sum index 6add6501c..4c3fe8616 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +cloud.google.com/go/compute/metadata v0.2.0 h1:nBbNSZyDpkNlo3DepaaLKVuO7ClyifSAmNloSCZrHnQ= +cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= diff --git a/internal/apiclient/token.go b/internal/apiclient/token.go index 7f9deecf4..c708b9b47 100644 --- a/internal/apiclient/token.go +++ b/internal/apiclient/token.go @@ -15,6 +15,7 @@ package apiclient import ( + "context" "crypto/x509" "encoding/json" "encoding/pem" @@ -33,6 +34,7 @@ import ( "github.com/lestrrat-go/jwx/v2/jwa" "github.com/lestrrat-go/jwx/v2/jwt" + "golang.org/x/oauth2/google" ) type serviceAccount struct { @@ -313,6 +315,21 @@ func getMetadata(metadata string) (respBpdy []byte, err error) { // GetDefaultAccessToken func GetDefaultAccessToken() (err error) { + ctx := context.Background() + tokenSource, err := google.DefaultTokenSource(ctx, "https://www.googleapis.com/auth/cloud-platform") + if err != nil { + return err + } + token, err := tokenSource.Token() + if err != nil { + return err + } + SetApigeeToken(token.AccessToken) + return nil +} + +// GetMetadataAccessToken +func GetMetadataAccessToken() (err error) { var tokenResponse map[string]interface{} respBody, err := getMetadata("token") From f6d72d4eb5243ac1f007c49a4a9fabee2b6752e2 Mon Sep 17 00:00:00 2001 From: srinandan <13950006+srinandan@users.noreply.github.com> Date: Tue, 17 Oct 2023 13:27:23 -0700 Subject: [PATCH 2/3] feat: adds readme for GDAC #317 --- README.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a6d358f9e..e69a8ab9a 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ curl -L https://raw.githubusercontent.com/apigee/apigeecli/main/downloadLatest.s ## Getting Started ### User Tokens + The simplest way to get started with `apigeecli` is ``` @@ -33,6 +34,15 @@ If you are using `apigeecli` on Cloud Shell, GCE instances, Cloud Build, then yo apigeecli orgs list --metadata-token ``` +### Google Default Application Credentials + +You can configure gcloud to setup/create default application credentials. These credentials can be used by `apigeecli`. + +```sh +gcloud auth application-default login +apigeecli orgs list --default-token +``` + ### Access Token Generation from Service Accounts `apigeecli` can use the service account directly and obtain an access token. @@ -57,17 +67,20 @@ apigeecli token cache -a serviceaccount.json ``` or + ```bash token=$(gcloud auth print-access-token) apigeecli token cache -t $token ``` or + ```bash apigeecli token cache --metadata-token ``` ## Set Preferences + If you are using the same GCP project for Apigee, then consider setting up preferences so they don't have to be included in every command. Preferences are written to the `$HOME/.apigeecli` folder ``` @@ -92,8 +105,8 @@ The following preferences can be set: | `-p, --proxy string` | Use http proxy before contacting the control plane | | `--nocheck` | Don't check for newer versions of cmd | - ## Container download + The lastest container version for apigeecli can be downloaded via ```sh @@ -156,6 +169,7 @@ The following environment variables may be set to control the behavior of `apige * `APIGEECLI_DRYRUN=true` does not execute Apigee control plane APIs ## Generating API Proxies + `apigeecli` can generate API proxies from: * OpenAPI 3.0 Specification @@ -196,7 +210,6 @@ components: is interpreted as OAuth-v20 (verification only) policy and the VerifyAPIKey policy. - These security schemes can be added to the PreFlow by enabling the scheme globally ```yaml @@ -381,6 +394,7 @@ C8gzi5q3xsycjI7if5FABk7bfciR4+g32H8xTl4mVHhHuz6I6FBG24/nuQ== cosign verify --key=cosign.pub ghcr.io/apigee/apigeecli:latest ``` + ___ ## Support From 979929a2e8d903106907f4547e9866a883db7ff7 Mon Sep 17 00:00:00 2001 From: srinandan <13950006+srinandan@users.noreply.github.com> Date: Tue, 17 Oct 2023 14:28:49 -0700 Subject: [PATCH 3/3] chore: add impersonation docs #317 --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index e69a8ab9a..b8ce034e2 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,13 @@ gcloud auth application-default login apigeecli orgs list --default-token ``` +or through impersonation + +```sh +gcloud auth application-default login --impersonate-service-account +apigeecli orgs list --default-token +``` + ### Access Token Generation from Service Accounts `apigeecli` can use the service account directly and obtain an access token.