Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: fixes #724: add input for --provenance-repository while image verification #736

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,28 @@ The only requirement is that the provenance file covers all artifacts passed as

To verify a container image, you need to pass a container image name that is _immutable_ by providing its digest, in order to avoid [TOCTOU attacks](#toctou-attacks).

#### The verify-image command

```bash
$ slsa-verifier verify-image --help
Verifies SLSA provenance for an image

Usage:
slsa-verifier verify-image [flags] tarball

Flags:
--build-workflow-input map[] [optional] a workflow input provided by a user at trigger time in the format 'key=value'. (Only for 'workflow_dispatch' events on GitHub Actions). (default map[])
--builder-id string [optional] the unique builder ID who created the provenance
-h, --help help for verify-npm-package
--print-provenance [optional] print the verified provenance to stdout
--provenance-path string path to a provenance file
--provenance-repository string [optional] provenance repository when stored different from image repository. When set, overrides COSIGN_REPOSITORY environment variable
--source-branch string [optional] expected branch the binary was compiled from
--source-tag string [optional] expected tag the binary was compiled from
--source-uri string expected source repository that should have produced the binary, e.g. github.com/some/repo
--source-versioned-tag string [optional] expected version the binary was compiled from. Uses semantic version to match the tag
```

First set the image name:

```shell
Expand Down
3 changes: 3 additions & 0 deletions cli/slsa-verifier/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ func verifyImageCmd() *cobra.Command {
if cmd.Flags().Changed("provenance-path") {
v.ProvenancePath = &o.ProvenancePath
}
if cmd.Flags().Changed("provenance-repository") {
v.ProvenanceRepository = &o.ProvenanceRepository
}
if cmd.Flags().Changed("source-branch") {
v.SourceBranch = &o.SourceBranch
}
Expand Down
8 changes: 6 additions & 2 deletions cli/slsa-verifier/verify/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ type VerifyOptions struct {
BuildWorkflowInputs workflowInputs
BuilderID string
/* Other */
ProvenancePath string
PrintProvenance bool
ProvenancePath string
ProvenanceRepository string
PrintProvenance bool
}

var _ Interface = (*VerifyOptions)(nil)
Expand Down Expand Up @@ -67,6 +68,9 @@ func (o *VerifyOptions) AddFlags(cmd *cobra.Command) {
cmd.Flags().StringVar(&o.ProvenancePath, "provenance-path", "",
"path to a provenance file")

cmd.Flags().StringVar(&o.ProvenanceRepository, "provenance-repository", "",
"image repository for provenance with format: <registry>/<repository>")

cmd.Flags().BoolVar(&o.PrintProvenance, "print-provenance", false,
"[optional] print the verified provenance to stdout")

Expand Down
31 changes: 17 additions & 14 deletions cli/slsa-verifier/verify/verify_image.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,15 @@ type ComputeDigestFn func(string) (string, error)
// Note: nil branch, tag, version-tag and builder-id means we ignore them during verification.
type VerifyImageCommand struct {
// May be nil if supplied alongside in the registry
ProvenancePath *string
BuilderID *string
SourceURI string
SourceBranch *string
SourceTag *string
SourceVersionTag *string
BuildWorkflowInputs map[string]string
PrintProvenance bool
ProvenancePath *string
ProvenanceRepository *string
BuilderID *string
SourceURI string
SourceBranch *string
SourceTag *string
SourceVersionTag *string
BuildWorkflowInputs map[string]string
PrintProvenance bool
}

func (c *VerifyImageCommand) Exec(ctx context.Context, artifacts []string) (*utils.TrustedBuilderID, error) {
Expand All @@ -50,12 +51,13 @@ func (c *VerifyImageCommand) Exec(ctx context.Context, artifacts []string) (*uti
}

provenanceOpts := &options.ProvenanceOpts{
ExpectedSourceURI: c.SourceURI,
ExpectedBranch: c.SourceBranch,
ExpectedDigest: digest,
ExpectedVersionedTag: c.SourceVersionTag,
ExpectedTag: c.SourceTag,
ExpectedWorkflowInputs: c.BuildWorkflowInputs,
ExpectedSourceURI: c.SourceURI,
ExpectedBranch: c.SourceBranch,
ExpectedDigest: digest,
ExpectedVersionedTag: c.SourceVersionTag,
ExpectedTag: c.SourceTag,
ExpectedProvenanceRepository: c.ProvenanceRepository,
ExpectedWorkflowInputs: c.BuildWorkflowInputs,
}

builderOpts := &options.BuilderOpts{
Expand All @@ -71,6 +73,7 @@ func (c *VerifyImageCommand) Exec(ctx context.Context, artifacts []string) (*uti
}

verifiedProvenance, outBuilderID, err := verifiers.VerifyImage(ctx, artifacts[0], provenance, provenanceOpts, builderOpts)

if err != nil {
return nil, err
}
Expand Down
3 changes: 3 additions & 0 deletions options/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ type ProvenanceOpts struct {
ExpectedPackageName *string

ExpectedPackageVersion *string

// ExpectedProvenanceRepository is the provenance repository that is passed from user and not verified
ExpectedProvenanceRepository *string
}

// BuildOpts are the options for checking the builder.
Expand Down
16 changes: 10 additions & 6 deletions verifiers/internal/gha/verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"os"
"strings"

"github.com/google/go-containerregistry/pkg/name"
"github.com/secure-systems-lab/go-securesystemslib/dsse"
"github.com/sigstore/cosign/v2/pkg/cosign"
"github.com/sigstore/rekor/pkg/client"
Expand Down Expand Up @@ -245,8 +246,7 @@ func (v *GHAVerifier) VerifyArtifact(ctx context.Context,

// VerifyImage verifies provenance for an OCI image.
func (v *GHAVerifier) VerifyImage(ctx context.Context,
provenance []byte, artifactImage string,
provenanceOpts *options.ProvenanceOpts,
provenance []byte, artifactImage string, provenanceOpts *options.ProvenanceOpts,
builderOpts *options.BuilderOpts,
) ([]byte, *utils.TrustedBuilderID, error) {
/* Retrieve any valid signed attestations that chain up to Fulcio root CA. */
Expand All @@ -255,10 +255,13 @@ func (v *GHAVerifier) VerifyImage(ctx context.Context,
return nil, nil, err
}

// Parse any provenance target repository set using environment variable COSIGN_REPOSITORY
provenanceTargetRepository, err := ociremote.GetEnvTargetRepository()
if err != nil {
return nil, nil, err
var provenanceTargetRepository name.Repository
// Consume input for --provenance-repository when set
if provenanceOpts.ExpectedProvenanceRepository != nil {
provenanceTargetRepository, err = name.NewRepository(*provenanceOpts.ExpectedProvenanceRepository)
laurentsimon marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return nil, nil, err
}
}

registryClientOpts := []ociremote.Option{}
Expand All @@ -276,6 +279,7 @@ func (v *GHAVerifier) VerifyImage(ctx context.Context,
RekorPubKeys: trustedRoot.RekorPubKeys,
CTLogPubKeys: trustedRoot.CTPubKeys,
}

atts, _, err := container.RunCosignImageVerification(ctx,
artifactImage, opts)
if err != nil {
Expand Down
Loading