Skip to content

Commit

Permalink
Merge pull request #1900 from simonbaird/no-cosign-with-wrapper-v02
Browse files Browse the repository at this point in the history
Replace cosign binary with bash wrapper [0.2]
  • Loading branch information
simonbaird authored Aug 29, 2024
2 parents 005785b + ec22d1a commit 1ee6a12
Show file tree
Hide file tree
Showing 12 changed files with 353 additions and 114 deletions.
22 changes: 4 additions & 18 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,17 @@
#
# SPDX-License-Identifier: Apache-2.0

FROM registry.access.redhat.com/ubi9/ubi-minimal:9.3@sha256:bc552efb4966aaa44b02532be3168ac1ff18e2af299d0fe89502a1d9fabafbc5 AS downloads

ARG TARGETOS
ARG TARGETARCH

ARG COSIGN_VERSION

ADD https://github.com/sigstore/cosign/releases/download/${COSIGN_VERSION}/cosign-${TARGETOS}-${TARGETARCH} /opt/
ADD https://github.com/sigstore/cosign/releases/download/${COSIGN_VERSION}/cosign_checksums.txt /opt/

RUN cd /opt && \
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.3@sha256:bc552efb4966aaa44b02532be3168ac1ff18e2af299d0fe89502a1d9fabafbc5

ARG TARGETOS
ARG TARGETARCH

COPY --from=downloads /opt/cosign /usr/local/bin/
RUN cosign version

RUN microdnf -y install git-core jq && microdnf clean all

COPY "dist/ec_"$TARGETOS"_"$TARGETARCH /usr/bin/ec

# Add a cosign wrapper command to handle "cosign initialize" for backwards
# compatibility with older task definitions
COPY hack/fake-cosign.sh /usr/local/bin/cosign

ENTRYPOINT ["/usr/bin/ec"]
105 changes: 38 additions & 67 deletions Dockerfile.dist
Original file line number Diff line number Diff line change
Expand Up @@ -68,69 +68,37 @@ COPY . .
# a PR is merged.
#
RUN \
EC_GIT_SHA=$( git rev-parse --short HEAD ); \
echo "EC_GIT_SHA=$EC_GIT_SHA"; \
\
EC_VERSION="v0.2"; \
echo "EC_VERSION=$EC_VERSION"; \
\
EC_BASE_TAG="${EC_VERSION}-patch-base"; \
echo "EC_BASE_TAG=$EC_BASE_TAG"; \
git log -n1 --format="%h %s" "$EC_BASE_TAG"; \
\
EC_PATCH_NUM=$( git rev-list --merges --count ${EC_BASE_TAG}..HEAD ); \
echo "EC_PATCH_NUM=$EC_PATCH_NUM"; \
\
EC_FULL_VERSION="${EC_VERSION}.${EC_PATCH_NUM}"; \
echo "EC_FULL_VERSION=$EC_FULL_VERSION"; \
\
BUILDS="${BUILD_LIST}"; \
echo "BUILDS=$BUILDS"; \
\
for os_arch in ${BUILDS}; do \
export GOOS="${os_arch%_*}"; \
export GOARCH="${os_arch#*_}"; \
[ "$GOOS" = "windows" ] && DOT_EXE=".exe" || DOT_EXE=""; \
BINFILE="ec_${GOOS}_${GOARCH}${DOT_EXE}"; \
echo "Building ${BINFILE} for ${EC_FULL_VERSION}"; \
go build \
-trimpath \
--mod=readonly \
-ldflags="-s -w -X github.com/enterprise-contract/ec-cli/internal/version.Version=${EC_FULL_VERSION}" \
-o "dist/${BINFILE}"; \
done

# 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:2636170dc55a0931d013014a72ae26c0c2521d4b61a28354b3e2e5369fa335a3 AS download

# Pull any fixes that may not have propagated to the parent image yet. Note that the --security flag
# is not used because sometimes a security fix is not marked as a security fix :(
RUN microdnf update --nodocs --setopt=keepcache=0 -y

ARG TARGETOS
ARG TARGETARCH

WORKDIR /download

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

# Download the matching version of cosign
# IMPORTANT: The version of cosign is hard-coded here because the version of cosign from go.mod
# pulls in a version of docker that contains a CVE. In the go.mod we can make it use a patched
# version of the docker library. However, the pre-compiled version of cosign will not contain the
# docker fix. The lowest version of cosign that contains the docker fix is v2.4.0. Unfortunately,
# that version requires go 1.22 which is not yet supported in the build chain. Thus, we cannot
# update go.mod to use it. For this reason, we use a different cosign version here.
RUN COSIGN_VERSION='v2.4.0' && \
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
EC_GIT_SHA=$( git rev-parse --short HEAD ); \
echo "EC_GIT_SHA=$EC_GIT_SHA"; \
\
EC_VERSION="v0.2"; \
echo "EC_VERSION=$EC_VERSION"; \
\
EC_BASE_TAG="${EC_VERSION}-patch-base"; \
echo "EC_BASE_TAG=$EC_BASE_TAG"; \
git log -n1 --format="%h %s" "$EC_BASE_TAG"; \
\
EC_PATCH_NUM=$( git rev-list --merges --count ${EC_BASE_TAG}..HEAD ); \
echo "EC_PATCH_NUM=$EC_PATCH_NUM"; \
\
EC_FULL_VERSION="${EC_VERSION}.${EC_PATCH_NUM}"; \
echo "EC_FULL_VERSION=$EC_FULL_VERSION"; \
\
BUILDS="${BUILD_LIST}"; \
echo "BUILDS=$BUILDS"; \
\
for os_arch in ${BUILDS}; do \
export GOOS="${os_arch%_*}"; \
export GOARCH="${os_arch#*_}"; \
[ "$GOOS" = "windows" ] && DOT_EXE=".exe" || DOT_EXE=""; \
BINFILE="ec_${GOOS}_${GOARCH}${DOT_EXE}"; \
echo "Building ${BINFILE} for ${EC_FULL_VERSION}"; \
go build \
-trimpath \
--mod=readonly \
-ldflags="-s -w -X github.com/enterprise-contract/ec-cli/internal/version.Version=${EC_FULL_VERSION}" \
-o "dist/${BINFILE}"; \
done

## Final image

Expand All @@ -150,10 +118,9 @@ LABEL \

# Pull any fixes that may not have propagated to the parent image yet. Note that the --security flag
# is not used because sometimes a security fix is not marked as a security fix :(
# Also, install cosign and other tools we want to use in the Tekton task
# Also, install other tools we want to use in the Tekton task
RUN microdnf update --nodocs --setopt=keepcache=0 -y && \
microdnf -y --nodocs --setopt=keepcache=0 install git-core jq
COPY --from=download /download/cosign /usr/local/bin/cosign
microdnf -y --nodocs --setopt=keepcache=0 install git-core jq

# 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 @@ -167,13 +134,17 @@ RUN gzip /usr/local/bin/ec_*
# Copy the one ec binary that can run in this container
COPY --from=build "/build/dist/ec_${TARGETOS}_${TARGETARCH}" /usr/local/bin/ec

# Add a cosign wrapper command to handle "cosign initialize" for backwards
# compatibility with older task definitions
COPY --from=build /build/hack/fake-cosign.sh /usr/local/bin/cosign

# OpenShift preflight check requires a license
COPY --from=build /build/LICENSE /licenses/LICENSE

# OpenShift preflight check requires a non-root user
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 All @@ -51,6 +52,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
}
Loading

0 comments on commit 1ee6a12

Please sign in to comment.