diff --git a/pkg/mirror/mirror.go b/pkg/mirror/mirror.go index 30ad287..a821f20 100644 --- a/pkg/mirror/mirror.go +++ b/pkg/mirror/mirror.go @@ -5,15 +5,12 @@ import ( "log" "os" - ecr "github.com/awslabs/amazon-ecr-credential-helper/ecr-login" - acr "github.com/chrismellard/docker-credential-acr-env/pkg/credhelper" "github.com/docker/attest/internal/embed" + "github.com/docker/attest/pkg/oci" "github.com/docker/attest/pkg/tuf" - "github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/empty" - "github.com/google/go-containerregistry/pkg/v1/google" "github.com/google/go-containerregistry/pkg/v1/layout" "github.com/google/go-containerregistry/pkg/v1/remote" ) @@ -34,15 +31,9 @@ func PushImageToRegistry(image v1.Image, imageName string) error { if err != nil { log.Fatalf("Failed to parse image name: %v", err) } - // Create a multi-keychain that will use the default Docker, Google, ECR or ACR keychain - keychain := authn.NewMultiKeychain( - authn.DefaultKeychain, - google.Keychain, - authn.NewKeychainFromHelper(ecr.NewECRHelper()), - authn.NewKeychainFromHelper(acr.NewACRCredentialsHelper()), - ) + // Push the image to the registry - return remote.Write(ref, image, remote.WithAuthFromKeychain(keychain)) + return remote.Write(ref, image, oci.MultiKeychainOption()) } func PushIndexToRegistry(image v1.ImageIndex, imageName string) error { @@ -51,15 +42,8 @@ func PushIndexToRegistry(image v1.ImageIndex, imageName string) error { if err != nil { log.Fatalf("Failed to parse image name: %v", err) } - // Create a multi-keychain that will use the default Docker, Google, ECR or ACR keychain - keychain := authn.NewMultiKeychain( - authn.DefaultKeychain, - google.Keychain, - authn.NewKeychainFromHelper(ecr.NewECRHelper()), - authn.NewKeychainFromHelper(acr.NewACRCredentialsHelper()), - ) // Push the index to the registry - return remote.WriteIndex(ref, image, remote.WithAuthFromKeychain(keychain)) + return remote.WriteIndex(ref, image, oci.MultiKeychainOption()) } func SaveImageAsOCILayout(image v1.Image, path string) error { diff --git a/pkg/oci/authn.go b/pkg/oci/authn.go new file mode 100644 index 0000000..0c7457a --- /dev/null +++ b/pkg/oci/authn.go @@ -0,0 +1,23 @@ +package oci + +import ( + ecr "github.com/awslabs/amazon-ecr-credential-helper/ecr-login" + acr "github.com/chrismellard/docker-credential-acr-env/pkg/credhelper" + "github.com/google/go-containerregistry/pkg/authn" + "github.com/google/go-containerregistry/pkg/v1/google" + "github.com/google/go-containerregistry/pkg/v1/remote" +) + +func MultiKeychainOption() remote.Option { + return remote.WithAuthFromKeychain(MultiKeychainAll()) +} + +func MultiKeychainAll() authn.Keychain { + // Create a multi-keychain that will use the default Docker, Google, ECR or ACR keychain + return authn.NewMultiKeychain( + authn.DefaultKeychain, + google.Keychain, + authn.NewKeychainFromHelper(ecr.NewECRHelper()), + authn.NewKeychainFromHelper(acr.NewACRCredentialsHelper()), + ) +} diff --git a/pkg/oci/oci.go b/pkg/oci/oci.go index 73c89e7..a1b72fa 100644 --- a/pkg/oci/oci.go +++ b/pkg/oci/oci.go @@ -6,15 +6,11 @@ import ( "fmt" "strings" - ecr "github.com/awslabs/amazon-ecr-credential-helper/ecr-login" - acr "github.com/chrismellard/docker-credential-acr-env/pkg/credhelper" "github.com/containerd/containerd/platforms" "github.com/distribution/reference" att "github.com/docker/attest/pkg/attestation" - "github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" - "github.com/google/go-containerregistry/pkg/v1/google" "github.com/google/go-containerregistry/pkg/v1/layout" "github.com/google/go-containerregistry/pkg/v1/remote" "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common" @@ -245,6 +241,9 @@ func (r *ReferrersResolver) resolveAttestations(ctx context.Context) error { return fmt.Errorf("failed to parse reference: %w", err) } subjectDigest, err := r.ImageDigest(ctx) + if err != nil { + return fmt.Errorf("failed to get image digest: %w", err) + } var referrersSubjectRef name.Digest if r.referrersRepo != "" { @@ -459,14 +458,7 @@ func FetchAttestationManifest(ctx context.Context, image string, platform *v1.Pl func WithOptions(ctx context.Context, platform *v1.Platform) []remote.Option { // prepare options - // Create a multi-keychain that will use the default Docker, Google, ECR or ACR keychain - keychain := authn.NewMultiKeychain( - authn.DefaultKeychain, - google.Keychain, - authn.NewKeychainFromHelper(ecr.NewECRHelper()), - authn.NewKeychainFromHelper(acr.NewACRCredentialsHelper()), - ) - options := []remote.Option{remote.WithAuthFromKeychain(keychain), remote.WithTransport(HttpTransport()), remote.WithContext(ctx)} + options := []remote.Option{MultiKeychainOption(), remote.WithTransport(HttpTransport()), remote.WithContext(ctx)} // add in platform into remote Get operation; this might conflict with an explicit digest, but we are trying anyway if platform != nil { diff --git a/pkg/oci/types.go b/pkg/oci/types.go index 02b673e..af7407a 100644 --- a/pkg/oci/types.go +++ b/pkg/oci/types.go @@ -4,12 +4,8 @@ import ( "fmt" "log" - ecr "github.com/awslabs/amazon-ecr-credential-helper/ecr-login" - acr "github.com/chrismellard/docker-credential-acr-env/pkg/credhelper" - "github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" - "github.com/google/go-containerregistry/pkg/v1/google" "github.com/google/go-containerregistry/pkg/v1/layout" "github.com/google/go-containerregistry/pkg/v1/remote" ) @@ -53,15 +49,8 @@ func SubjectIndexFromRemote(image string) (*SubjectIndex, error) { if err != nil { log.Fatalf("Failed to parse image name: %v", err) } - // Create a multi-keychain that will use the default Docker, Google, ECR or ACR keychain - keychain := authn.NewMultiKeychain( - authn.DefaultKeychain, - google.Keychain, - authn.NewKeychainFromHelper(ecr.NewECRHelper()), - authn.NewKeychainFromHelper(acr.NewACRCredentialsHelper()), - ) // Pull the image from the registry - idx, err := remote.Index(ref, remote.WithAuthFromKeychain(keychain)) + idx, err := remote.Index(ref, MultiKeychainOption()) if err != nil { return nil, fmt.Errorf("failed to pull image %s: %w", image, err) } diff --git a/pkg/tuf/registry.go b/pkg/tuf/registry.go index 6a4520a..3aad2bd 100644 --- a/pkg/tuf/registry.go +++ b/pkg/tuf/registry.go @@ -10,12 +10,10 @@ import ( "strings" "time" - ecr "github.com/awslabs/amazon-ecr-credential-helper/ecr-login" - acr "github.com/chrismellard/docker-credential-acr-env/pkg/credhelper" + "github.com/docker/attest/pkg/oci" "github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/crane" v1 "github.com/google/go-containerregistry/pkg/v1" - "github.com/google/go-containerregistry/pkg/v1/google" "github.com/google/go-containerregistry/pkg/v1/types" "github.com/theupdateframework/go-tuf/v2/metadata" ) @@ -121,20 +119,13 @@ func (d *RegistryFetcher) getManifest(ref string) ([]byte, error) { var err error var found bool var mf []byte - // Create a multi-keychain that will use the default Docker, Google, ECR or ACR keychain - keychain := authn.NewMultiKeychain( - authn.DefaultKeychain, - google.Keychain, - authn.NewKeychainFromHelper(ecr.NewECRHelper()), - authn.NewKeychainFromHelper(acr.NewACRCredentialsHelper()), - ) // Check cache for manifest and only pull if not found if mf, found = d.cache.Get(ref); !found { mf, err = crane.Manifest(ref, crane.WithUserAgent(d.httpUserAgent), crane.WithTransport(transportWithTimeout(d.timeout)), crane.WithAuth(authn.Anonymous), - crane.WithAuthFromKeychain(keychain)) + crane.WithAuthFromKeychain(oci.MultiKeychainAll())) if err != nil { return nil, err } @@ -154,7 +145,7 @@ func (d *RegistryFetcher) pullFileLayer(ref string, maxLength int64) ([]byte, er crane.WithUserAgent(d.httpUserAgent), crane.WithTransport(transportWithTimeout(d.timeout)), crane.WithAuth(authn.Anonymous), - crane.WithAuthFromKeychain(authn.DefaultKeychain)) + crane.WithAuthFromKeychain(oci.MultiKeychainAll())) if err != nil { return nil, err } diff --git a/pkg/tuf/registry_test.go b/pkg/tuf/registry_test.go index 7facd7a..31787b7 100644 --- a/pkg/tuf/registry_test.go +++ b/pkg/tuf/registry_test.go @@ -9,16 +9,13 @@ import ( "strings" "testing" - ecr "github.com/awslabs/amazon-ecr-credential-helper/ecr-login" - acr "github.com/chrismellard/docker-credential-acr-env/pkg/credhelper" "github.com/docker/attest/internal/embed" "github.com/docker/attest/internal/util" - "github.com/google/go-containerregistry/pkg/authn" + "github.com/docker/attest/pkg/oci" "github.com/google/go-containerregistry/pkg/crane" "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/empty" - "github.com/google/go-containerregistry/pkg/v1/google" "github.com/google/go-containerregistry/pkg/v1/layout" "github.com/google/go-containerregistry/pkg/v1/mutate" "github.com/google/go-containerregistry/pkg/v1/remote" @@ -371,22 +368,14 @@ func LoadRegistryTestData(t *testing.T, registry *url.URL, path string) { TARGETS_REPO := "tuf-targets" DELEGATED_ROLE := "test-role" - // Create a multi-keychain that will use the default Docker, Google, ECR or ACR keychain - keychain := authn.NewMultiKeychain( - authn.DefaultKeychain, - google.Keychain, - authn.NewKeychainFromHelper(ecr.NewECRHelper()), - authn.NewKeychainFromHelper(acr.NewACRCredentialsHelper()), - ) - // push top-level metadata -> metadata:latest - err := LoadMetadata(filepath.Join(path, "metadata"), registry.Host, METADATA_REPO, METADATA_TAG, keychain) + err := LoadMetadata(filepath.Join(path, "metadata"), registry.Host, METADATA_REPO, METADATA_TAG) if err != nil { t.Fatal(err) } // push delegated metadata -> metadata: - err = LoadMetadata(filepath.Join(path, "metadata", DELEGATED_ROLE), registry.Host, METADATA_REPO, DELEGATED_ROLE, keychain) + err = LoadMetadata(filepath.Join(path, "metadata", DELEGATED_ROLE), registry.Host, METADATA_REPO, DELEGATED_ROLE) if err != nil { t.Fatal(err) } @@ -418,13 +407,13 @@ func LoadRegistryTestData(t *testing.T, registry *url.URL, path string) { if err != nil { t.Fatal(err) } - err = remote.Write(ref, img, remote.WithAuthFromKeychain(keychain)) + err = remote.Write(ref, img, oci.MultiKeychainOption()) if err != nil { t.Fatal(err) } } else if len(mf.Manifests) > 1 { // delegated target - err = remote.WriteIndex(ref, tIdx, remote.WithAuthFromKeychain(keychain)) + err = remote.WriteIndex(ref, tIdx, oci.MultiKeychainOption()) if err != nil { t.Fatal(err) } @@ -435,7 +424,7 @@ func LoadRegistryTestData(t *testing.T, registry *url.URL, path string) { } // LoadMetadata loads TUF metadata from a local path and pushes to a registry -func LoadMetadata(path, host, repo, tag string, keychain authn.Keychain) error { +func LoadMetadata(path, host, repo, tag string) error { mIdx, err := layout.ImageIndexFromPath(path) if err != nil { return err @@ -452,5 +441,5 @@ func LoadMetadata(path, host, repo, tag string, keychain authn.Keychain) error { if err != nil { return err } - return remote.Write(ref, img, remote.WithAuthFromKeychain(keychain)) + return remote.Write(ref, img, oci.MultiKeychainOption()) }