Skip to content

Commit

Permalink
(feat/cli): add input for --provenance-repository while image verific…
Browse files Browse the repository at this point in the history
…ation

Signed-off-by: saisatishkarra <saisatish.karra@konghq.com>
  • Loading branch information
saisatishkarra committed Jan 15, 2024
1 parent f09d99f commit 2c971c1
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 21 deletions.
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
5 changes: 4 additions & 1 deletion cli/slsa-verifier/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func verifyArtifactCmd() *cobra.Command {
}

func verifyImageCmd() *cobra.Command {
o := &verify.VerifyOptions{}
o := &verify.VerifyImageOptions{}

cmd := &cobra.Command{
Use: "verify-image [flags] image",
Expand All @@ -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
42 changes: 42 additions & 0 deletions cli/slsa-verifier/verify/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,48 @@ func (o *VerifyOptions) AddFlags(cmd *cobra.Command) {
cmd.MarkFlagsMutuallyExclusive("source-versioned-tag", "source-tag")
}

// VerifyImageOptions is the top-level options for the `verifyImage` command

type VerifyImageOptions struct {
VerifyOptions
/* Other */
ProvenanceRepository string
}

var _ Interface = (*VerifyImageOptions)(nil)

// AddFlags implements Interface.
func (o *VerifyImageOptions) AddFlags(cmd *cobra.Command) {
cmd.Flags().Var(&o.BuildWorkflowInputs, "build-workflow-input",
"[optional] a workflow input provided by a user at trigger time in the format 'key=value'. (Only for 'workflow_dispatch' events on GitHub Actions).")

cmd.Flags().StringVar(&o.BuilderID, "builder-id", "", "[optional] the unique builder ID who created the provenance")

/* Source options */
cmd.Flags().StringVar(&o.SourceURI, "source-uri", "",
"expected source repository that should have produced the binary, e.g. github.com/some/repo")

cmd.Flags().StringVar(&o.SourceBranch, "source-branch", "", "[optional] expected branch the binary was compiled from")

cmd.Flags().StringVar(&o.SourceTag, "source-tag", "", "[optional] expected tag the binary was compiled from")

cmd.Flags().StringVar(&o.SourceVersionTag, "source-versioned-tag", "",
"[optional] expected version the binary was compiled from. Uses semantic version to match the tag")

/* Other options */
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>. When set, overrides COSIGN_REPOSITORY environment variable")

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

cmd.MarkFlagRequired("source-uri")
cmd.MarkFlagsMutuallyExclusive("source-versioned-tag", "source-tag")
}

// VerifyNpmOptions is the top-level options for the `verifyNpmPackage` command.
type VerifyNpmOptions struct {
VerifyOptions
Expand Down
24 changes: 15 additions & 9 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 Down Expand Up @@ -70,7 +71,12 @@ func (c *VerifyImageCommand) Exec(ctx context.Context, artifacts []string) (*uti
}
}

verifiedProvenance, outBuilderID, err := verifiers.VerifyImage(ctx, artifacts[0], provenance, provenanceOpts, builderOpts)
var provenanceRepository string
if c.ProvenanceRepository != nil {
provenanceRepository = *c.ProvenanceRepository
}

verifiedProvenance, outBuilderID, err := verifiers.VerifyImage(ctx, artifacts[0], provenance, provenanceRepository, provenanceOpts, builderOpts)
if err != nil {
return nil, err
}
Expand Down
4 changes: 2 additions & 2 deletions register/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ type SLSAVerifier interface {

// VerifyImage verifies a provenance for a supplied OCI image.
VerifyImage(ctx context.Context,
provenance []byte, artifactImage string,
provenanceOpts *options.ProvenanceOpts,
provenance []byte, provenanceRepository string,
artifactImage string, provenanceOpts *options.ProvenanceOpts,
builderOpts *options.BuilderOpts,
) ([]byte, *utils.TrustedBuilderID, error)

Expand Down
4 changes: 2 additions & 2 deletions verifiers/internal/gcb/verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ func (v *GCBVerifier) VerifyNpmPackage(ctx context.Context,

// VerifyImage verifies provenance for an OCI image.
func (v *GCBVerifier) VerifyImage(ctx context.Context,
provenance []byte, artifactImage string,
provenanceOpts *options.ProvenanceOpts,
provenance []byte, provenanceRepository string,
artifactImage string, provenanceOpts *options.ProvenanceOpts,
builderOpts *options.BuilderOpts,
) ([]byte, *utils.TrustedBuilderID, error) {
prov, err := ProvenanceFromBytes(provenance)
Expand Down
22 changes: 16 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,8 @@ 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, provenanceRepository string,
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 +256,19 @@ 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 provenanceRepository != "" {
provenanceTargetRepository, err = name.NewRepository(provenanceRepository)
if err != nil {
return nil, nil, err
}
} else {
// If user input --provenance-repository is empty, look for COSIGN_REPOSITORY environment
provenanceTargetRepository, err = ociremote.GetEnvTargetRepository()
if err != nil {
return nil, nil, err
}
}

registryClientOpts := []ociremote.Option{}
Expand Down
3 changes: 2 additions & 1 deletion verifiers/verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,15 @@ func getVerifier(builderOpts *options.BuilderOpts) (register.SLSAVerifier, error

func VerifyImage(ctx context.Context, artifactImage string,
provenance []byte,
provenanceRepository string,
provenanceOpts *options.ProvenanceOpts,
builderOpts *options.BuilderOpts,
) ([]byte, *utils.TrustedBuilderID, error) {
verifier, err := getVerifier(builderOpts)
if err != nil {
return nil, nil, err
}
return verifier.VerifyImage(ctx, provenance, artifactImage, provenanceOpts, builderOpts)
return verifier.VerifyImage(ctx, provenance, provenanceRepository, artifactImage, provenanceOpts, builderOpts)
}

func VerifyArtifact(ctx context.Context,
Expand Down

0 comments on commit 2c971c1

Please sign in to comment.