Skip to content

Commit

Permalink
add keylime-poc
Browse files Browse the repository at this point in the history
Make a Proof of Concept of Keylime is k8s cluster.

This part 1 is adding Keylime in Docker Compose. This doubles as the
keylime service part in part 2, where agent(s) move to k8s. Agent image
is having SWTPM module built-in, so this environment is portable across
machines, regardless of their TPM chip or lack there of.

This POC is needed as the concept of having Keylime
Tenant/Verifier/Registrar outside k8s cluster, but Keylime Agent in k8s
cluster and being accessed via Ingress/LoadBalancer IP, is something
Keylime maintainers did not think originally as a use-case. This has
several issues with the current design, and while there is a proposal/
study for changing from "pull model" to "push model", it is miles away
and this POC tries to find out the minimal changes needed to make the
current model work for this use case.

Signed-off-by: Tuomo Tanskanen <tuomo.tanskanen@est.tech>
  • Loading branch information
tuminoid committed Dec 11, 2024
1 parent 226bedb commit 475db7a
Show file tree
Hide file tree
Showing 13 changed files with 890 additions and 0 deletions.
8 changes: 8 additions & 0 deletions security/keylime-poc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Keylime POC
<!-- cSpell:ignore keylime -->

## Docker Compose

First part of POC is deploying Keylime services in
[Docker Compose](compose/README.md). Setup is verified by a single Agent, backed
by software TPM, also in Docker.
85 changes: 85 additions & 0 deletions security/keylime-poc/agent-with-swtpm/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
##############################################################################
# keylime TPM 2.0 Dockerfile
#
# This file is for automatic test running of Keylime and rust-keylime.
# It is not recommended for use beyond testing scenarios.
##############################################################################

FROM quay.io/fedora/fedora

# environment variables
ARG BRANCH=master
ENV container docker
ENV HOME /root
ENV KEYLIME_HOME ${HOME}/keylime
ENV TPM_HOME ${HOME}/swtpm2
COPY dbus-policy.conf /etc/dbus-1/system.d/

# Packaged dependencies
ENV PKGS_DEPS "automake \
clang clang-devel \
createrepo_c \
czmq-devel \
dbus \
dbus-daemon \
dbus-devel \
dnf-plugins-core \
efivar-devel \
gcc \
git \
glib2-devel \
glib2-static \
gnulib \
iproute \
kmod \
libarchive-devel \
libselinux-python3 \
libtool \
libtpms \
llvm llvm-devel \
make \
openssl-devel \
pkg-config \
procps \
python3-cryptography \
python3-dbus \
python3-devel \
python3-gpg \
python3-pip \
python3-requests \
python3-setuptools \
python3-sqlalchemy \
python3-tornado \
python3-virtualenv \
python3-yaml \
python3-zmq \
redhat-rpm-config \
rpm-build \
rpm-sign \
rust clippy cargo \
swtpm \
swtpm-tools \
tpm2-abrmd \
tpm2-tools \
tpm2-tss \
tpm2-tss-devel \
uthash-devel \
wget \
which"

ENV DEV_DEPS "strace openssl"

