Skip to content

Commit

Permalink
Codify the creation of test containers
Browse files Browse the repository at this point in the history
Signed-off-by: Chris Porter <[email protected]>
  • Loading branch information
portersrc committed Oct 23, 2024
1 parent 02e5c59 commit e395f98
Show file tree
Hide file tree
Showing 17 changed files with 387 additions and 0 deletions.
62 changes: 62 additions & 0 deletions .github/workflows/build-test-containers.yaml
Original file line number Diff line number Diff line change
@@ -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 [email protected] 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
118 changes: 118 additions & 0 deletions container-images/Makefile
Original file line number Diff line number Diff line change
@@ -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 [email protected].
# 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 [email protected] \
--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
5 changes: 5 additions & 0 deletions container-images/configs/ocicrypt.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"key-providers": {
"attestation-agent": {
"grpc": "127.0.0.1:50000"
}}}
21 changes: 21 additions & 0 deletions container-images/dockerfiles/alpine-with-sshd/Dockerfile
Original file line number Diff line number Diff line change
@@ -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@<container-ip-addr>
65 changes: 65 additions & 0 deletions container-images/dockerfiles/alpine-with-sshd/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# SSH demo

To demonstrate confidential containers capabilities, we run a pod with SSH public key authentication.

Compared to the execution of and login to a shell on a pod, an SSH connection is cryptographically secured and requires a private key.
It cannot be established by unauthorized parties, such as someone who controls the node.
The container image contains the SSH host key that can be used for impersonating the host we will connect to.
Because this container image is encrypted, and the key to decrypting this image is only provided in measurable ways (e.g. attestation or encrypted initrd), and because the pod/guest memory is protected, even someone who controls the node cannot steal this key.

## Using a pre-provided container image

