ggcr

package
v0.1.379 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 15, 2026 License: Apache-2.0 Imports: 5 Imported by: 0

Documentation

Overview

Package ggcr provides authentication integration between Chainguard identity tokens and the go-containerregistry library for accessing the cgr.dev container registry.

Overview

This package implements the authn.Keychain interface from go-containerregistry, enabling seamless authentication to cgr.dev using Chainguard identity tokens. It handles the token exchange flow using STS (Security Token Service) to convert base tokens into Chainguard-specific access tokens.

Features

  • authn.Keychain implementation for cgr.dev registry authentication
  • Automatic token exchange using Chainguard STS
  • Support for any OAuth2 token source as the base credential
  • Token reuse to minimize exchange operations
  • Registry-aware authentication (only authenticates for cgr.dev)

Usage

The primary entry point is the Keychain function, which creates a keychain from an identity UIDP and a base token source:

import (
	"context"

	"chainguard.dev/sdk/auth/ggcr"
	"github.com/google/go-containerregistry/pkg/name"
	"github.com/google/go-containerregistry/pkg/v1/remote"
	"google.golang.org/api/idtoken"
)

func pullImage(ctx context.Context, identity string) error {
	// Create a token source using ambient GCP credentials
	ts, err := idtoken.NewTokenSource(ctx, "https://cgr.dev")
	if err != nil {
		return err
	}

	// Create the keychain for the specified identity
	kc := ggcr.Keychain(identity, ts)

	// Use the keychain to pull images
	ref, err := name.ParseReference("cgr.dev/my/image:latest")
	if err != nil {
		return err
	}
	img, err := remote.Image(ref, remote.WithAuthFromKeychain(kc))
	if err != nil {
		return err
	}

	// Work with the image...
	return nil
}

Integration Patterns

The package integrates with go-containerregistry's remote operations:

  • remote.Image: Pull container images
  • remote.Write: Push container images
  • remote.Index: Pull multi-platform image indexes
  • remote.Layer: Pull individual layers

All remote operations accept the keychain via remote.WithAuthFromKeychain(kc).

For advanced use cases where you already have an OAuth2 token source configured with the complete token exchange flow, use TokenSourceKeychain directly:

kc := ggcr.TokenSourceKeychain(myConfiguredTokenSource)

Authentication Flow

The authentication flow works as follows:

  1. Base token source provides an initial token (e.g., GCP ID token)
  2. STS exchanges the base token for a Chainguard access token
  3. Token is cached and reused until expiration
  4. Keychain provides the token to go-containerregistry as HTTP Basic auth
  5. Registry validates the token and grants access

The keychain only provides credentials when the target registry is cgr.dev. For other registries, it returns anonymous authentication, allowing go-containerregistry to fall back to other authentication methods.

Package ggcr provides a go-containerregistry authn.Keychain for the cgr.dev registry.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Keychain

func Keychain(identity string, base oauth2.TokenSource) authn.Keychain

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))
Example

ExampleKeychain demonstrates how to create a keychain for authenticating to cgr.dev using a Chainguard identity and a base token source.

package main

import (
	"context"
	"fmt"

	"chainguard.dev/sdk/auth/ggcr"
	"github.com/chainguard-dev/clog"
	"github.com/google/go-containerregistry/pkg/name"
	"github.com/google/go-containerregistry/pkg/v1/remote"
	"google.golang.org/api/idtoken"
)

func main() {
	ctx := context.Background()

	// Create a token source using ambient GCP credentials
	ts, err := idtoken.NewTokenSource(ctx, "https://cgr.dev")
	if err != nil {
		clog.FatalContextf(ctx, "%v", err)
	}

	// Create the keychain for a specific Chainguard identity
	kc := ggcr.Keychain("my-identity-uidp", ts)

	// Use the keychain to pull an image from cgr.dev
	ref, err := name.ParseReference("cgr.dev/my/image:latest")
	if err != nil {
		clog.FatalContextf(ctx, "%v", err)
	}
	img, err := remote.Image(ref, remote.WithAuthFromKeychain(kc))
	if err != nil {
		clog.FatalContextf(ctx, "%v", err)
	}

	// Get the image digest
	digest, err := img.Digest()
	if err != nil {
		clog.FatalContextf(ctx, "%v", err)
	}

	fmt.Printf("Pulled image with digest: %s\n", digest)
}
Example (PushImage)

