docs: update examples in README.md
This commit is contained in:
78
pkg/attest/example_sign.go
Normal file
78
pkg/attest/example_sign.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package attest
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/attest/pkg/attestation"
|
||||
"github.com/docker/attest/pkg/mirror"
|
||||
"github.com/docker/attest/pkg/oci"
|
||||
"github.com/docker/attest/pkg/signerverifier"
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/google/go-containerregistry/pkg/v1/empty"
|
||||
"github.com/google/go-containerregistry/pkg/v1/mutate"
|
||||
)
|
||||
|
||||
func ExampleSign_remote() {
|
||||
// configure signerverifier
|
||||
// local signer (unsafe for production)
|
||||
signer, err := signerverifier.GenKeyPair()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// example using AWS KMS signer
|
||||
// aws_arn := "arn:aws:kms:us-west-2:123456789012:key/12345678-1234-1234-1234-123456789012"
|
||||
// aws_region := "us-west-2"
|
||||
// signer, err := signerverifier.GetAWSSigner(cmd.Context(), aws_arn, aws_region)
|
||||
|
||||
// configure signing options
|
||||
opts := &SigningOptions{
|
||||
Replace: true, // replace unsigned intoto statements with signed intoto attestations, otherwise leave in place
|
||||
}
|
||||
|
||||
// configure VSA options (optional)
|
||||
slsaBuildLevel := "3"
|
||||
slsaPolicyUri := "https://docker.com/attest/policy"
|
||||
slsaVerifierId := "https://docker.com"
|
||||
opts.VSAOptions = &attestation.VSAOptions{
|
||||
BuildLevel: "SLSA_BUILD_LEVEL_" + slsaBuildLevel,
|
||||
PolicyURI: slsaPolicyUri,
|
||||
VerifierID: slsaVerifierId,
|
||||
}
|
||||
|
||||
// load image index with unsigned attestation-manifests
|
||||
ref := "docker/image-signer-verifier:latest"
|
||||
att, err := oci.AttestationIndexFromRemote(ref)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// example for local image index
|
||||
// path := "/myimage"
|
||||
// att, err := oci.AttestationIndexFromLocal(path)
|
||||
|
||||
// sign attestations
|
||||
signedImageIndex, err := Sign(context.Background(), att.Index, signer, opts)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// push image index with signed attestation-manifests
|
||||
err = mirror.PushToRegistry(signedImageIndex, ref)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// output image index to filesystem (optional)
|
||||
path := "/myimage"
|
||||
idx := v1.ImageIndex(empty.Index)
|
||||
idx = mutate.AppendManifests(idx, mutate.IndexAddendum{
|
||||
Add: signedImageIndex,
|
||||
Descriptor: v1.Descriptor{
|
||||
Annotations: map[string]string{
|
||||
oci.OciReferenceTarget: att.Name,
|
||||
},
|
||||
},
|
||||
})
|
||||
err = mirror.SaveAsOCILayout(idx, path)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
69
pkg/attest/example_verify.go
Normal file
69
pkg/attest/example_verify.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package attest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/docker/attest/internal/embed"
|
||||
"github.com/docker/attest/pkg/oci"
|
||||
"github.com/docker/attest/pkg/policy"
|
||||
"github.com/docker/attest/pkg/tuf"
|
||||
)
|
||||
|
||||
func createTufClient(outputPath string) (*tuf.TufClient, error) {
|
||||
// using oci tuf metadata and targets
|
||||
metadataURI := "regsitry-1.docker.io/docker/tuf-metadata:latest"
|
||||
targetsURI := "regsitry-1.docker.io/docker/tuf-targets"
|
||||
// example using http tuf metadata and targets
|
||||
// metadataURI := "https://docker.github.io/tuf-staging/metadata"
|
||||
// targetsURI := "https://docker.github.io/tuf-staging/targets"
|
||||
|
||||
return tuf.NewTufClient(embed.DefaultRoot, outputPath, metadataURI, targetsURI)
|
||||
}
|
||||
|
||||
func ExampleVerify_remote() {
|
||||
// create a tuf client
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
tufOutputPath := filepath.Join(home, ".docker", "tuf")
|
||||
tufClient, err := createTufClient(tufOutputPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// create a resolver for remote attestations
|
||||
image := "regsitry-1.docker.io/notary:server"
|
||||
platform := "linux/amd64"
|
||||
resolver := &oci.RegistryResolver{
|
||||
Image: image, // path to image index in OCI registry containing image attestations
|
||||
Platform: platform, // platform of subject image (image that attestations are being verified against)
|
||||
}
|
||||
// example using a local resolver
|
||||
// path := "/myimage"
|
||||
// platform := "linux/amd64"
|
||||
// resolver := &oci.OCILayoutResolver{
|
||||
// Path: path, // file path to OCI layout containing image attestations
|
||||
// Platform: platform, // platform of subject image (image that attestations are being verified against)
|
||||
// }
|
||||
|
||||
// configure policy options
|
||||
opts := &policy.PolicyOptions{
|
||||
TufClient: tufClient,
|
||||
LocalTargetsDir: filepath.Join(home, ".docker", "policy"), // location to store policy files downloaded from TUF
|
||||
LocalPolicyDir: "", // overrides TUF policy for local policy files if set
|
||||
}
|
||||
|
||||
// verify attestations
|
||||
policy, err := Verify(context.Background(), opts, resolver)
|
||||
if err != nil {
|
||||
panic(err) // failed policy or attestation signature verification
|
||||
}
|
||||
if policy {
|
||||
print("policy passed: %v\n", policy)
|
||||
return // passed policy
|
||||
}
|
||||
// no policy for image
|
||||
}
|
||||
150
pkg/mirror/example_mirror.go
Normal file
150
pkg/mirror/example_mirror.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package mirror
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/attest/internal/embed"
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
)
|
||||
|
||||
type TufMirrorOutput struct {
|
||||
metadata *v1.Image
|
||||
delegatedMetadata []*MirrorImage
|
||||
targets []*MirrorImage
|
||||
delegatedTargets []*MirrorIndex
|
||||
}
|
||||
|
||||
func ExampleMirror() {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
tufOutputPath := filepath.Join(home, ".docker", "tuf")
|
||||
|
||||
// configure TUF mirror
|
||||
metadataURI := "https://docker.github.io/tuf-staging/metadata"
|
||||
targetsURI := "https://docker.github.io/tuf-staging/targets"
|
||||
m, err := NewTufMirror(embed.DefaultRoot, tufOutputPath, metadataURI, targetsURI)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// create metadata manifest
|
||||
metadataManifest, err := m.GetMetadataManifest(metadataURI)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// create delegated targets metadata manifests
|
||||
delegatedMetadata, err := m.GetDelegatedMetadataMirrors()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// create targets manifest
|
||||
targets, err := m.GetTufTargetMirrors()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// create delegated targets manifests
|
||||
delegatedTargets, err := m.GetDelegatedTargetMirrors()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
mirrorOutput := &TufMirrorOutput{
|
||||
metadata: metadataManifest,
|
||||
delegatedMetadata: delegatedMetadata,
|
||||
targets: targets,
|
||||
delegatedTargets: delegatedTargets,
|
||||
}
|
||||
|
||||
// push metadata and targets to registry (optional)
|
||||
err = mirrorToRegistry(mirrorOutput)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// save metadata and targets to local directory (optional)
|
||||
mirrorOutputPath := filepath.Join(home, ".docker", "tuf", "mirror")
|
||||
err = mirrorToLocal(mirrorOutput, mirrorOutputPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func mirrorToRegistry(o *TufMirrorOutput) error {
|
||||
// push metadata to registry
|
||||
metadataRepo := "registry-1.docker.io/docker/tuf-metadata:latest"
|
||||
err := PushToRegistry(o.metadata, metadataRepo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// push delegated metadata to registry
|
||||
for _, metadata := range o.delegatedMetadata {
|
||||
repo, _, ok := strings.Cut(metadataRepo, ":")
|
||||
if !ok {
|
||||
return fmt.Errorf("failed to get repo without tag: %s", metadataRepo)
|
||||
}
|
||||
imageName := fmt.Sprintf("%s:%s", repo, metadata.Tag)
|
||||
err = PushToRegistry(metadata.Image, imageName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// push top-level targets to registry
|
||||
targetsRepo := "registry-1.docker.io/docker/tuf-targets"
|
||||
for _, target := range o.targets {
|
||||
imageName := fmt.Sprintf("%s:%s", targetsRepo, target.Tag)
|
||||
err = PushToRegistry(target.Image, imageName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// push delegated targets to registry
|
||||
for _, target := range o.delegatedTargets {
|
||||
imageName := fmt.Sprintf("%s:%s", targetsRepo, target.Tag)
|
||||
err = PushToRegistry(target.Index, imageName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func mirrorToLocal(o *TufMirrorOutput, outputPath string) error {
|
||||
// output metadata to local directory
|
||||
err := SaveAsOCILayout(o.metadata, outputPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// output delegated metadata to local directory
|
||||
for _, metadata := range o.delegatedMetadata {
|
||||
path := filepath.Join(outputPath, metadata.Tag)
|
||||
err = SaveAsOCILayout(metadata.Image, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// output top-level targets to local directory
|
||||
for _, target := range o.targets {
|
||||
path := filepath.Join(outputPath, target.Tag)
|
||||
err = SaveAsOCILayout(target.Image, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// output delegated targets to local directory
|
||||
for _, target := range o.delegatedTargets {
|
||||
path := filepath.Join(outputPath, target.Tag)
|
||||
err = SaveAsOCILayout(target.Index, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
43
pkg/tuf/example_registry.go
Normal file
43
pkg/tuf/example_registry.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package tuf
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/docker/attest/internal/embed"
|
||||
"github.com/theupdateframework/go-tuf/v2/metadata"
|
||||
)
|
||||
|
||||
func ExampleTufRegistryClient() {
|
||||
// create a tuf client
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
tufOutputPath := filepath.Join(home, ".docker", "tuf")
|
||||
|
||||
// using oci tuf metadata and targets
|
||||
metadataURI := "regsitry-1.docker.io/docker/tuf-metadata:latest"
|
||||
targetsURI := "regsitry-1.docker.io/docker/tuf-targets"
|
||||
registryClient, err := NewTufClient(embed.DefaultRoot, tufOutputPath, metadataURI, targetsURI)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// get trusted tuf metadata
|
||||
trustedMetadata := registryClient.GetMetadata()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// top-level target files
|
||||
targets := trustedMetadata.Targets[metadata.TARGETS].Signed.Targets
|
||||
|
||||
for _, t := range targets {
|
||||
// download target files
|
||||
_, _, err := registryClient.DownloadTarget(t.Path, filepath.Join(tufOutputPath, "download"))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user