Skip to content

Commit

Permalink
Add container signing and SBOMs (#837)
Browse files Browse the repository at this point in the history
* Add container signing and SBOMs

Signed-off-by: Jakub Scholz <[email protected]>

* Review comments PP

Signed-off-by: Jakub Scholz <[email protected]>

---------

Signed-off-by: Jakub Scholz <[email protected]>
  • Loading branch information
scholzj authored Oct 2, 2023
1 parent da9fac4 commit 64d0235
Show file tree
Hide file tree
Showing 17 changed files with 202 additions and 52 deletions.
8 changes: 0 additions & 8 deletions .azure/scripts/container-build.sh

This file was deleted.

20 changes: 0 additions & 20 deletions .azure/scripts/container-push.sh

This file was deleted.

11 changes: 11 additions & 0 deletions .azure/scripts/install_cosign.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/usr/bin/env bash

readonly VERSION="2.2.0"

ARCH=$1
if [ -z "$ARCH" ]; then
ARCH="amd64"
fi

curl -L https://github.com/sigstore/cosign/releases/download/v${VERSION}/cosign-linux-${ARCH} > cosign && chmod +x cosign
sudo mv cosign /usr/bin/
14 changes: 14 additions & 0 deletions .azure/scripts/install_syft.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -e

readonly VERSION="0.90.0"

ARCH=$1
if [ -z "$ARCH" ]; then
ARCH="amd64"
fi

wget https://github.com/anchore/syft/releases/download/v${VERSION}/syft_${VERSION}_linux_${ARCH}.tar.gz -O syft.tar.gz
tar xf syft.tar.gz -C /tmp
chmod +x /tmp/syft
sudo mv /tmp/syft /usr/bin
8 changes: 0 additions & 8 deletions .azure/scripts/java-build.sh

This file was deleted.

4 changes: 2 additions & 2 deletions .azure/templates/jobs/build_container.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
vmImage: 'Ubuntu-22.04'
# Pipeline steps
steps:
- template: '../steps/setup_docker.yaml'
- template: '../steps/prerequisites/install_docker.yaml'
- task: DownloadPipelineArtifact@2
inputs:
source: '${{ parameters.artifactSource }}'
Expand All @@ -26,7 +26,7 @@ jobs:
runId: '${{ parameters.artifactRunId }}'
- bash: tar -xvf target.tar
displayName: "Untar the target directory"
- bash: ".azure/scripts/container-build.sh"
- bash: "make docker_build docker_save"
env:
DOCKER_BUILDKIT: 1
BUILD_REASON: $(Build.Reason)
Expand Down
4 changes: 2 additions & 2 deletions .azure/templates/jobs/build_docs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ jobs:
steps:
# Get cached Maven repository
- template: "../steps/maven_cache.yaml"
- template: '../steps/setup_java.yaml'
- template: '../steps/prerequisites/install_java.yaml'
parameters:
JDK_VERSION: $(jdk_version)
- template: '../steps/setup_asciidoc.yaml'
- template: '../steps/prerequisites/install_asciidoc.yaml'
- bash: "make docu_html docu_htmlnoheader"
displayName: "Build docs"
env:
Expand Down
4 changes: 2 additions & 2 deletions .azure/templates/jobs/build_java.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ jobs:
steps:
# Get cached Maven repository
- template: "../steps/maven_cache.yaml"
- template: '../steps/setup_java.yaml'
- template: '../steps/prerequisites/install_java.yaml'
parameters:
JDK_VERSION: $(jdk_version)
- bash: "make spotbugs"
displayName: "Spotbugs"
env:
MVN_ARGS: "-e -V -B"
- bash: ".azure/scripts/java-build.sh"
- bash: "make java_verify"
displayName: "Build & Test Java"
env:
BUILD_REASON: $(Build.Reason)
Expand Down
78 changes: 74 additions & 4 deletions .azure/templates/jobs/push_container.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ jobs:
vmImage: 'Ubuntu-22.04'
# Pipeline steps
steps:
- template: '../steps/setup_docker.yaml'
- template: '../steps/prerequisites/install_docker.yaml'
- template: "../steps/prerequisites/install_cosign.yaml"
- template: "../steps/prerequisites/install_syft.yaml"
- ${{ each arch in parameters.architectures }}:
- task: DownloadPipelineArtifact@2
inputs:
Expand All @@ -19,14 +21,82 @@ jobs:
pipeline: '${{ parameters.artifactPipeline }}'
runVersion: '${{ parameters.artifactRunVersion }}'
runId: '${{ parameters.artifactRunId }}'
- bash: ".azure/scripts/container-push.sh"
# Push containers and their manifests
- bash: "docker login -u $DOCKER_USER -p $DOCKER_PASS $DOCKER_REGISTRY"
displayName: "Login to container registry"
env:
BUILD_REASON: $(Build.Reason)
BRANCH: $(Build.SourceBranch)
DOCKER_USER: $(QUAY_USER)
DOCKER_PASS: $(QUAY_PASS)
DOCKER_REGISTRY: "quay.io"
- bash: "make docker_delete_manifest"
displayName: "Delete existing container manifest"
env:
BUILD_REASON: $(Build.Reason)
BRANCH: $(Build.SourceBranch)
DOCKER_REGISTRY: "quay.io"
DOCKER_ORG: "strimzi"
DOCKER_TAG: '${{ parameters.dockerTag }}'
ARCHITECTURES: ${{ join(' ', parameters.architectures) }}
displayName: "Tag & Push container"
- ${{ each arch in parameters.architectures }}:
- bash: make docker_load docker_tag docker_push docker_amend_manifest docker_delete_archive
displayName: "Push the ${{ arch }} containers and create manifest"
env:
BUILD_REASON: $(Build.Reason)
BRANCH: $(Build.SourceBranch)
DOCKER_REGISTRY: "quay.io"
DOCKER_ORG: "strimzi"
DOCKER_TAG: '${{ parameters.dockerTag }}'
DOCKER_ARCHITECTURE: ${{ arch }}
- bash: "make docker_push_manifest"
displayName: "Push container manifest"
env:
BUILD_REASON: $(Build.Reason)
BRANCH: $(Build.SourceBranch)
DOCKER_REGISTRY: "quay.io"
DOCKER_ORG: "strimzi"
DOCKER_TAG: '${{ parameters.dockerTag }}'
- bash: "make docker_sign_manifest"
displayName: "Sign container manifest"
env:
BUILD_REASON: $(Build.Reason)
BRANCH: $(Build.SourceBranch)
BUILD_ID: $(Build.BuildId)
BUILD_COMMIT: $(Build.SourceVersion)
DOCKER_REGISTRY: "quay.io"
DOCKER_ORG: "strimzi"
DOCKER_TAG: '${{ parameters.dockerTag }}'
COSIGN_PASSWORD: $(COSIGN_PASSWORD)
COSIGN_PRIVATE_KEY: $(COSIGN_PRIVATE_KEY)
# SBOMs generation, packaging, and signing
- ${{ each arch in parameters.architectures }}:
- bash: make docker_sbom
displayName: "Generate SBOMs for ${{ arch }} container"
env:
BUILD_REASON: $(Build.Reason)
BRANCH: $(Build.SourceBranch)
DOCKER_REGISTRY: "quay.io"
DOCKER_ORG: "strimzi"
DOCKER_TAG: '${{ parameters.dockerTag }}'
DOCKER_ARCHITECTURE: ${{ arch }}
COSIGN_PASSWORD: $(COSIGN_PASSWORD)
COSIGN_PRIVATE_KEY: $(COSIGN_PRIVATE_KEY)
- bash: tar -z -C ./sbom/ -cvpf sbom.tar.gz ./
displayName: "Tar the SBOM files"
- publish: $(System.DefaultWorkingDirectory)/sbom.tar.gz
artifact: SBOMs
displayName: "Publish the SBOM files"
# push the SBOMs to container registry only for releases
- ${{ each arch in parameters.architectures }}:
- bash: make docker_push_sbom
displayName: "Push SBOMs for ${{ arch }} container"
condition: startsWith(variables['build.sourceBranch'], 'refs/heads/release-')
env:
BUILD_REASON: $(Build.Reason)
BRANCH: $(Build.SourceBranch)
DOCKER_REGISTRY: "quay.io"
DOCKER_ORG: "strimzi"
DOCKER_TAG: '${{ parameters.dockerTag }}'
DOCKER_ARCHITECTURE: ${{ arch }}
COSIGN_PASSWORD: $(COSIGN_PASSWORD)
COSIGN_PRIVATE_KEY: $(COSIGN_PRIVATE_KEY)
File renamed without changes.
3 changes: 3 additions & 0 deletions .azure/templates/steps/prerequisites/install_cosign.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
steps:
- bash: ".azure/scripts/install_cosign.sh"
displayName: "Install cosign"
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# Steps needed for local Docker installation
steps:
- task: DockerInstaller@0
displayName: Docker Installer
displayName: Install Docker
inputs:
dockerVersion: 20.10.8
# Versions can be found from https://download.docker.com/linux/static/stable/x86_64/
dockerVersion: 24.0.5
releaseType: stable
- bash: |
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
# Step to setup JAVA on the agent
# Step to configure JAVA on the agent
parameters:
- name: JDK_VERSION
default: '11'

steps:
- task: JavaToolInstaller@0
inputs:
versionSpec: $(JDK_VERSION)
jdkArchitectureOption: 'x64'
jdkSourceOption: 'PreInstalled'
displayName: 'Configure Java'
displayName: 'Configure Java'
3 changes: 3 additions & 0 deletions .azure/templates/steps/prerequisites/install_syft.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
steps:
- bash: ".azure/scripts/install_syft.sh"
displayName: "Install Syft"
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
* The `bridge.tracing=jaeger` configuration is not valid anymore.
* The OpenTelemetry based tracing is the only available by using `bridge.tracing=opentelemetry`.
* Fixed logging Kafka TLS related password for trust/key stores on startup.
* Sign containers using cosign
* Generate and publish Software Bill of Materials (SBOMs) of Strimzi containers

## 0.26.1

Expand Down
46 changes: 45 additions & 1 deletion Makefile.docker
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
# default latest) variables are used to name the Docker image. DOCKER_REGISTRY identifies
# the registry where the image will be pushed (default is Docker Hub).
TOPDIR=$(dir $(lastword $(MAKEFILE_LIST)))
SBOM_DIR=$(TOPDIR)sbom

DOCKERFILE_DIR ?= ./
DOCKER_REGISTRY ?= docker.io
DOCKER_ORG ?= $(USER)
Expand All @@ -16,6 +18,7 @@ RELEASE_VERSION ?= $(shell cat $(TOPDIR)/release.version)
ifdef DOCKER_ARCHITECTURE
DOCKER_PLATFORM = --platform linux/$(DOCKER_ARCHITECTURE)
DOCKER_PLATFORM_TAG_SUFFIX = -$(DOCKER_ARCHITECTURE)
SBOM_DIR=$(TOPDIR)sbom/$(DOCKER_ARCHITECTURE)
endif

.PHONY: docker_build
Expand Down Expand Up @@ -48,6 +51,11 @@ docker_push: docker_tag
# Push the $(DOCKER_TAG)-tagged image to the registry
docker push $(DOCKER_REGISTRY)/$(DOCKER_ORG)/$(PROJECT_NAME):$(DOCKER_TAG)$(DOCKER_PLATFORM_TAG_SUFFIX)

.PHONY: docker_delete_archive
docker_delete_archive:
# Deletes the archive
rm kafka-bridge$(DOCKER_PLATFORM_TAG_SUFFIX).tar.gz

.PHONY: docker_amend_manifest
docker_amend_manifest:
# Create / Amend the manifest
Expand All @@ -61,4 +69,40 @@ docker_push_manifest:
.PHONY: docker_delete_manifest
docker_delete_manifest:
# Delete the manifest to the registry, ignore the error if manifest doesn't exist
docker manifest rm $(DOCKER_REGISTRY)/$(DOCKER_ORG)/$(PROJECT_NAME):$(DOCKER_TAG) || true
docker manifest rm $(DOCKER_REGISTRY)/$(DOCKER_ORG)/$(PROJECT_NAME):$(DOCKER_TAG) || true

.PHONY: docker_sign_manifest
docker_sign_manifest:
# Signs the manifest and its images
@echo $$COSIGN_PRIVATE_KEY | base64 -d > cosign.key
MANIFEST_DIGEST=$(shell docker buildx imagetools inspect $(DOCKER_REGISTRY)/$(DOCKER_ORG)/$(PROJECT_NAME):$(DOCKER_TAG) --format '{{ json . }}' | jq -r .manifest.digest); \
cosign sign --recursive --tlog-upload=false -a author=StrimziCI -a BuildID=$(BUILD_ID) -a Commit=$(BUILD_COMMIT) --key cosign.key $(DOCKER_REGISTRY)/$(DOCKER_ORG)/$(PROJECT_NAME)@$$MANIFEST_DIGEST
@rm cosign.key

.PHONY: docker_sbom
docker_sbom:
# Saves the SBOM of the image
test -d $(SBOM_DIR) || mkdir -p $(SBOM_DIR)
# Generate the text format
MANIFEST_DIGEST=$(shell docker buildx imagetools inspect $(DOCKER_REGISTRY)/$(DOCKER_ORG)/$(PROJECT_NAME):$(DOCKER_TAG)$(DOCKER_PLATFORM_TAG_SUFFIX) --format '{{ json . }}' | jq -r .manifest.digest); \
syft packages $(DOCKER_REGISTRY)/$(DOCKER_ORG)/$(PROJECT_NAME)@$$MANIFEST_DIGEST --output syft-table --file $(SBOM_DIR)/$(DOCKER_REGISTRY)/$(DOCKER_ORG)/$(PROJECT_NAME)/$(DOCKER_TAG)/$$MANIFEST_DIGEST.txt
# Generate the SPDX JSON format for machine processing
MANIFEST_DIGEST=$(shell docker buildx imagetools inspect $(DOCKER_REGISTRY)/$(DOCKER_ORG)/$(PROJECT_NAME):$(DOCKER_TAG)$(DOCKER_PLATFORM_TAG_SUFFIX) --format '{{ json . }}' | jq -r .manifest.digest); \
syft packages $(DOCKER_REGISTRY)/$(DOCKER_ORG)/$(PROJECT_NAME)@$$MANIFEST_DIGEST --output spdx-json --file $(SBOM_DIR)/$(DOCKER_REGISTRY)/$(DOCKER_ORG)/$(PROJECT_NAME)/$(DOCKER_TAG)/$$MANIFEST_DIGEST.json
# Sign the TXT and SPDX-JSON SBOM
@echo $$COSIGN_PRIVATE_KEY | base64 -d > cosign.key
MANIFEST_DIGEST=$(shell docker buildx imagetools inspect $(DOCKER_REGISTRY)/$(DOCKER_ORG)/$(PROJECT_NAME):$(DOCKER_TAG)$(DOCKER_PLATFORM_TAG_SUFFIX) --format '{{ json . }}' | jq -r .manifest.digest); \
cosign sign-blob --tlog-upload=false --key cosign.key --bundle $(SBOM_DIR)/$(DOCKER_REGISTRY)/$(DOCKER_ORG)/$(PROJECT_NAME)/$(DOCKER_TAG)/$$MANIFEST_DIGEST.txt.bundle $(SBOM_DIR)/$(DOCKER_REGISTRY)/$(DOCKER_ORG)/$(PROJECT_NAME)/$(DOCKER_TAG)/$$MANIFEST_DIGEST.txt
MANIFEST_DIGEST=$(shell docker buildx imagetools inspect $(DOCKER_REGISTRY)/$(DOCKER_ORG)/$(PROJECT_NAME):$(DOCKER_TAG)$(DOCKER_PLATFORM_TAG_SUFFIX) --format '{{ json . }}' | jq -r .manifest.digest); \
cosign sign-blob --tlog-upload=false --key cosign.key --bundle $(SBOM_DIR)/$(DOCKER_REGISTRY)/$(DOCKER_ORG)/$(PROJECT_NAME)/$(DOCKER_TAG)/$$MANIFEST_DIGEST.json.bundle $(SBOM_DIR)/$(DOCKER_REGISTRY)/$(DOCKER_ORG)/$(PROJECT_NAME)/$(DOCKER_TAG)/$$MANIFEST_DIGEST.json
@rm cosign.key

.PHONY: docker_push_sbom
docker_push_sbom:
# Push the SBOMto the container registry and sign it
@echo $$COSIGN_PRIVATE_KEY | base64 -d > cosign.key
MANIFEST_DIGEST=$(shell docker buildx imagetools inspect $(DOCKER_REGISTRY)/$(DOCKER_ORG)/$(PROJECT_NAME):$(DOCKER_TAG)$(DOCKER_PLATFORM_TAG_SUFFIX) --format '{{ json . }}' | jq -r .manifest.digest); \
cosign attach sbom --sbom $(SBOM_DIR)/$(DOCKER_REGISTRY)/$(DOCKER_ORG)/$(PROJECT_NAME)/$(DOCKER_TAG)/$$MANIFEST_DIGEST.json $(DOCKER_REGISTRY)/$(DOCKER_ORG)/$(PROJECT_NAME):$(DOCKER_TAG)$(DOCKER_PLATFORM_TAG_SUFFIX)
MANIFEST_DIGEST=$(shell docker buildx imagetools inspect $(DOCKER_REGISTRY)/$(DOCKER_ORG)/$(PROJECT_NAME):$(DOCKER_TAG)$(DOCKER_PLATFORM_TAG_SUFFIX) --format '{{ json . }}' | jq -r .manifest.digest); \
cosign sign --tlog-upload=false -a author=StrimziCI -a BuildID=$(BUILD_ID) -a Commit=$(BUILD_COMMIT) --key cosign.key --attachment sbom $(DOCKER_REGISTRY)/$(DOCKER_ORG)/$(PROJECT_NAME)@$$MANIFEST_DIGEST
@rm cosign.key
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,42 @@ Learn more on how you can contribute on our [Join Us](https://strimzi.io/join-us
## License

Strimzi Kafka Bridge is licensed under the [Apache License](./LICENSE), Version 2.0

## Container signatures

From the 0.27.0 release, Strimzi Kafka Bridge containers are signed using the [`cosign` tool](https://github.com/sigstore/cosign).
Strimzi currently does not use the keyless signing and the transparency log.
To verify the container, you can copy the following public key into a file:

```
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAET3OleLR7h0JqatY2KkECXhA9ZAkC
TRnbE23Wb5AzJPnpevvQ1QUEQQ5h/I4GobB7/jkGfqYkt6Ct5WOU2cc6HQ==
-----END PUBLIC KEY-----
```

And use it to verify the signature:

```
cosign verify --key strimzi.pub quay.io/strimzi/kafka-bridge:latest --insecure-ignore-tlog=true
```

## Software Bill of Materials (SBOM)

From the 0.27.0 release, Strimzi Kafka Bridge publishes the software bill of materials (SBOM) of our containers.
The SBOMs are published as an archive with `SPDX-JSON` and `Syft-Table` formats signed using cosign.
For releases, they are also pushed into the container registry.
To verify the SBOM signatures, please use the Strimzi public key:

```
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAET3OleLR7h0JqatY2KkECXhA9ZAkC
TRnbE23Wb5AzJPnpevvQ1QUEQQ5h/I4GobB7/jkGfqYkt6Ct5WOU2cc6HQ==
-----END PUBLIC KEY-----
```

You can use it to verify the signature of the SBOM files with the following command:

```
cosign verify-blob --key cosign.pub --bundle <SBOM-file>.bundle --insecure-ignore-tlog=true <SBOM-file>
```

0 comments on commit 64d0235

Please sign in to comment.