From f6308e6789b5952f8f9141b12bd8e93b95fb836f Mon Sep 17 00:00:00 2001 From: Joseph Stevens Date: Sat, 12 Oct 2024 16:45:18 -0700 Subject: [PATCH] enable standard forms of GCP auth for oci sources --- oci/auth/gcp/auth.go | 54 +++++++++++++------------------------------- oci/go.mod | 3 ++- oci/go.sum | 6 +++++ 3 files changed, 24 insertions(+), 39 deletions(-) diff --git a/oci/auth/gcp/auth.go b/oci/auth/gcp/auth.go index 584f0b25..4e017a53 100644 --- a/oci/auth/gcp/auth.go +++ b/oci/auth/gcp/auth.go @@ -18,10 +18,7 @@ package gcp import ( "context" - "encoding/json" "fmt" - "io" - "net/http" "net/url" "strings" "time" @@ -31,6 +28,7 @@ import ( "github.com/google/go-containerregistry/pkg/name" "github.com/fluxcd/pkg/oci" + "golang.org/x/oauth2/google" ) type gceToken struct { @@ -79,54 +77,34 @@ func (c *Client) WithTokenURL(url string) *Client { return c } -// getLoginAuth obtains authentication by getting a token from the metadata API -// on GCP. This assumes that the pod has right to pull the image which would be -// the case if it is hosted on GCP. It works with both service account and -// workload identity enabled clusters. +// getLoginAuth obtains authentication using the default GCP credential chain. +// This supports various authentication methods including service account JSON, +// external account JSON, user credentials, and GCE metadata service. func (c *Client) getLoginAuth(ctx context.Context) (authn.AuthConfig, time.Time, error) { var authConfig authn.AuthConfig - request, err := http.NewRequestWithContext(ctx, http.MethodGet, c.tokenURL, nil) - if err != nil { - return authConfig, time.Time{}, err - } - - request.Header.Add("Metadata-Flavor", "Google") - - var transport http.RoundTripper - if c.proxyURL != nil { - t := http.DefaultTransport.(*http.Transport).Clone() - t.Proxy = http.ProxyURL(c.proxyURL) - transport = t - } + // Define the required scopes for accessing GCR. + scopes := []string{"https://www.googleapis.com/auth/cloud-platform"} - client := &http.Client{Transport: transport} - response, err := client.Do(request) + // Obtain the default token source. + tokenSource, err := google.DefaultTokenSource(ctx, scopes...) if err != nil { - return authConfig, time.Time{}, err + return authConfig, time.Time{}, fmt.Errorf("failed to get default token source: %w", err) } - defer response.Body.Close() - defer io.Copy(io.Discard, response.Body) - if response.StatusCode != http.StatusOK { - return authConfig, time.Time{}, fmt.Errorf("unexpected status from metadata service: %s", response.Status) - } - - var accessToken gceToken - decoder := json.NewDecoder(response.Body) - if err := decoder.Decode(&accessToken); err != nil { - return authConfig, time.Time{}, err + // Retrieve the token. + token, err := tokenSource.Token() + if err != nil { + return authConfig, time.Time{}, fmt.Errorf("failed to obtain token: %w", err) } + // Set up the authentication configuration. authConfig = authn.AuthConfig{ Username: "oauth2accesstoken", - Password: accessToken.AccessToken, + Password: token.AccessToken, } - // add expiresIn seconds to the current time to get the expiry time - expiresAt := time.Now().Add(time.Duration(accessToken.ExpiresIn) * time.Second) - - return authConfig, expiresAt, nil + return authConfig, token.Expiry, nil } // Login attempts to get the authentication material for GCR. diff --git a/oci/go.mod b/oci/go.mod index 8cc1706f..15121763 100644 --- a/oci/go.mod +++ b/oci/go.mod @@ -29,6 +29,7 @@ require ( ) require ( + cloud.google.com/go/compute/metadata v0.3.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.13 // indirect @@ -136,7 +137,7 @@ require ( go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect golang.org/x/crypto v0.27.0 // indirect golang.org/x/net v0.29.0 // indirect - golang.org/x/oauth2 v0.22.0 // indirect + golang.org/x/oauth2 v0.23.0 // indirect golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.25.0 // indirect golang.org/x/term v0.24.0 // indirect diff --git a/oci/go.sum b/oci/go.sum index 7ac23d2f..080a8fbe 100644 --- a/oci/go.sum +++ b/oci/go.sum @@ -1,4 +1,8 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.110.7 h1:rJyC7nWRg2jWGZ4wSJ5nY65GTdYJkg0cd/uXb+ACI6o= +cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= +cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= +cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 h1:nyQWyZvwGTvunIMxi1Y9uXkcyr+I7TeNrr/foo4Kpk8= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0/go.mod h1:l38EPgmsp71HHLq9j7De57JcKOWPyhrsW1Awm1JS6K0= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 h1:tfLQ34V6F7tVSwoTf/4lH5sE0o6eCJuNDTmH09nDpbc= @@ -408,6 +412,8 @@ golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=