If you would rather build the image with your own keys, skip to [Building the container image](#building-the-container-image).
The [operator](/demos/operator-demo) can be used to set up a compatible runtime.

A demo image is provided at [docker.io/katadocker/ccv0-ssh](https://hub.docker.com/r/katadocker/ccv0-ssh).
It is encrypted with [Attestation Agent](https://github.com/confidential-containers/attestation-agent)'s [offline file system key broker](https://github.com/confidential-containers/attestation-agent/tree/64c12fbecfe90ba974d5fe4896bf997308df298d/src/kbc_modules/offline_fs_kbc) and [`aa-offline_fs_kbc-keys.json`](./aa-offline_fs_kbc-keys.json) as its key file.
The private key for establishing an SSH connection to this container is given in [`ccv0-ssh`](./ccv0-ssh).
To use it with SSH, its permissions should be adjusted: `chmod 600 ccv0-ssh`.
The host key fingerprint is `SHA256:wK7uOpqpYQczcgV00fGCh+X97sJL3f6G1Ku4rvlwtR0`.

All keys shown here are for demonstration purposes.
To achieve actually confidential containers, use a hardware trusted execution environment and **do not** reuse these keys.

Continue at [Connecting to the guest](#connecting-to-the-guest).

## Building the container image

The image built should be encrypted.
To receive a decryption key at run time, the Confidential Containers project utilizes the [Attestation Agent](https://github.com/confidential-containers/attestation-agent).

### Generating SSH keys

```sh
$ ssh-keygen -t ed25519 -f ccv0-ssh -P "" -C ""
```

generates an SSH key `ccv0-ssh` and the correspondent public key `ccv0-ssh.pub`.

### Building the image

The provided [`Dockerfile`](./Dockerfile) expects `ccv0-sh.pub` to exist.
Using Docker, you can build with

```sh
$ docker build -t ccv0-ssh .
```

Alternatively, Buildah can be used (`buildah build` or formerly `buildah bud`).
The SSH host key fingerprint is displayed during the build.

## Connecting to the guest

A [Kubernetes YAML file](./k8s-cc-ssh.yaml) specifying the [`kata`](https://github.com/kata-containers/kata-containers) runtime is included.
If you use a [self-built image](#building-the-container-image), you should replace the image specification with the image you built.
The default tag points to an `amd64` image, an `s390x` tag is also available.
With common CNI setups, on the same host, with the service running, you can connect via SSH with

```sh
$ ssh -i ccv0-ssh root@$(kubectl get service ccv0-ssh -o jsonpath="{.spec.clusterIP}")
```

You will be prompted about whether the host key fingerprint is correct.
This fingerprint should match the one specified above/displayed in the Docker build.

`crictl`-compatible [sandbox](./cri-sandbox-config.yaml) and [container](./cri-container-config.yaml) configurations are also included, which forward the pod SSH port (22) to 2222 on the host (use the `-p` flag in SSH).
3 changes: 3 additions & 0 deletions container-images/dockerfiles/busybox/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
FROM busybox:1.36

CMD ["sh"]
1 change: 1 addition & 0 deletions container-images/keys/encrypt/key1
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0����r���Z�OR��U���C<�c�\�B
64 changes: 64 additions & 0 deletions container-images/keys/sign/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# 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, though the approach is a little more autoamted
and has a keener eye towards real-world usage:
https://dev.to/n3wt0n/sign-your-container-images-with-cosign-github-actions-and-github-container-registry-3mni
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
[email protected]
Password:
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



11 changes: 11 additions & 0 deletions container-images/keys/sign/cosign.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
-----BEGIN ENCRYPTED SIGSTORE PRIVATE KEY-----
eyJrZGYiOnsibmFtZSI6InNjcnlwdCIsInBhcmFtcyI6eyJOIjozMjc2OCwiciI6
OCwicCI6MX0sInNhbHQiOiJYc083MWhFYVZEMEdMdDh3Q0ZmTU9ybmxKb0RQMG90
dGY5bnJmTlZJbXVnPSJ9LCJjaXBoZXIiOnsibmFtZSI6Im5hY2wvc2VjcmV0Ym94
Iiwibm9uY2UiOiJlWlZDRGI0c0RMT1NzWnZ1QjV0WjAwVjhBMkorV3gvQSJ9LCJj
aXBoZXJ0ZXh0IjoiSlhLOXFUZzNJaFlMNkd0MG9qekpyUkQ0ZXRjUkh0RmZmYUJB
L3VmZDFUNFVXQVphcytmR0NGNjFQQnlVTDljTTdONzl2MUIrSDhtd0FhZmYycUVj
S0RUM3hSYTMwcU9ET29uQUQ0WnRGT1h5K3Zwd0xkcThjT2JkQTZBUVdSREpFZzlL
ak1zUjZXNVRuSk9xL0ZHc1g2a2QzbjZNbnlZM2ptaXY1V0sveGVJeUdUVUJhVVJM
V1o2MmdWeHlCTzhtNzZRaHcrK1g5NTRqWUE9PSJ9
-----END ENCRYPTED SIGSTORE PRIVATE KEY-----
4 changes: 4 additions & 0 deletions container-images/keys/sign/cosign.pub
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWT07eR1HNK3D2iqHotE0c389aSTh
Lj0B39PXTBcJzJpkXPO82lLGQdc47V5HPWaPZ2Fc3DWyRoz1oWbnLlvQ5Q==
-----END PUBLIC KEY-----
1 change: 1 addition & 0 deletions container-images/keys/sign/git-runner-password.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
just1testing2password3
Binary file added container-images/keys/sign/github-runner.keys
Binary file not shown.
7 changes: 7 additions & 0 deletions container-images/keys/ssh/ccv0-ssh
Original file line number Diff line number Diff line change
@@ -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-----
1 change: 1 addition & 0 deletions container-images/keys/ssh/ccv0-ssh.pub
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB+IZXZfij7oCCNUFpj9lHZS9mnzh1VgXluk1kYwvKVD
7 changes: 7 additions & 0 deletions container-images/keys/ssh/ssh_host_ed25519_key
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACBZCWq2MBTX8Bkvdtf9htpfqTTosRzYtTQgbeHADF1k3wAAAJiKehLQinoS
0AAAAAtzc2gtZWQyNTUxOQAAACBZCWq2MBTX8Bkvdtf9htpfqTTosRzYtTQgbeHADF1k3w
AAAEAlKROeyUCGfooVH87ObAnd4FAgvSnCgiIY2R6G+PpRTVkJarYwFNfwGS921/2G2l+p
NOixHNi1NCBt4cAMXWTfAAAAFHJvb3RAYnVpbGRraXRzYW5kYm94AQ==
-----END OPENSSH PRIVATE KEY-----
1 change: 1 addition & 0 deletions container-images/keys/ssh/ssh_host_ed25519_key.pub
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFkJarYwFNfwGS921/2G2l+pNOixHNi1NCBt4cAMXWTf root@buildkitsandbox
Loading

0 comments on commit e395f98

Please sign in to comment.