28 KiB
How to build, run and test Kata CCv0
Introduction and Background
In order to try and make building (locally) and demoing the Kata Containers CCv0 code base as simple as possible I've
shared a script ccv0.sh. This script was originally my attempt to automate the steps of the
Developer Guide so that I could do
different sections of them repeatedly and reliably as I was playing around with make changes to different parts of the
Kata code base. I then tried to weave in some of the tests/.ci
scripts in order to have less duplicated code.
As we're progress on the confidential containers journey I hope to add more features to demonstrate the functionality
we have working.
Disclaimer: This script has mostly just been used and tested by me (@stevenhorsman), so there might be issues with it. I'm happy to try and help solve these if possible, but this shouldn't be considered a fully supported process by the Kata Containers community.
Basic script set-up and optional environment variables
In order to build, configure and demo the CCv0 functionality, these are the set-up steps I take:
- Provision a new VM
- I choose a Ubuntu 20.04 8GB VM for this as I had one available. There are some dependences on apt-get installed packages, so these will need re-working to be compatible with other platforms.
- Copy the script over to your VM (I put it in the home directory) and ensure it has execute permission by running
$ chmod u+x ccv0.sh
-
Optionally set up some environment variables
- By default the script checks out the
CCv0branches of thekata-containers/kata-containersandkata-containers/testsrepositories, but it is designed to be used to test of personal forks and branches as well. If you want to build and run these you can export thekatacontainers_repo,katacontainers_branch,tests_repoandtests_branchvariables e.g.before running the script.$ export katacontainers_repo=github.com/stevenhorsman/kata-containers $ export katacontainers_branch=stevenh/agent-pull-image-endpoint $ export tests_repo=github.com/stevenhorsman/tests $ export tests_branch=stevenh/add-ccv0-changes-to-build - By default the build and configuration are using
QEMUas the hypervisor. In order to useCloud Hypervisorinstead set:before running the build.$ export KATA_HYPERVISOR="cloud-hypervisor"
- By default the script checks out the
-
At this point you can provision a Kata confidential containers pod and container with either
crictl, or Kubernetes and then test and use it.
Using crictl for end-to-end provisioning of a Kata confidential containers pod with an unencrypted image
-
Run the full build process with Kubernetes turned off, so its configuration doesn't interfere with
crictlusing:$ export KUBERNETES="no" $ export KATA_HYPERVISOR="qemu" $ ~/ccv0.sh -d build_and_install_allNote
: Much of this script has to be run as
sudo, so you are likely to get prompted for your password.- I run this script sourced just so that the required installed components are accessible on the
PATHto the rest of the process without having to reload the session. - The steps that
build_and_install_alltakes is:- Checkout the git repos for the
testsandkata-containersrepos as specified by the environment variables (default toCCv0branches if they are not supplied) - Use the
tests/.ciscripts to install the build dependencies - Build and install the Kata runtime
- Configure Kata to use containerd and for debug and confidential containers features to be enabled (including enabling console access to the Kata guest shell, which should only be done in development)
- Create, build and install a rootfs for the Kata hypervisor to use. For 'CCv0' this is currently based on Ubuntu
20.04 and has extra packages like
umociadded. - Build the Kata guest kernel
- Install the hypervisor (in order to select which hypervisor will be used, the
KATA_HYPERVISORenvironment variable can be used to select betweenqemuorcloud-hypervisor)
- Checkout the git repos for the
Note
: Depending on how where your VMs are hosted and how IPs are shared you might get an error from docker during matching
ERROR: toomanyrequests: Too Many Requests. To get past this, login into Docker Hub and pull the images used with:$ sudo docker login $ sudo docker pull ubuntuthen re-run the command.
- The first time this runs it may take a while, but subsequent runs will be quicker as more things are already installed and they can be further cut down by not running all the above steps see "Additional script usage" below
- I run this script sourced just so that the required installed components are accessible on the
-
Create a new Kata sandbox pod using
crictlwith:$ ~/ccv0.sh crictl_create_cc_pod- This creates a pod configuration file, creates the pod from this using
sudo crictl runp -r kata ~/pod-config.yamland runssudo crictl podsto show the pod
- This creates a pod configuration file, creates the pod from this using
-
Create a new Kata confidential container with:
$ ~/ccv0.sh crictl_create_cc_container- This creates a container (based on
busybox:1.33.1) in the Kata cc sandbox and prints a list of containers. This will have been created based on an image pulled in the Kata pod sandbox/guest, not on the host machine.
- This creates a container (based on
As this point you should have a crictl pod and container that is using the Kata confidential containers runtime.
You can validate that the container image was pulled on the guest
or using the Kata pod sandbox for testing with agent-ctl or ctr shim
Clean up the crictl pod sandbox and container
- When the testing is complete you can delete the container and pod by running:
$ ~/ccv0.sh crictl_delete_cc
Using Kubernetes for end-to-end provisioning of a Kata confidential containers pod with an unencrypted image
-
Run the full build process with the Kubernetes environment variable set to
"yes", so the Kubernetes cluster is configured and created using the VM as a single node cluster:$ export KUBERNETES="yes" $ ~/ccv0.sh build_and_install_allNote
: Depending on how where your VMs are hosted and how IPs are shared you might get an error from docker during matching
ERROR: toomanyrequests: Too Many Requests. To get past this, login into Docker Hub and pull the images used with:$ sudo docker login $ sudo docker pull registry:2 $ sudo docker pull ubuntu:20.04then re-run the command.
-
Check that your Kubernetes cluster has been correctly set-up by running :
$ kubectl get nodesand checking that you see a single node e.g.
NAME STATUS ROLES AGE VERSION stevenh-ccv0-k8s1.fyre.ibm.com Ready control-plane,master 43s v1.22.0 -
Create a Kata confidential containers pod by running:
$ ~/ccv0.sh kubernetes_create_cc_pod -
Wait a few seconds for pod to start then check that the pod's status is
Runningwith$ kubectl get podswhich should show something like:
NAME READY STATUS RESTARTS AGE busybox-cc 1/1 Running 0 54s -
As this point you should have a Kubernetes pod and container running, that is using the Kata confidential containers runtime. You can validate that the container image was pulled on the guest or using the Kata pod sandbox for testing with
agent-ctlorctr shim
Clean up the Kubernetes pod sandbox and container
- When the testing is complete you can delete the container and pod by running:
$ ~/ccv0.sh kubernetes_delete_cc_pod
Validate that the container image was pulled on the guest
There are a couple of ways we can check that the container pull image action was offloaded to the guest, by checking the guest's file system for the unpacked bundle and checking the host's directories to ensure it wasn't also pulled there.
- To check the guest's file system:
- Open a shell into the Kata guest with:
$ ~/ccv0.sh open_kata_shell - List the files in the directory that the container image bundle should have been unpacked to with:
$ ls -ltr /run/kata-containers/confidential-containers_signed/ - This should give something like
which shows how the image has been pulled and then unbundled on the guest.
total 72 -rw-r--r-- 1 root root 2977 Jan 20 10:03 config.json -rw-r--r-- 1 root root 372 Jan 20 10:03 umoci.json -rw-r--r-- 1 root root 63584 Jan 20 10:03 sha256_be9faa75035c20288cde7d2cdeb6cd1f5f4dbcd845d3f86f7feab61c4eff9eb5.mtree drwxr-xr-x 12 root root 240 Jan 20 10:03 rootfs - Leave the Kata guest shell by running:
$ exit
- Open a shell into the Kata guest with:
- To verify that the image wasn't pulled on the host system we can look at the shared sandbox on the host and we
should only see a single bundle for the pause container as the
busyboxbased container image should have been pulled on the guest:- Find all the
rootfsdirectories under in the pod's shared directory with:which should only show a single$ pod_id=$(ps -ef | grep containerd-shim-kata-v2 | egrep -o "id [^,][^,].* " | awk '{print $2}') $ sudo find /run/kata-containers/shared/sandboxes/${pod_id}/shared -name rootfsrootfsdirectory if the container image was pulled on the guest, not the host - Looking that
rootfsdirectory withshows something similar to$ sudo ls -ltr $(sudo find /run/kata-containers/shared/sandboxes/${pod_id}/shared -name rootfs)which is clearly the pause container indicating that thetotal 668 -rwxr-xr-x 1 root root 682696 Aug 25 13:58 pause drwxr-xr-x 2 root root 6 Jan 20 02:01 proc drwxr-xr-x 2 root root 6 Jan 20 02:01 dev drwxr-xr-x 2 root root 6 Jan 20 02:01 sys drwxr-xr-x 2 root root 25 Jan 20 02:01 etcbusyboxbased container image is not exposed to the host.
- Find all the
Using a Kata pod sandbox for testing with agent-ctl or ctr shim
Once you have a kata pod sandbox created as described above, either using
crictl, or Kubernetes
, you can use this to test specific components of the Kata confidential
containers architecture. This can be useful for development and debugging to isolate and test features
that aren't broadly supported end-to-end. Here are some examples:
- In the first terminal run the pull image on guest command against the Kata agent, via the shim (
containerd-shim-kata-v2). This can be achieved using the containerd CLI tool,ctr, which can be used to interact with the shim directly. The command takes the formctr --namespace k8s.io shim --id <sandbox-id> pull-image <image> <new-container-id>and can been run directly, or through theccv0.shscript to automatically fill in the variables:- Optionally, set up some environment variables to set the image and credentials used:
- By default the shim pull image test in
ccv0.shwill use thebusybox:1.33.1based test imagequay.io/kata-containers/confidential-containers:signedwhich requires no authentication. To use a different image, set thePULL_IMAGEenvironment variable e.g.Currently the containerd shim pull image code doesn't support using a container registry that requires authentication, so if this is required, see the below steps to run the pull image command against the agent directly.$ export PULL_IMAGE="docker.io/library/busybox:latest"
- By default the shim pull image test in
- Run the pull image agent endpoint with:
which we print the
$ ~/ccv0.sh shim_pull_imagectr shimcommand for reference
- Optionally, set up some environment variables to set the image and credentials used:
- Alternatively you can issue the command directly to the
kata-agentpull image endpoint, which also supports credentials in order to pull from an authenticated registry:- Optionally set up some environment variables to set the image and credentials used:
- Set the
PULL_IMAGEenvironment variable e.g.export PULL_IMAGE="docker.io/library/busybox:latest"if a specific container image is required. - If the container registry for the image requires authentication then this can be set with an environment
variable
SOURCE_CREDS. For example to use Docker Hub (docker.io) as an authenticated user first runexport SOURCE_CREDS="<dockerhub username>:<dockerhub api key>"Note
: the credentials support on the agent request is a tactical solution for the short-term proof of concept to allow more images to be pulled and tested. Once we have support for getting keys into the Kata guest image using the attestation-agent and/or KBS I'd expect container registry credentials to be looked up using that mechanism.
- Set the
- Run the pull image agent endpoint with
and you should see output which includes
$ ~/ccv0.sh agent_pull_imageCommand PullImage (1 of 1) returned (Ok(()), false)to indicate that thePullImagerequest was successful e.g.Finished release [optimized] target(s) in 0.21s {"msg":"announce","level":"INFO","ts":"2021-09-15T08:40:14.189360410-07:00","subsystem":"rpc","name":"kata-agent-ctl","pid":"830920","version":"0.1.0","source":"kata-agent-ctl","config":"Config { server_address: \"vsock://1970354082:1024\", bundle_dir: \"/tmp/bundle\", timeout_nano: 0, interactive: false, ignore_errors: false }"} {"msg":"client setup complete","level":"INFO","ts":"2021-09-15T08:40:14.193639057-07:00","pid":"830920","source":"kata-agent-ctl","name":"kata-agent-ctl","subsystem":"rpc","version":"0.1.0","server-address":"vsock://1970354082:1024"} {"msg":"Run command PullImage (1 of 1)","level":"INFO","ts":"2021-09-15T08:40:14.196643765-07:00","pid":"830920","source":"kata-agent-ctl","subsystem":"rpc","name":"kata-agent-ctl","version":"0.1.0"} {"msg":"response received","level":"INFO","ts":"2021-09-15T08:40:43.828200633-07:00","source":"kata-agent-ctl","name":"kata-agent-ctl","subsystem":"rpc","version":"0.1.0","pid":"830920","response":""} {"msg":"Command PullImage (1 of 1) returned (Ok(()), false)","level":"INFO","ts":"2021-09-15T08:40:43.828261708-07:00","subsystem":"rpc","pid":"830920","source":"kata-agent-ctl","version":"0.1.0","name":"kata-agent-ctl"}Note
: The first time that
~/ccv0.sh agent_pull_imageis run, theagent-ctltool will be built which may take a few minutes.
- Optionally set up some environment variables to set the image and credentials used:
- To validate that the image pull was successful, you can open a shell into the Kata guest with:
$ ~/ccv0.sh open_kata_shell - Check the
/run/kata-containers/directory to verify that the container image bundle has been created in a directory named either01234556789(for the container id), or the container image name, e.g.which should show something like$ ls -ltr /run/kata-containers/confidential-containers_signed/total 72 drwxr-xr-x 10 root root 200 Jan 1 1970 rootfs -rw-r--r-- 1 root root 2977 Jan 20 16:45 config.json -rw-r--r-- 1 root root 372 Jan 20 16:45 umoci.json -rw-r--r-- 1 root root 63584 Jan 20 16:45 sha256_be9faa75035c20288cde7d2cdeb6cd1f5f4dbcd845d3f86f7feab61c4eff9eb5.mtree - Leave the Kata shell by running:
$ exit
Verifying signed images
For this sample demo, we use local attestation to pass through the required
configuration to do container image signature verification. Due to this, the ability to verify images is limited
to a pre-created selection of test images in our test
repository quay.io/kata-containers/confidential-containers.
For pulling images not in this test repository (called an unprotected registry below), we fall back to the behaviour
of not enforcing signatures. More documentation on how to customise this to match your own containers through local,
or remote attestation will be available in future.
In our test repository there are three tagged images:
| Test Image | Base Image used | Signature status | GPG key status |
|---|---|---|---|
quay.io/kata-containers/confidential-containers:signed |
busybox:1.33.1 |
signature embedded in kata rootfs | public key embedded in kata rootfs |
quay.io/kata-containers/confidential-containers:unsigned |
busybox:1.33.1 |
not signed | not signed |
quay.io/kata-containers/confidential-containers:other_signed |
nginx:1.21.3 |
signature embedded in kata rootfs | GPG key not kept |
Using a standard unsigned busybox image that can be pulled from another, unprotected, quay.io repository we can
test a few scenarios.
In this sample, with local attestation, we pass in the the public GPG key and signature files, and the offline_fs_kbc
configuration
into the guest image which specifies that any container image from quay.io/kata-containers
must be signed with the embedded GPG key and the agent configuration needs updating to enable this.
With this policy set a few tests of image verification can be done to test different scenarios by attempting
to create containers from these images using crictl:
-
If you don't already have the Kata Containers CC code built and configured for
crictl, then follow the instructions above up to the~/ccv0.sh crictl_create_cc_podcommand. -
In order to enable the guest image, you will need to setup the required configuration, policy and signature files needed by running
~/ccv0.sh copy_signature_files_to_guestand then run~/ccv0.sh crictl_create_cc_podwhich will delete and recreate your pod - adding in the new files. -
To test the fallback behaviour works using an unsigned image from an unprotected registry we can pull the
busyboximage by running:$ export CONTAINER_CONFIG_FILE=container-config_unsigned-unprotected.yaml $ ~/ccv0.sh crictl_create_cc_container- This finishes showing the running container e.g.
CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID 98c70fefe997a quay.io/prometheus/busybox:latest Less than a second ago Running prometheus-busybox-signed 0 70119e0539238 -
To test that an unsigned image from our protected test container registry is rejected we can run:
$ export CONTAINER_CONFIG_FILE=container-config_unsigned-protected.yaml $ ~/ccv0.sh crictl_create_cc_container- This correctly results in an error message from
crictl:PullImage from image service failed" err="rpc error: code = Internal desc = Security validate failed: Validate image failed: The signatures do not satisfied! Reject reason: [Match reference failed.]" image="quay.io/kata-containers/confidential-containers:unsigned"
- This correctly results in an error message from
-
To test that the signed image our protected test container registry is accepted we can run:
$ export CONTAINER_CONFIG_FILE=container-config.yaml $ ~/ccv0.sh crictl_create_cc_container- This finishes by showing a new
kata-cc-busybox-signedrunning container e.g.
CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID b4d85c2132ed9 quay.io/kata-containers/confidential-containers:signed Less than a second ago Running kata-cc-busybox-signed 0 70119e0539238 ... - This finishes by showing a new
-
Finally to check the image with a valid signature, but invalid GPG key (the real trusted piece of information we really want to protect with the attestation agent in future) fails we can run:
$ export CONTAINER_CONFIG_FILE=container-config_signed-protected-other.yaml $ ~/ccv0.sh crictl_create_cc_container- Again this results in an error message from
crictl:"PullImage from image service failed" err="rpc error: code = Internal desc = Security validate failed: Validate image failed: The signatures do not satisfied! Reject reason: [signature verify failed! There is no pubkey can verify the signature!]" image="quay.io/kata-containers/confidential-containers:other_signed"
- Again this results in an error message from
Using Kubernetes to create a Kata confidential containers pod from the encrypted ssh demo sample image
The ssh-demo explains how to demonstrate creating a Kata confidential containers pod from an encrypted image with the runtime created by the confidential-containers operator. To be fully confidential, this should be run on a Trusted Execution Environment, but it can be tested on generic hardware as well.
If you wish to build the Kata confidential containers runtime to do this yourself, then you can using the following steps:
-
Run the full build process with the Kubernetes environment variable set to
"yes", so the Kubernetes cluster is configured and created using the VM as a single node cluster and withAA_KBCset tooffline_fs_kbc.$ export KUBERNETES="yes" $ export AA_KBC=offline_fs_kbc $ ~/ccv0.sh build_and_install_all- The
AA_KBC=offline_fs_kbcmode will ensure that, when creating the rootfs of the Kata guest, the attestation-agent will be added along with the sample offline KBC and an agent configuration file
Note
: Depending on how where your VMs are hosted and how IPs are shared you might get an error from docker during matching
ERROR: toomanyrequests: Too Many Requests. To get past this, login into Docker Hub and pull the images used with:$ sudo docker login $ sudo docker pull registry:2 $ sudo docker pull ubuntu:20.04then re-run the command.
- The
-
Check that your Kubernetes cluster has been correctly set-up by running :
$ kubectl get nodesand checking that you see a single node e.g.
NAME STATUS ROLES AGE VERSION stevenh-ccv0-k8s1.fyre.ibm.com Ready control-plane,master 43s v1.22.0 -
Create a sample Kata confidential containers ssh pod by running:
$ ~/ccv0.sh kubernetes_create_ssh_demo_pod -
As this point you should have a Kubernetes pod running the Kata confidential containers runtime that has pulled the sample image which was encrypted by the key file that we included in the rootfs. During the pod deployment the image was pulled and then decrypted using the key file, on the Kata guest image, without it ever being available to the host.
-
To validate that the container is working you, can connect to the image via SSH by running:
$ ~/ccv0.sh connect_to_ssh_demo_pod- During this connection the host key fingerprint is shown and should match:
ED25519 key fingerprint is SHA256:wK7uOpqpYQczcgV00fGCh+X97sJL3f6G1Ku4rvlwtR0. - After you are finished connecting then run:
$ exit
- During this connection the host key fingerprint is shown and should match:
-
To delete the sample SSH demo pod run:
$ ~/ccv0.sh kubernetes_delete_ssh_demo_pod
Additional script usage
As well as being able to use the script as above to build all of kata-containers from scratch it can be used to just
re-build bits of it by running the script with different parameters. For example after the first build you will often
not need to re-install the dependencies, the hypervisor or the Guest kernel, but just test code changes made to the
runtime and agent. This can be done by running ~/ccv0.sh rebuild_and_install_kata. (Note this does a hard checkout
from git, so if your changes are only made locally it is better to do the individual steps e.g.
~/ccv0.sh build_kata_runtime && ~/ccv0.sh build_and_add_agent_to_rootfs && ~/ccv0.sh build_and_install_rootfs).
There are commands for a lot of steps in building, setting up and testing and the full list can be seen by running
~/ccv0.sh help:
$ ~/ccv0.sh help
Overview:
Build and test kata containers from source
Optionally set kata-containers and tests repo and branch as exported variables before running
e.g. export katacontainers_repo=github.com/stevenhorsman/kata-containers && export katacontainers_branch=kata-ci-from-fork && export tests_repo=github.com/stevenhorsman/tests && export tests_branch=kata-ci-from-fork && ~/ccv0.sh build_and_install_all
Usage:
ccv0.sh [options] <command>
Commands:
- help: Display this help
- all: Build and install everything, test kata with containerd and capture the logs
- build_and_install_all: Build and install everything
- initialize: Install dependencies and check out kata-containers source
- rebuild_and_install_kata: Rebuild the kata runtime and agent and build and install the image
- build_kata_runtime: Build and install the kata runtime
- configure: Configure Kata to use rootfs and enable debug
- create_rootfs: Create a local rootfs
- build_and_add_agent_to_rootfs:Builds the kata-agent and adds it to the rootfs
- build_and_install_rootfs: Builds and installs the rootfs image
- install_guest_kernel: Setup, build and install the guest kernel
- build_cloud_hypervisor Checkout, patch, build and install Cloud Hypervisor
- build_qemu: Checkout, patch, build and install QEMU
- init_kubernetes: initialize a Kubernetes cluster on this system
- crictl_create_cc_pod Use crictl to create a new kata cc pod
- crictl_create_cc_container Use crictl to create a new busybox container in the kata cc pod
- crictl_delete_cc Use crictl to delete the kata cc pod sandbox and container in it
- kubernetes_create_cc_pod: Create a Kata CC runtime busybox-based pod in Kubernetes
- kubernetes_delete_cc_pod: Delete the Kata CC runtime busybox-based pod in Kubernetes
- open_kata_shell: Open a shell into the kata runtime
- agent_pull_image: Run PullImage command against the agent with agent-ctl
- shim_pull_image: Run PullImage command against the shim with ctr
- agent_create_container: Run CreateContainer command against the agent with agent-ctl
- test: Test using kata with containerd
- test_capture_logs: Test using kata with containerd and capture the logs in the user's home directory
Options:
-d: Enable debug
-h: Display this help