RUN dnf makecache && \
dnf -y install $PKGS_DEPS $DEV_DEPS && \
dnf clean all && \
rm -rf /var/cache/dnf/*

RUN git clone https://github.com/keylime/rust-keylime \
&& cd rust-keylime \
&& make all \
&& make install \
&& cd .. \
&& rm -rf rust-keylime

COPY start.sh /
CMD ["/start.sh"]
12 changes: 12 additions & 0 deletions security/keylime-poc/agent-with-swtpm/dbus-policy.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<policy context="default">
<!-- Allow everything to be sent -->
<allow send_destination="*" eavesdrop="true"/>
<!-- Allow everything to be received -->
<allow eavesdrop="true"/>
<!-- Allow anyone to own anything -->
<allow own="*"/>
</policy>
</busconfig>
57 changes: 57 additions & 0 deletions security/keylime-poc/agent-with-swtpm/start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/usr/bin/env bash

set -eux

KEYLIME=/var/lib/keylime
TPMDIR=/tmp/tpmdir

# configure swtpm2 and start it
mkdir -p "${TPMDIR}"
chown tss:tss "${TPMDIR}"
chmod 750 "${TPMDIR}"

swtpm_setup --tpm2 \
--tpmstate "${TPMDIR}" \
--createek --decryption --create-ek-cert \
--create-platform-cert \
--display || true
swtpm socket --tpm2 \
--tpmstate dir="${TPMDIR}" \
--flags startup-clear \
--ctrl type=tcp,port=2322 \
--server type=tcp,port=2321 \
--daemon
sleep 2

# configure dbus for abmrd
sudo rm -rf /var/run/dbus
sudo mkdir /var/run/dbus
sudo dbus-daemon --system

# run abmrd
tpm2-abrmd \
--logger=stdout \
--tcti=swtpm: \
--allow-root \
--flush-all \
&
sleep 2

# prep image for running agent as non-root
useradd -s /sbin/nologin -g tss keylime || true

chown keylime:tss "${KEYLIME}" "${KEYLIME}"/secure
chmod 770 "${KEYLIME}" "${KEYLIME}"/secure
cp "${KEYLIME}"/cv_ca/cacert.crt "${KEYLIME}"/secure/
chown keylime:tss "${KEYLIME}"/secure/cacert.crt

# make swtpm CA accessible to tenant to validate EK cert
# and verify it to be sure we have it right to avoid issues down the road
cat /var/lib/swtpm-localca/{issuercert,swtpm-localca-rootca-cert}.pem > "${KEYLIME}"/tpm_cert_store/swtpm_localca.pem
tpm2_getekcertificate > "${KEYLIME}"/ek.bin
openssl x509 -inform DER -in "${KEYLIME}"/ek.bin -out "${KEYLIME}"/ek.pem
openssl verify -CAfile "${KEYLIME}"/tpm_cert_store/swtpm_localca.pem "${KEYLIME}"/ek.pem
sleep 2

# run agent
keylime_agent
1 change: 1 addition & 0 deletions security/keylime-poc/compose/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
allowlist.txt
21 changes: 21 additions & 0 deletions security/keylime-poc/compose/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Keylime in Docker Compose POC
<!-- cSpell:ignore keylime -->

Make a Proof of Concept of [Keylime in Docker Compose](compose/README.md).

This will also work as part of [Keylime Agent in k8s](../k8s/README.md) POC,
as Keylime Verifier, Registrar and Tenant will be outside k8s, but Agent inside.
This creates interesting problems to be solved as Agent traffic will need to
flow via Ingress/LoadBalancer and it cannot be reached via IP.

## Steps

1. docker compose installed
1. Keylime images built locally via upstream
[build_locally.sh](https://github.com/keylime/keylime/blob/master/docker/release/build_locally.sh)
(we need unreleased fixes from `master`).
1. `docker compose up --build` to launch it
1. `./tenant.sh -c add` to verify stack works and agent gets added to verifier,
with EK certificate from software TPM.

After this, feel free to play with `./tenant.sh`.
87 changes: 87 additions & 0 deletions security/keylime-poc/compose/agent.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
[agent]
# The configuration file version
version = "2.3"

# The agent's UUID.
uuid = "c47b9ea2-2bc2-461b-957b-e77dbcf35e5e"
# uuid = "hash_ek"
# uuid = "generate"

# The keylime working directory. The default value is /var/lib/keylime
keylime_dir = "/var/lib/keylime"

# The size of the memory-backed tmpfs partition where Keylime stores crypto keys.
# Use syntax that the 'mount' command would accept as a size parameter for tmpfs.
# The default below sets it to 1 megabyte.
secure_size = "1m"
# run_as = "keylime:tss"

# Enable mTLS communication between agent, verifier and tenant.
# Details on why setting it to "false" is generally considered insecure can be found
# on https://github.com/keylime/keylime/security/advisories/GHSA-2m39-75g9-ff5r
agent_enable_mtls = "true"

# The name of the file containing the Keylime agent TLS server private key.
# This private key is used to serve the Keylime agent REST API
# A new private key is generated in case it is not found.
# If set as "default", the "server-private.pem" value is used.
# If a relative path is set, it will be considered relative from the keylime_dir.
# If an absolute path is set, it is used without change
server_key = "secure/agent.key"

# The name of the file containing the X509 certificate used as the Keylime agent
# server TLS certificate.
# This certificate must be self signed.
# If set as "default", the "server-cert.crt" value is used
# If a relative path is set, it will be considered relative from the keylime_dir.
# If an absolute path is set, it is used without change.
server_cert = "secure/agent.crt"

# The CA that signs the client certificates of the tenant and verifier.
# If set as "default" the "cv_ca/cacert.crt" value, relative from the
# keylime_dir is used.
# If a relative path is set, it will be considered relative from the keylime_dir.
# If an absolute path is set, it is used without change.
trusted_client_ca = "secure/cacert.crt"

# The address and port of registrar server which agent communicate with
registrar_ip = "127.0.0.2"
registrar_port = 8890

# tbd
# The binding IP address and port for the agent server
ip = "0.0.0.0"
port = 9002

# Address and port where the verifier and tenant can connect to reach the agent.
# These keys are optional.
contact_ip = "127.0.0.3"
contact_port = 9002

# Use this option to state the existing TPM ownerpassword.
# This option should be set only when a password is set for the Endorsement
# Hierarchy (e.g. via "tpm2_changeauth -c e").
# In order to use a hex value for the password, use the prefix "hex:"
# For example if tpm2_changeauth -c e "hex:00a1b2c3e4" has run, the config option
# would be 'tpm_ownerpassword = "hex:00a1b2c3e4"'
# If no password was set, keep the empty string "".
tpm_ownerpassword = ""
tpm_version = "2"

# enc_keyname = "derived_tci_key"
# dec_payload_file = "decrypted_payload"
# extract_payload_zip = true
# enable_revocation_notifications = false
# revocation_actions_dir = "/usr/libexec/keylime"
# revocation_cert = "default"
# revocation_actions = ""
# payload_script = "autorun.sh"
# allow_payload_revocation_actions = true
# tpm_hash_alg = "sha256"
# tpm_encryption_alg = "rsa"
# tpm_signing_alg = "rsassa"
# ek_handle = "generate"
# enable_iak_idevid = false
# agent_data_path = ""
# ima_ml_path = "default"
# measuredboot_ml_path = "default"
72 changes: 72 additions & 0 deletions security/keylime-poc/compose/compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# need locally built keylime tenant,registrar,verifier images
# see: https://github.com/keylime/keylime/blob/master/docker/release/build_locally.sh
# agent image is built from custom Dockerfile in ../agent-with-swtpm

services:
keylime-verifier:
image: keylime_verifier:latest # locally built
hostname: keylime-verifier
volumes:
- ./verifier.conf:/etc/keylime/verifier.conf:ro
- ./logging.conf:/etc/keylime/logging.conf:ro
- secure_volume:/var/lib/keylime
ports:
- "8881:8881"
user: root

keylime-registrar:
image: keylime_registrar:latest # locally built
hostname: keylime-registrar
depends_on:
- keylime-verifier
volumes:
- ./registrar.conf:/etc/keylime/registrar.conf:ro
- ./logging.conf:/etc/keylime/logging.conf:ro
- secure_volume:/var/lib/keylime
ports:
- "8891:8891"
- "8890:8890"
user: root
entrypoint: ["bash", "-c", "sleep 5; keylime_registrar"]

keylime-tenant:
image: keylime_tenant:latest # locally built
hostname: keylime-tenant
network_mode: host
depends_on:
- keylime-verifier
- keylime-registrar
volumes:
- ./tenant.conf:/etc/keylime/tenant.conf:ro
- ./logging.conf:/etc/keylime/logging.conf:ro
- secure_volume:/var/lib/keylime
user: root
entrypoint: ["bash", "-c", "tail -f /dev/null"]

keylime-agent:
build:
# image: quay.io/keylime/keylime_agent:master + swtpm config
context: ../agent-with-swtpm
dockerfile: ../agent-with-swtpm/Dockerfile
hostname: keylime-agent
network_mode: host
user: root
depends_on:
- keylime-verifier
- keylime-registrar
environment:
- TPM2TOOLS_TCTI=tabrmd:bus_type=system
- TCTI=tabrmd:bus_type=system
- RUST_LOG=keylime_agent=debug
volumes:
- /sys/kernel/security:/sys/kernel/security:ro
- ./agent.conf:/etc/keylime/agent.conf:ro
- secure_volume:/var/lib/keylime
- agent_volume:/var/lib/keylime/secure

volumes:
secure_volume:
agent_volume:
driver_opts:
type: tmpfs
device: tmpfs
32 changes: 32 additions & 0 deletions security/keylime-poc/compose/logging.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Keylime logging configuration

[logging]
version = 2.3

[loggers]
keys = root,keylime

[handlers]
keys = consoleHandler

[formatters]
keys = formatter

[formatter_formatter]
format = %(asctime)s.%(msecs)03d - %(name)s - %(levelname)s - %(message)s
datefmt = %Y-%m-%d %H:%M:%S

[logger_root]
level = DEBUG
handlers = consoleHandler

[handler_consoleHandler]
class = StreamHandler
level = DEBUG
formatter = formatter
args = (sys.stdout,)

[logger_keylime]
level = DEBUG
qualname = keylime
handlers =
Loading

0 comments on commit 475db7a

Please sign in to comment.