diff --git a/auth/ggcr/keychain.go b/auth/ggcr/keychain.go new file mode 100644 index 0000000..f1cdc30 --- /dev/null +++ b/auth/ggcr/keychain.go @@ -0,0 +1,61 @@ +/* +Copyright 2024 Chainguard, Inc. +SPDX-License-Identifier: Apache-2.0 +*/ + +// Package ggcr provides a go-containerregistry authn.Keychain for the cgr.dev registry. +package ggcr + +import ( + "context" + "fmt" + + "chainguard.dev/sdk/sts" + "github.com/google/go-containerregistry/pkg/authn" + "golang.org/x/oauth2" +) + +const issuer = "https://issuer.enforce.dev" + +// Keychain returns an authn.Keychain used to authorize requests to the cgr.dev registry using go-containerregistry. +// +// It takes the identity UIDP to assume, and a token source to obtain the token to exchange. +// +// This can be used with google.golang.org/api/idtoken.NewTokenSource to exchange ambient GCP credentials for Chainguard tokens: +// +// ts, err := idtoken.NewTokenSource(ctx, "https://cgr.dev") +// kc := ggcr.Keychain("my-identity", ts) +// +// This keychain can then be used to pull images from the cgr.dev registry: +// +// img, err := remote.Image("cgr.dev/my/image", remote.WithAuth(kc)) +func Keychain(identity string, ts oauth2.TokenSource) authn.Keychain { + return cgKeychain{identity, ts} +} + +type cgKeychain struct { + identity string + ts oauth2.TokenSource +} + +func (k cgKeychain) Resolve(res authn.Resource) (authn.Authenticator, error) { + if res.RegistryStr() != "cgr.dev" { + return authn.Anonymous, nil + } + + ctx := context.Background() + exch := sts.New(issuer, res.RegistryStr(), sts.WithIdentity(k.identity)) + + tok, err := k.ts.Token() + if err != nil { + return nil, fmt.Errorf("getting token: %w", err) + } + cgtok, err := exch.Exchange(ctx, tok.AccessToken) + if err != nil { + return nil, fmt.Errorf("exchanging token: %w", err) + } + return &authn.Basic{ + Username: "_token", + Password: cgtok.AccessToken, + }, nil +} diff --git a/go.mod b/go.mod index 3dee895..2bb1dbd 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module chainguard.dev/sdk go 1.23.2 require ( - chainguard.dev/apko v0.19.6 + chainguard.dev/apko v0.19.7 chainguard.dev/go-grpc-kit v0.17.6 chainguard.dev/go-oidctest v0.3.1 cloud.google.com/go/compute/metadata v0.5.2 @@ -14,6 +14,7 @@ require ( github.com/coreos/go-oidc/v3 v3.11.0 github.com/go-jose/go-jose/v3 v3.0.3 github.com/google/go-cmp v0.6.0 + github.com/google/go-containerregistry v0.20.2 github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 github.com/microcosm-cc/bluemonday v1.0.27 github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c @@ -42,6 +43,8 @@ require ( github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cloudflare/circl v1.3.7 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect + github.com/docker/cli v27.1.1+incompatible // indirect + github.com/docker/docker-credential-helpers v0.8.0 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect @@ -51,7 +54,6 @@ require ( github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/google/go-containerregistry v0.20.2 // indirect github.com/google/s2a-go v0.1.8 // indirect github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect @@ -62,10 +64,13 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/kelseyhightower/envconfig v1.4.0 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.20.5 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.60.0 // indirect @@ -73,6 +78,7 @@ require ( github.com/rogpeppe/go-internal v1.13.1 // indirect github.com/segmentio/ksuid v1.0.4 // indirect github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect github.com/skeema/knownhosts v1.2.2 // indirect github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect diff --git a/go.sum b/go.sum index d6e4e91..d7188cf 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -chainguard.dev/apko v0.19.6 h1:ZlWL5csihT4kBZmACpNOGqbb7DgqUS2IdmcNsnjwG18= -chainguard.dev/apko v0.19.6/go.mod h1:Xwby6unVOg4xJZ11l2kyHdr9sykJmmEaWvgoT18CFbI= +chainguard.dev/apko v0.19.7 h1:5NBSzI3YjrDGunNbpFiAbMk1HS+3oPRiV3e3unQyLtA= +chainguard.dev/apko v0.19.7/go.mod h1:Xwby6unVOg4xJZ11l2kyHdr9sykJmmEaWvgoT18CFbI= chainguard.dev/go-grpc-kit v0.17.6 h1:lwIs9LmSnm8jwrH1QmigCwMP6MYkIBENq/0xGduYZss= chainguard.dev/go-grpc-kit v0.17.6/go.mod h1:ZNaXn2KEO++2u2WveHs65krYiHmAEGjYLeEtfaQaOWU= chainguard.dev/go-oidctest v0.3.1 h1:Q1OvIVIcl+i0hqgmrXZLeDhSjtDjbnLEBASoTbhyuBY= @@ -56,6 +56,10 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/docker/cli v27.1.1+incompatible h1:goaZxOqs4QKxznZjjBWKONQci/MywhtRv2oNn0GkeZE= +github.com/docker/cli v27.1.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/docker-credential-helpers v0.8.0 h1:YQFtbBQb4VrpoPxhFuzEBPQ9E16qz5SpHLS+uswaCp8= +github.com/docker/docker-credential-helpers v0.8.0/go.mod h1:UGFXcuoQ5TxPiB54nHOZ32AWRqQdECoh/Mg0AlEYb40= github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= @@ -162,6 +166,8 @@ github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -171,6 +177,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= @@ -427,6 +435,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= +gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=