diff --git a/.github/workflows/build-test-containers.yaml b/.github/workflows/build-test-containers.yaml new file mode 100644 index 0000000..128c3f0 --- /dev/null +++ b/.github/workflows/build-test-containers.yaml @@ -0,0 +1,62 @@ +name: Build Test Containers +run-name: Build Test Containers +on: + workflow_dispatch: + push: + branches: + - 'main' + paths: + - 'container-images' + - '.github/workflows/build-test-containers.yaml' +jobs: + Explore-GitHub-Actions: + env: + RUSTC_VERSION: 1.72.0 + runs-on: ubuntu-24.04 + + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Check out guest-components + uses: actions/checkout@v4 + with: + repository: confidential-containers/guest-components + ref: refs/heads/main + path: ./guest-components + - name: Install Protoc + uses: arduino/setup-protoc@v3 + - name: Import github@runner.com key + working-directory: container-images + run: gpg --batch --import keys/sign/github-runner.keys + - name: Install expect + run: sudo apt-get install -y expect + - name: Install cosign + uses: sigstore/cosign-installer@main + with: + cosign-release: "v2.4.1" + - name: Log in to ghcr + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Make all + env: + COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }} + run: | + cd guest-components/attestation-agent/coco_keyprovider + cargo build --release + RUST_LOG=coco_keyprovider cargo run --release -- --socket 127.0.0.1:50000 & + cd ../../../container-images + echo "Waiting for coco-keyprovider on localhost:50000" + timeout_count=1 + while ! nc -z localhost 50000; do + timeout_count=$((timeout_count+1)) + sleep 1 + if [ $timeout_count == 5 ]; then + echo "ERROR: Timed out. Exiting." + exit 1 + fi + done + echo "coco-keyprovider is ready" + make all diff --git a/container-images/Makefile b/container-images/Makefile new file mode 100644 index 0000000..1bda3b9 --- /dev/null +++ b/container-images/Makefile @@ -0,0 +1,118 @@ +# +# This makefile's targets rebuild various container images that can be used +# for development and testing in the CoCo project. +# They also are intended to serve as an up-to-date reference for creating +# new images. +# +# Note: The targets push to ghcr, which requires proper credentials and +# `docker login`. +# + +.PHONY: unsig \ +cosign-sig \ +simple-sig \ +enc-unsig \ +enc-cosign-sig \ +test-container-unencrypted \ +test-container-encrypted \ +busybox + +SHELL=/bin/bash + + +# FIXME need to choose sane package URLs/names/tags +COCO_PKG=confidential-containers/test-container +COCO_PKG_IMGRS=confidential-cointainers/test-container-image-rs + + + +all: \ + unsig \ + cosign-sig \ + simple-sig \ + enc-unsig \ + enc-cosign-sig \ + test-container-unencrypted \ + test-container-encrypted \ + busybox + + + +unsig: + docker build \ + -t ghcr.io/$(COCO_PKG):unsig \ + -f dockerfiles/alpine-with-sshd/Dockerfile \ + . + docker push ghcr.io/$(COCO_PKG):unsig + + +cosign-sig: + docker build \ + -t ghcr.io/$(COCO_PKG):cosign-sig \ + -f dockerfiles/alpine-with-sshd/Dockerfile \ + . + docker push ghcr.io/$(COCO_PKG):cosign-sig + # FIXME Replace expect script with something better + ${CURDIR}/scripts/make-cosign-sig.exp $(COCO_PKG) cosign-sig + + +# NOTE: This depends on a gpg key owned by git@runner.com. +# That is, before issuing this make target, have to do something like: +# $ gpg --batch --import ./keys/sign/github-runner.keys +simple-sig: + skopeo \ + copy \ + --debug \ + --insecure-policy \ + --sign-by git@runner.com \ + --sign-passphrase-file $(shell pwd)/keys/sign/git-runner-password.txt \ + docker-daemon:ghcr.io/$(COCO_PKG):unsig \ + docker://ghcr.io/$(COCO_PKG):simple-sig + + +# NOTE: This requires coco-keyprovider running from guest-components... +# That is, before issuing this make target, have to do something like: +# $ cd guest-components/attestation-agent/coco_keyprovider +# $ RUST_LOG=coco_keyprovider cargo run --release -- --socket 127.0.0.1:50000 +enc-unsig: unsig + OCICRYPT_KEYPROVIDER_CONFIG="$(shell pwd)/configs/ocicrypt.conf" \ + skopeo copy \ + --insecure-policy \ + --encryption-key provider:attestation-agent:keypath=$(shell pwd)/keys/encrypt/key1::keyid=kbs:///default/key/key_id1::algorithm=A256GCM \ + docker-daemon:ghcr.io/$(COCO_PKG):unsig \ + docker://ghcr.io/$(COCO_PKG):enc-unsig + + +# NOTE: see enc-unsig about coco-keyprovider +# NOTE: see cosign-sig about replacing expect script +enc-cosign-sig: cosign-sig + OCICRYPT_KEYPROVIDER_CONFIG="$(shell pwd)/configs/ocicrypt.conf" \ + skopeo copy \ + --insecure-policy \ + --encryption-key provider:attestation-agent:keypath=$(shell pwd)/keys/encrypt/key1::keyid=kbs:///default/key/key_id1::algorithm=A256GCM \ + docker-daemon:ghcr.io/$(COCO_PKG):cosign-sig \ + docker://ghcr.io/$(COCO_PKG):enc-cosign-sig + ./scripts/make-cosign-sig.exp $(COCO_PKG) enc-cosign-sig + + +test-container-unencrypted: + docker build \ + -t ghcr.io/$(COCO_PKG):unencrypted \ + -f dockerfiles/alpine-with-sshd/Dockerfile \ + . + docker push ghcr.io/$(COCO_PKG):unencrypted + + +# NOTE: see enc-unsig about coco-keyprovider +test-container-encrypted: test-container-unencrypted + OCICRYPT_KEYPROVIDER_CONFIG="$(shell pwd)/configs/ocicrypt.conf" \ + skopeo copy \ + --insecure-policy \ + --encryption-key provider:attestation-agent:keypath=$(shell pwd)/keys/encrypt/key1::keyid=kbs:///default/key/key_id1::algorithm=A256GCM \ + docker-daemon:ghcr.io/$(COCO_PKG):unencrypted \ + docker://ghcr.io/$(COCO_PKG):encrypted + + +busybox: + docker build -t ghcr.io/$(COCO_PKG_IMGRS):busybox dockerfiles/busybox + docker push ghcr.io/$(COCO_PKG_IMGRS):busybox diff --git a/container-images/configs/ocicrypt.conf b/container-images/configs/ocicrypt.conf new file mode 100644 index 0000000..52bc66d --- /dev/null +++ b/container-images/configs/ocicrypt.conf @@ -0,0 +1,5 @@ +{ + "key-providers": { + "attestation-agent": { + "grpc": "127.0.0.1:50000" +}}} diff --git a/container-images/dockerfiles/alpine-with-sshd/Dockerfile b/container-images/dockerfiles/alpine-with-sshd/Dockerfile new file mode 100644 index 0000000..aefa66e --- /dev/null +++ b/container-images/dockerfiles/alpine-with-sshd/Dockerfile @@ -0,0 +1,21 @@ +FROM alpine:3.14 +RUN apk update && apk upgrade && apk add openssh-server + +# Use the ssh-demo image's legacy keys. To generate new ones, can do something +# like: +# RUN ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -P "" +COPY keys/ssh/ssh_host_ed25519_key /etc/ssh/ssh_host_ed25519_key +COPY keys/ssh/ssh_host_ed25519_key.pub /etc/ssh/ssh_host_ed25519_key.pub + +# A password needs to be set for login to work. An empty password is +# unproblematic as password-based login to root is not allowed. +RUN passwd -d root + +# Use the ssh-demo user/client's legacy keys. To generate new ones, can do +# something like: +# $ ssh-keygen -t ed25519 -f ccv0-ssh -P "" -C ""` +COPY keys/ssh/ccv0-ssh.pub /root/.ssh/authorized_keys +ENTRYPOINT /usr/sbin/sshd -D + +# Can connect to the running container with something like: +# $ ssh -i keys/ssh/ccv0-ssh root@ diff --git a/container-images/dockerfiles/busybox/Dockerfile b/container-images/dockerfiles/busybox/Dockerfile new file mode 100644 index 0000000..5f1b2db --- /dev/null +++ b/container-images/dockerfiles/busybox/Dockerfile @@ -0,0 +1,3 @@ +FROM busybox:1.36 + +CMD ["sh"] diff --git a/container-images/keys/encrypt/key1 b/container-images/keys/encrypt/key1 new file mode 100644 index 0000000..143d8f4 --- /dev/null +++ b/container-images/keys/encrypt/key1 @@ -0,0 +1 @@ +0È¥±²r‰´ðZõORõêUÚØëC<ÿcÖ\B \ No newline at end of file diff --git a/container-images/keys/sign/README.md b/container-images/keys/sign/README.md new file mode 100644 index 0000000..5e9f925 --- /dev/null +++ b/container-images/keys/sign/README.md @@ -0,0 +1,79 @@ +# README + + +## For cosign +Keys are generated with something like: +``` + $ COSIGN_PASSWORD=just1testing2password3 cosign generate-key-pair +``` + +Then upload them manually to the github repo's secrets. Name them like so: +``` + COSIGN_PASSWORD + COSIGN_PRIVATE_KEY + COSIGN_PUBLIC_KEY +``` + +Also a good tutorial is +[here](https://dev.to/n3wt0n/sign-your-container-images-with-cosign-github-actions-and-github-container-registry-3mni), +though the approach is a little more autoamted and has a keener eye towards +real-world usage. +The key-generation step would be more like the following, which automatically +uploads the public key, private key, and key secret to the github repo: +``` + $ GITHUB_TOKEN=ghp_... \ + COSIGN_PASSWORD=just1testing2password3 \ + cosign generate-key-pair github://portersrc/infra +``` +This may be a better realistic case, but it puts the private key in a github +secret, and I want to just keep it open and readable in the infra repo for +testing purposes. + + + + + + + +## For "simple signing" (i.e. with gpg) +The first step was to generate a key. Choose the default options for these +purposes. The command is: +``` + $ gpg --full-generate-key +``` +It has some prompts. The user for testing purposes is: +``` + Github Runner + git@runner.com + just1testing2password3 +``` + + +Then we exported it. The `--export-secret-key` option is sufficient for +exporting both the secret and public key. Example command: +``` + $ gpg --export-secret-key F63DB2A1AB7C7F195F698C9ED9582CADF7FBCC5D &> github-runner.keys +``` + +This is all that was needed (in addition to creating a .txt file with the +password to make automation with skopeo testing easy). + +The CI will import the key (using `--batch` to avoid typing the password): +``` + $ gpg --batch --import github-runner.keys +``` + + +### Other helpful commands +List public and secret keys: +``` + $ gpg --list-keys + $ gpg --list-secret-keys +``` + +Example of deleting a key (must first delete the secret one first, then the +public one): +``` + $ gpg --delete-secret-keys F63DB2A1AB7C7F195F698C9ED9582CADF7FBCC5D + $ gpg --delete-keys F63DB2A1AB7C7F195F698C9ED9582CADF7FBCC5D +``` diff --git a/container-images/keys/sign/cosign.key b/container-images/keys/sign/cosign.key new file mode 100644 index 0000000..1785a96 --- /dev/null +++ b/container-images/keys/sign/cosign.key @@ -0,0 +1,11 @@ +-----BEGIN ENCRYPTED SIGSTORE PRIVATE KEY----- +eyJrZGYiOnsibmFtZSI6InNjcnlwdCIsInBhcmFtcyI6eyJOIjozMjc2OCwiciI6 +OCwicCI6MX0sInNhbHQiOiJYc083MWhFYVZEMEdMdDh3Q0ZmTU9ybmxKb0RQMG90 +dGY5bnJmTlZJbXVnPSJ9LCJjaXBoZXIiOnsibmFtZSI6Im5hY2wvc2VjcmV0Ym94 +Iiwibm9uY2UiOiJlWlZDRGI0c0RMT1NzWnZ1QjV0WjAwVjhBMkorV3gvQSJ9LCJj +aXBoZXJ0ZXh0IjoiSlhLOXFUZzNJaFlMNkd0MG9qekpyUkQ0ZXRjUkh0RmZmYUJB +L3VmZDFUNFVXQVphcytmR0NGNjFQQnlVTDljTTdONzl2MUIrSDhtd0FhZmYycUVj +S0RUM3hSYTMwcU9ET29uQUQ0WnRGT1h5K3Zwd0xkcThjT2JkQTZBUVdSREpFZzlL +ak1zUjZXNVRuSk9xL0ZHc1g2a2QzbjZNbnlZM2ptaXY1V0sveGVJeUdUVUJhVVJM +V1o2MmdWeHlCTzhtNzZRaHcrK1g5NTRqWUE9PSJ9 +-----END ENCRYPTED SIGSTORE PRIVATE KEY----- diff --git a/container-images/keys/sign/cosign.pub b/container-images/keys/sign/cosign.pub new file mode 100644 index 0000000..97c389d --- /dev/null +++ b/container-images/keys/sign/cosign.pub @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWT07eR1HNK3D2iqHotE0c389aSTh +Lj0B39PXTBcJzJpkXPO82lLGQdc47V5HPWaPZ2Fc3DWyRoz1oWbnLlvQ5Q== +-----END PUBLIC KEY----- diff --git a/container-images/keys/sign/git-runner-password.txt b/container-images/keys/sign/git-runner-password.txt new file mode 100644 index 0000000..2912acc --- /dev/null +++ b/container-images/keys/sign/git-runner-password.txt @@ -0,0 +1 @@ +just1testing2password3 diff --git a/container-images/keys/sign/github-runner.keys b/container-images/keys/sign/github-runner.keys new file mode 100644 index 0000000..cadfcb7 Binary files /dev/null and b/container-images/keys/sign/github-runner.keys differ diff --git a/container-images/keys/ssh/ccv0-ssh b/container-images/keys/ssh/ccv0-ssh new file mode 100644 index 0000000..0657b74 --- /dev/null +++ b/container-images/keys/ssh/ccv0-ssh @@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACAfiGV2X4o+6AgjVBaY/ZR2UvZp84dVYF5bpNZGMLylQwAAAIhawtHJWsLR +yQAAAAtzc2gtZWQyNTUxOQAAACAfiGV2X4o+6AgjVBaY/ZR2UvZp84dVYF5bpNZGMLylQw +AAAEAwWYIBvBxQZgk0irFku3Lj1Xbfb8dHtVM/kkz/Uz/l2h+IZXZfij7oCCNUFpj9lHZS +9mnzh1VgXluk1kYwvKVDAAAAAAECAwQF +-----END OPENSSH PRIVATE KEY----- diff --git a/container-images/keys/ssh/ccv0-ssh.pub b/container-images/keys/ssh/ccv0-ssh.pub new file mode 100644 index 0000000..d412d78 --- /dev/null +++ b/container-images/keys/ssh/ccv0-ssh.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB+IZXZfij7oCCNUFpj9lHZS9mnzh1VgXluk1kYwvKVD diff --git a/container-images/keys/ssh/ssh_host_ed25519_key b/container-images/keys/ssh/ssh_host_ed25519_key new file mode 100644 index 0000000..59240d5 --- /dev/null +++ b/container-images/keys/ssh/ssh_host_ed25519_key @@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACBZCWq2MBTX8Bkvdtf9htpfqTTosRzYtTQgbeHADF1k3wAAAJiKehLQinoS +0AAAAAtzc2gtZWQyNTUxOQAAACBZCWq2MBTX8Bkvdtf9htpfqTTosRzYtTQgbeHADF1k3w +AAAEAlKROeyUCGfooVH87ObAnd4FAgvSnCgiIY2R6G+PpRTVkJarYwFNfwGS921/2G2l+p +NOixHNi1NCBt4cAMXWTfAAAAFHJvb3RAYnVpbGRraXRzYW5kYm94AQ== +-----END OPENSSH PRIVATE KEY----- diff --git a/container-images/keys/ssh/ssh_host_ed25519_key.pub b/container-images/keys/ssh/ssh_host_ed25519_key.pub new file mode 100644 index 0000000..9b9fd21 --- /dev/null +++ b/container-images/keys/ssh/ssh_host_ed25519_key.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFkJarYwFNfwGS921/2G2l+pNOixHNi1NCBt4cAMXWTf root@buildkitsandbox diff --git a/container-images/scripts/make-cosign-sig.exp b/container-images/scripts/make-cosign-sig.exp new file mode 100755 index 0000000..01e488f --- /dev/null +++ b/container-images/scripts/make-cosign-sig.exp @@ -0,0 +1,16 @@ +#!/usr/bin/expect + +set COCO_PKG [lindex $argv 0] +set IMG_TAG [lindex $argv 1] + +# XXX ONLY use for testing. Private key (cosign.key) is obviously exposed. +# And the password for this key is: just1testing2password3 +spawn cosign sign --key keys/sign/cosign.key ghcr.io/$COCO_PKG:$IMG_TAG + +#By typing 'y', you attest that (1) you are not submitting the personal data of any other person; and (2) you understand and agree to the statement and the Agreement terms at the URLs listed above. +expect "Are you sure you would like to continue?" + +# yes +send -- "y\n" + +expect eof