ExampleKeychain_pushImage demonstrates using the keychain to push an image to cgr.dev.

package main

import (
	"context"
	"fmt"

	"chainguard.dev/sdk/auth/ggcr"
	"github.com/chainguard-dev/clog"
	"github.com/google/go-containerregistry/pkg/name"
	"github.com/google/go-containerregistry/pkg/v1/remote"
	"google.golang.org/api/idtoken"
)

func main() {
	ctx := context.Background()

	// Create a token source
	ts, err := idtoken.NewTokenSource(ctx, "https://cgr.dev")
	if err != nil {
		clog.FatalContextf(ctx, "%v", err)
	}

	// Create the keychain
	kc := ggcr.Keychain("my-identity-uidp", ts)

	// Pull an image from one location
	srcRef, err := name.ParseReference("cgr.dev/source/image:latest")
	if err != nil {
		clog.FatalContextf(ctx, "%v", err)
	}
	img, err := remote.Image(srcRef, remote.WithAuthFromKeychain(kc))
	if err != nil {
		clog.FatalContextf(ctx, "%v", err)
	}

	// Push it to another location
	dstRef, err := name.ParseReference("cgr.dev/destination/image:latest")
	if err != nil {
		clog.FatalContextf(ctx, "%v", err)
	}
	if err := remote.Write(dstRef, img, remote.WithAuthFromKeychain(kc)); err != nil {
		clog.FatalContextf(ctx, "%v", err)
	}

	fmt.Println("Image pushed successfully")
}
Example (WithContext)

ExampleKeychain_withContext demonstrates using the keychain with a context for timeout and cancellation support.

package main

import (
	"context"

	"chainguard.dev/sdk/auth/ggcr"
	"github.com/chainguard-dev/clog"
	"github.com/google/go-containerregistry/pkg/name"
	"github.com/google/go-containerregistry/pkg/v1/remote"
	"google.golang.org/api/idtoken"
)

func main() {
	ctx := context.Background()

	// Create a token source
	ts, err := idtoken.NewTokenSource(ctx, "https://cgr.dev")
	if err != nil {
		clog.FatalContextf(ctx, "%v", err)
	}

	// Create the keychain
	kc := ggcr.Keychain("my-identity-uidp", ts)

	// Use with context for operations
	ref, err := name.ParseReference("cgr.dev/my/image:latest")
	if err != nil {
		clog.FatalContextf(ctx, "%v", err)
	}
	img, err := remote.Image(ref, remote.WithAuthFromKeychain(kc), remote.WithContext(ctx))
	if err != nil {
		clog.FatalContextf(ctx, "%v", err)
	}

	// Work with the image
	_ = img
}

func TokenSourceKeychain added in v0.1.33

func TokenSourceKeychain(ts oauth2.TokenSource) authn.Keychain

TokenSourceKeychain returns an authn.Keychain that uses the provided oauth2.TokenSource to obtain tokens.

Example

ExampleTokenSourceKeychain demonstrates how to create a keychain from a pre-configured OAuth2 token source.

package main

import (
	"context"

	"chainguard.dev/sdk/auth/ggcr"
	"github.com/chainguard-dev/clog"
	"github.com/google/go-containerregistry/pkg/name"
	"github.com/google/go-containerregistry/pkg/v1/remote"
	"golang.org/x/oauth2"
)

func main() {
	ctx := context.Background()

	// Create a custom token source (this example uses a static token,
	// but in practice you would use a properly configured OAuth2 source)
	ts := oauth2.StaticTokenSource(&oauth2.Token{
		AccessToken: "my-chainguard-token",
	})

	// Create the keychain directly from the token source
	kc := ggcr.TokenSourceKeychain(ts)

	// Use the keychain with go-containerregistry operations
	ref, err := name.ParseReference("cgr.dev/my/image:latest")
	if err != nil {
		clog.FatalContextf(ctx, "%v", err)
	}
	img, err := remote.Image(ref, remote.WithAuthFromKeychain(kc))
	if err != nil {
		clog.FatalContextf(ctx, "%v", err)
	}

	// Work with the image
	_ = img
}

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL