Skip to content

Commit 3cb3cff

Browse files
committed
Remote attestation with PCRs and AMD SEV-SNP on GCP using RHCOS
Signed-off-by: Roy Kaufman <[email protected]>
1 parent f08d71a commit 3cb3cff

18 files changed

+582
-6
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@ coreos/*.qcow2
77
secret
88
tmp/
99
trustee/keys
10+
*.tar
11+
*.tar.gz

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ Build the Fedora CoreOS or Centos Stream CoreOS image with the custom initrd:
2727
```bash
2828
cd coreos
2929
# Centos Stream CoreOS image
30-
just os=scos build oci-archive osbuild-qemu
30+
just os=scos build oci-archive osbuild
3131
# Fedora CoreOS image
32-
just build oci-archive osbuild-qemu
32+
just build oci-archive osbuild
3333
```
3434
3535
### Create local Trustee deployment

configs/trustee-gcp.bu

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
variant: fcos
2+
version: 1.6.0
3+
passwd:
4+
users:
5+
- name: core
6+
ssh_authorized_keys:
7+
- <KEY>
8+
9+
systemd:
10+
units:
11+
12+
dropins:
13+
- name: autologin-core.conf
14+
contents: |
15+
[Service]
16+
# Override Execstart in main unit
17+
ExecStart=
18+
# Add new Execstart with `-` prefix to ignore failure`
19+
ExecStart=-/usr/sbin/agetty --autologin core --noclear %I $TERM
20+
21+
storage:
22+
directories:
23+
- path: /var/kbs/config
24+
overwrite: true
25+
- path: /var/srv/www
26+
overwrite: true
27+
files:
28+
- path: /etc/profile.d/systemd-pager.sh
29+
mode: 0644
30+
contents:
31+
inline: |
32+
# Tell systemd to not use a pager when printing information
33+
export SYSTEMD_PAGER=cat
34+
- path: /usr/local/bin/populate_kbs.sh
35+
mode: 0755
36+
contents:
37+
local: populate_kbs.sh
38+
- path: /etc/containers/systemd/key-generation.container
39+
mode: 0644
40+
contents:
41+
local: containers/key-generation.container
42+
- path: /var/kbs/config/kbs-config.toml
43+
mode: 0644
44+
contents:
45+
local: kbs-config.toml
46+
- path: /etc/containers/systemd/kbs.container
47+
mode: 0644
48+
contents:
49+
local: containers/kbs.container
50+
- path: /etc/containers/systemd/kbs-client.container
51+
mode: 0644
52+
contents:
53+
local: containers/kbc.container
54+
- path: /etc/containers/systemd/nginx.container
55+
mode: 0644
56+
contents:
57+
local: containers/nginx.container
58+
59+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[Unit]
2+
Description=Trustee KBS client container
3+
After=key-generation.container
4+
5+
[Container]
6+
ContainerName=kbs-client
7+
Image=quay.io/rkaufman/kbs-tpm-snp:v1
8+
Network=host
9+
Volume=user-keys:/opt/confidential-containers/kbs/user-keys
10+
Exec=tail -f /dev/null
11+
12+
[Install]
13+
WantedBy=default.target
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
[Unit]
2+
Description=Trustee KBS container
3+
After=key-generation.container
4+
5+
[Container]
6+
ContainerName=kbs
7+
Image=quay.io/rkaufman/kbs-tpm-snp:v1
8+
Network=host
9+
Entrypoint=/usr/local/bin/kbs
10+
PublishPort=8080:8080
11+
Environment=RUST_LOG=debug
12+
Volume=/var/kbs/config/kbs-config.toml:/opt/confidential-containers/kbs/config/kbs-config.toml:z
13+
Volume=kbs-storage:/opt/confidential-containers/kbs/repository
14+
Volume=nebula-ca:/opt/confidential-containers/kbs/nebula-ca
15+
Volume=user-keys:/opt/confidential-containers/kbs/user-keys
16+
Exec=--config-file \
17+
/opt/confidential-containers/kbs/config/kbs-config.toml
18+
19+
[Install]
20+
WantedBy=default.target
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[Unit]
2+
Description=Trustee Key Generator
3+
Wants=network-online.target
4+
After=network-online.target
5+
6+
[Container]
7+
ContainerName=keyprovider
8+
Image=docker.io/alpine/openssl:latest
9+
Entrypoint=/bin/ash
10+
Volume=user-keys:/opt/confidential-containers/kbs/user-keys
11+
Exec=-c "if [ ! -s /opt/confidential-containers/kbs/user-keys/private.key ]; then \
12+
/usr/bin/openssl genpkey -algorithm ed25519 > /opt/confidential-containers/kbs/user-keys/private.key && \
13+
/usr/bin/openssl pkey -in /opt/confidential-containers/kbs/user-keys/private.key -pubout \
14+
-out /opt/confidential-containers/kbs/user-keys/public.pub; else exit 0; fi;"
15+
16+
[Install]
17+
WantedBy=default.target
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[Unit]
2+
Description=nginx HTTP server emulating registration server
3+
Wants=network-online.target
4+
After=network-online.target
5+
6+
[Container]
7+
ContainerName=nginx
8+
Image=quay.io/fedora/nginx-126:latest
9+
PublishPort=8000:8080
10+
Volume=/srv/www:/opt/app-root/src:z
11+
Exec=nginx -g "daemon off;"
12+
13+
[Install]
14+
WantedBy=default.target
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
[http_server]
2+
sockets = ["0.0.0.0:8080"]
3+
insecure_http = true
4+
5+
[admin]
6+
insecure_api = true
7+
auth_public_key = "./keys/public.pub"
8+
9+
10+
[attestation_token]
11+
insecure_key = true
12+
13+
[attestation_service]
14+
type = "coco_as_builtin"
15+
work_dir = "/opt/confidential-containers/attestation-service"
16+
policy_engine = "opa"
17+
18+
[attestation_service.attestation_token_broker]
19+
type = "Ear"
20+
duration_min = 5
21+
22+
[attestation_service.rvps_config]
23+
type = "BuiltIn"
24+
25+
[attestation_service.rvps_config.storage]
26+
type = "LocalFs"
27+
28+
29+
[[plugins]]
30+
name = "resource"
31+
type = "LocalFs"
32+
dir_path = "/opt/confidential-containers/kbs/repository"
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#!/bin/bash
2+
3+
set -xe
4+
5+
SECRET_PATH=${SECRET_PATH:=default/machine/root}
6+
KEY=${KEY:=/opt/confidential-containers/kbs/user-keys/private.key}
7+
8+
9+
## set reference values for TPM
10+
for i in {7,14}; do
11+
value=$(sudo tpm2_pcrread sha256:${i} | awk -F: '/0x/ {sub(/.*0x/, "", $2); gsub(/[^0-9A-Fa-f]/, "", $2); print tolower($2)}')
12+
podman exec -ti kbs-client \
13+
kbs-client config \
14+
--auth-private-key ${KEY} \
15+
set-sample-reference-value tpm_pcr${i} "${value}"
16+
done
17+
18+
# Check reference values
19+
podman exec -ti kbs-client \
20+
kbs-client config \
21+
--auth-private-key ${KEY} \
22+
get-reference-values
23+
24+
25+
# Create attestation policy
26+
## This policy allows access only if the system’s TPM or SNP
27+
## hardware measurements match trusted reference values
28+
cat << 'EOF' > A_policy.rego
29+
package policy
30+
import rego.v1
31+
32+
default hardware := 97
33+
default executables := 3
34+
default configuration := 2
35+
36+
##### TPM
37+
38+
hardware := 2 if {
39+
input.tpm.pcr07 in data.reference.tpm_pcr7
40+
input.tpm.pcr14 in data.reference.tpm_pcr14
41+
}
42+
43+
hardware := 2 if {
44+
input.snp.reported_tcb_snp == 27
45+
}
46+
47+
48+
##### Final decision
49+
result := {
50+
"executables": executables,
51+
"hardware": hardware,
52+
"configuration": configuration
53+
}
54+
EOF
55+
56+
podman cp A_policy.rego kbs-client:/A_policy.rego
57+
podman exec -ti kbs-client \
58+
kbs-client config \
59+
--auth-private-key ${KEY} \
60+
set-attestation-policy \
61+
--policy-file /A_policy.rego \
62+
--type rego --id default_cpu
63+
64+
# Upload resource
65+
cat > secret << EOF
66+
{ "key_type": "oct", "key": "2b442dd5db4478367729ef8bbf2e7480" }
67+
EOF
68+
podman cp secret kbs-client:/secret
69+
podman exec -ti kbs-client \
70+
kbs-client config \
71+
--auth-private-key ${KEY} \
72+
set-resource --resource-file /secret \
73+
--path ${SECRET_PATH}
74+
75+
76+
# Create resource policy
77+
## This policy allows access only if both CPUs report an "affirming" status
78+
## and provide TPM and SNP attestation evidence.
79+
cat << 'EOF' > R_policy.rego
80+
package policy
81+
import rego.v1
82+
83+
default allow = false
84+
85+
allow if {
86+
input["submods"]["cpu0"]["ear.status"] == "affirming"
87+
input["submods"]["cpu1"]["ear.status"] == "affirming"
88+
input["submods"]["cpu1"]["ear.veraison.annotated-evidence"]["tpm"]
89+
input["submods"]["cpu0"]["ear.veraison.annotated-evidence"]["snp"]
90+
}
91+
EOF
92+
93+
podman cp R_policy.rego kbs-client:/R_policy.rego
94+
podman exec -ti kbs-client \
95+
kbs-client config \
96+
--auth-private-key ${KEY} \
97+
set-resource-policy \
98+
--policy-file /R_policy.rego \

coreos/Containerfile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@ ARG BASE
22
FROM quay.io/trusted-execution-clusters/trustee-attester:2025-11-12 as kbc
33
FROM quay.io/trusted-execution-clusters/clevis-pin-trustee as clevis
44
FROM quay.io/trusted-execution-clusters/ignition:attestation as ignition
5+
6+
ARG KBS_CLIENT_IMAGE=quay.io/confidential-clusters/trustee-attester:2025-10-21
7+
ARG CLEVIS_PIN_TRUSTEE_IMAGE=quay.io/confidential-clusters/clevis-pin-trustee
8+
9+
FROM $KBS_CLIENT_IMAGE as kbc
10+
FROM $CLEVIS_PIN_TRUSTEE_IMAGE as clevis
11+
FROM quay.io/confidential-clusters/ignition:attestation as ignition
12+
513
FROM $BASE
614

715
COPY ./usr /usr

0 commit comments

Comments
 (0)