Skip to content

Commit

Permalink
Merge pull request #1695 from lcarva/EC-584
Browse files Browse the repository at this point in the history
Teach EC CLI to initialize a TUF root
  • Loading branch information
lcarva authored Jun 14, 2024
2 parents 209cd0a + 65d0fea commit 0527fad
Show file tree
Hide file tree
Showing 13 changed files with 283 additions and 55 deletions.
25 changes: 0 additions & 25 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -32,36 +32,11 @@ COPY . .

RUN /build/build.sh "${TARGETOS}_${TARGETARCH}"

# Extract this so we can download the matching cosign version below
RUN go list --mod=readonly -f '{{.Version}}' -m github.com/sigstore/cosign/v2 | tee cosign_version.txt

## Downloads

FROM registry.access.redhat.com/ubi9/ubi-minimal:9.4@sha256:ef6fb6b3b38ef6c85daebeabebc7ff3151b9dd1500056e6abc9c3295e4b78a51 AS download

ARG TARGETOS
ARG TARGETARCH

WORKDIR /download

COPY --from=build /build/cosign_version.txt /download/

# Download the matching version of cosign
RUN COSIGN_VERSION=$(cat /download/cosign_version.txt) && \
curl -sLO https://github.com/sigstore/cosign/releases/download/${COSIGN_VERSION}/cosign-${TARGETOS}-${TARGETARCH} && \
curl -sLO https://github.com/sigstore/cosign/releases/download/${COSIGN_VERSION}/cosign_checksums.txt && \
sha256sum --check <(grep -w "cosign-${TARGETOS}-${TARGETARCH}" < cosign_checksums.txt) && \
mv "cosign-${TARGETOS}-${TARGETARCH}" cosign && \
chmod +x cosign

FROM registry.access.redhat.com/ubi9/ubi-minimal:9.4@sha256:ef6fb6b3b38ef6c85daebeabebc7ff3151b9dd1500056e6abc9c3295e4b78a51

ARG TARGETOS
ARG TARGETARCH

COPY --from=download /download/cosign /usr/local/bin/cosign
RUN cosign version

RUN microdnf upgrade --assumeyes --nodocs --setopt=keepcache=0 --refresh && microdnf -y --nodocs --setopt=keepcache=0 install git-core jq

# Copy the one ec binary that can run in this container
Expand Down
27 changes: 2 additions & 25 deletions Dockerfile.dist
Original file line number Diff line number Diff line change
Expand Up @@ -40,28 +40,6 @@ COPY . .

RUN /build/build.sh "${BUILD_LIST}" "${BUILD_SUFFIX}"

# Extract this so we can download the matching cosign version below
RUN go list --mod=readonly -f '{{.Version}}' -m github.com/sigstore/cosign/v2 | tee cosign_version.txt

## Downloads

FROM registry.access.redhat.com/ubi9/ubi-minimal:9.4@sha256:ef6fb6b3b38ef6c85daebeabebc7ff3151b9dd1500056e6abc9c3295e4b78a51 AS download

ARG TARGETOS
ARG TARGETARCH

WORKDIR /download

COPY --from=build /build/cosign_version.txt /download/

# Download the matching version of cosign
RUN COSIGN_VERSION=$(cat /download/cosign_version.txt) && \
curl -sLO https://github.com/sigstore/cosign/releases/download/${COSIGN_VERSION}/cosign-${TARGETOS}-${TARGETARCH} && \
curl -sLO https://github.com/sigstore/cosign/releases/download/${COSIGN_VERSION}/cosign_checksums.txt && \
sha256sum --check <(grep -w "cosign-${TARGETOS}-${TARGETARCH}" < cosign_checksums.txt) && \
mv "cosign-${TARGETOS}-${TARGETARCH}" cosign && \
chmod +x cosign

## Final image

FROM registry.access.redhat.com/ubi9/ubi-minimal:9.4@sha256:ef6fb6b3b38ef6c85daebeabebc7ff3151b9dd1500056e6abc9c3295e4b78a51
Expand All @@ -78,9 +56,8 @@ LABEL \
io.openshift.tags="rhtas rhtap trusted-artifact-signer trusted-application-pipeline enterprise-contract ec opa cosign sigstore" \
com.redhat.component="ec-cli"

# Install cosign and other tools we want to use in the Tekton task
# Install tools we want to use in the Tekton task
RUN microdnf upgrade --assumeyes --nodocs --setopt=keepcache=0 --refresh && microdnf -y --nodocs --setopt=keepcache=0 install git-core jq
COPY --from=download /download/cosign /usr/local/bin/cosign

# Copy all the binaries so they're available to extract and download
# (Beware if you're testing this locally it will copy everything from
Expand All @@ -101,6 +78,6 @@ COPY --from=build /build/LICENSE /licenses/LICENSE
USER 1001

# Show some version numbers for troubleshooting purposes
RUN git version && jq --version && cosign version && ec version && ls -l /usr/local/bin
RUN git version && jq --version && ec version && ls -l /usr/local/bin

ENTRYPOINT ["/usr/local/bin/ec"]
2 changes: 2 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/enterprise-contract/ec-cli/cmd/inspect"
"github.com/enterprise-contract/ec-cli/cmd/opa"
"github.com/enterprise-contract/ec-cli/cmd/root"
"github.com/enterprise-contract/ec-cli/cmd/sigstore"
"github.com/enterprise-contract/ec-cli/cmd/test"
"github.com/enterprise-contract/ec-cli/cmd/track"
"github.com/enterprise-contract/ec-cli/cmd/validate"
Expand Down Expand Up @@ -53,6 +54,7 @@ func init() {
RootCmd.AddCommand(validate.ValidateCmd)
RootCmd.AddCommand(version.VersionCmd)
RootCmd.AddCommand(opa.OPACmd)
RootCmd.AddCommand(sigstore.SigstoreCmd)
if utils.Experimental() {
RootCmd.AddCommand(test.TestCmd)
}
Expand Down
77 changes: 77 additions & 0 deletions cmd/sigstore/initialize.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright The Enterprise Contract Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0

package sigstore

import (
"context"

hd "github.com/MakeNowJust/heredoc"
"github.com/sigstore/cosign/v2/cmd/cosign/cli/options"
"github.com/spf13/cobra"
)

type sigstoreInitializeFunc func(ctx context.Context, root, mirror string) error

func sigstoreInitializeCmd(f sigstoreInitializeFunc) *cobra.Command {

opts := &options.InitializeOptions{}

cmd := &cobra.Command{
Use: "initialize",
Short: "Initializes Sigstore root to retrieve trusted certificate and key targets for verification",

Long: hd.Doc(`
Initializes Sigstore root to retrieve trusted certificate and key targets for verification.
The following options are used by default:
- The current trusted Sigstore TUF root is embedded inside ec at the time of release.
- Sigstore remote TUF repository is pulled from the CDN mirror at tuf-repo-cdn.sigstore.dev.
To provide an out-of-band trusted initial root.json, use the --root flag with a file or
URL reference. This will enable you to point ec to a separate TUF root.
Any updated TUF repository will be written to $HOME/.sigstore/root/.
Trusted keys and certificate used in ec verification (e.g. verifying Fulcio issued certificates
with Fulcio root CA) are pulled form the trusted metadata.
This command is mostly a wrapper around "cosign initialize".
`),

Example: hd.Doc(`
ec initialize -mirror <url> -out <file>
Initialize root with distributed root keys, default mirror, and default out path.
ec initialize
Initialize with an out-of-band root key file, using the default mirror.
ec initialize -root <url>
Initialize with an out-of-band root key file and custom repository mirror.
ec initialize -mirror <url> -root <url>
`),

Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, _ []string) error {
return f(cmd.Context(), opts.Root, opts.Mirror)
},
}

opts.AddFlags(cmd)

return cmd
}
83 changes: 83 additions & 0 deletions cmd/sigstore/initialize_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Copyright The Enterprise Contract Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0

//go:build unit

package sigstore

import (
"context"
"testing"

"github.com/stretchr/testify/require"

"github.com/enterprise-contract/ec-cli/cmd/root"
)

func TestInitializeCmd(t *testing.T) {
cases := []struct {
name string
args []string
expectedRoot string
expectedMirror string
}{
{
name: "no args",
expectedMirror: "https://tuf-repo-cdn.sigstore.dev",
},
{
name: "with root",
args: []string{"--root", "/some/path/root.json"},
expectedRoot: "/some/path/root.json",
expectedMirror: "https://tuf-repo-cdn.sigstore.dev",
},
{
name: "with mirror",
args: []string{"--mirror", "https://tuf.local"},
expectedMirror: "https://tuf.local",
},
{
name: "with root and mirror",
args: []string{"--root", "/some/path/root.json", "--mirror", "https://tuf.local"},
expectedRoot: "/some/path/root.json",
expectedMirror: "https://tuf.local",
},
}

for _, tt := range cases {
t.Run(tt.name, func(t *testing.T) {
initF := func(ctx context.Context, root, mirror string) error {
require.Equal(t, tt.expectedRoot, root)
require.Equal(t, tt.expectedMirror, mirror)
return nil
}

sigInitCmd := sigstoreInitializeCmd(initF)

sigCmd := NewSigstoreCmd()
sigCmd.AddCommand(sigInitCmd)

rootCmd := root.NewRootCmd()
rootCmd.AddCommand(sigCmd)

rootCmd.SetContext(context.Background())
rootCmd.SetArgs(append([]string{"sigstore", "initialize"}, tt.args...))

err := rootCmd.Execute()
require.NoError(t, err)
})
}
}
39 changes: 39 additions & 0 deletions cmd/sigstore/sigstore.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright The Enterprise Contract Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0

package sigstore

import (
"github.com/sigstore/cosign/v2/cmd/cosign/cli/initialize"
"github.com/spf13/cobra"

_ "github.com/enterprise-contract/ec-cli/internal/rego"
)

var SigstoreCmd *cobra.Command

func init() {
SigstoreCmd = NewSigstoreCmd()
SigstoreCmd.AddCommand(sigstoreInitializeCmd(initialize.DoInitialize))
}

func NewSigstoreCmd() *cobra.Command {
sigstoreCmd := &cobra.Command{
Use: "sigstore",
Short: "Perform certain sigstore operations",
}
return sigstoreCmd
}
19 changes: 19 additions & 0 deletions docs/modules/ROOT/pages/ec_sigstore.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
= ec sigstore

Perform certain sigstore operations
== Options

-h, --help:: help for sigstore (Default: false)

== Options inherited from parent commands

--debug:: same as verbose but also show function names and line numbers (Default: false)
--kubeconfig:: path to the Kubernetes config file to use
--quiet:: less verbose output (Default: false)
--timeout:: max overall execution duration (Default: 5m0s)
--trace:: enable trace logging (Default: false)
--verbose:: more verbose output (Default: false)

== See also

* xref:ec.adoc[ec - Enterprise Contract CLI]
55 changes: 55 additions & 0 deletions docs/modules/ROOT/pages/ec_sigstore_initialize.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
= ec sigstore initialize

Initializes Sigstore root to retrieve trusted certificate and key targets for verification== Synopsis

Initializes Sigstore root to retrieve trusted certificate and key targets for verification.

The following options are used by default:
- The current trusted Sigstore TUF root is embedded inside ec at the time of release.
- Sigstore remote TUF repository is pulled from the CDN mirror at tuf-repo-cdn.sigstore.dev.

To provide an out-of-band trusted initial root.json, use the --root flag with a file or
URL reference. This will enable you to point ec to a separate TUF root.

Any updated TUF repository will be written to $HOME/.sigstore/root/.

Trusted keys and certificate used in ec verification (e.g. verifying Fulcio issued certificates
with Fulcio root CA) are pulled form the trusted metadata.

This command is mostly a wrapper around "cosign initialize".

[source,shell]
----
ec sigstore initialize [flags]
----

== Examples
ec initialize -mirror <url> -out <file>

Initialize root with distributed root keys, default mirror, and default out path.
ec initialize

Initialize with an out-of-band root key file, using the default mirror.
ec initialize -root <url>

Initialize with an out-of-band root key file and custom repository mirror.
ec initialize -mirror <url> -root <url>

== Options

-h, --help:: help for initialize (Default: false)
--mirror:: GCS bucket to a SigStore TUF repository, or HTTP(S) base URL, or file:/// for local filestore remote (air-gap) (Default: https://tuf-repo-cdn.sigstore.dev)
--root:: path to trusted initial root. defaults to embedded root

== Options inherited from parent commands

--debug:: same as verbose but also show function names and line numbers (Default: false)
--kubeconfig:: path to the Kubernetes config file to use
--quiet:: less verbose output (Default: false)
--timeout:: max overall execution duration (Default: 5m0s)
--trace:: enable trace logging (Default: false)
--verbose:: more verbose output (Default: false)

== See also

* xref:ec_sigstore.adoc[ec sigstore - Perform certain sigstore operations]
2 changes: 2 additions & 0 deletions docs/modules/ROOT/partials/cli_nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
** xref:ec_opa_sign.adoc[ec opa sign]
** xref:ec_opa_test.adoc[ec opa test]
** xref:ec_opa_version.adoc[ec opa version]
** xref:ec_sigstore.adoc[ec sigstore]
** xref:ec_sigstore_initialize.adoc[ec sigstore initialize]
** xref:ec_test.adoc[ec test]
** xref:ec_track.adoc[ec track]
** xref:ec_track_bundle.adoc[ec track bundle]
Expand Down
1 change: 0 additions & 1 deletion features/__snapshots__/task_validate_image.snap
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,6 @@ ${TIMESTAMP} Skipping step because a previous step failed
[Initialize TUF fails:initialize-tuf - 1]
Initializing TUF root...
Error: Get "http://tuf.invalid/root.json": dial tcp: lookup tuf.invalid on 10.96.0.10:53: no such host
main.go:74: error during command execution: Get "http://tuf.invalid/root.json": dial tcp: lookup tuf.invalid on 10.96.0.10:53: no such host

---

Expand Down
Loading

0 comments on commit 0527fad

Please sign in to comment.