Skip to content

Commit 3d83e03

Browse files
amd-aliemmkulke
andcommitted
snp-verifier: offline vcek cache support
Add the verifier config for SNP to parse the vcek_sources option. Implement a filesystem based cache option that enables specifying a directory that may be preloaded with certs for offline trustee deployments. Signed-off-by: Amanda Liem <aliem@amd.com> Update deps/verifier/src/snp/mod.rs Apply suggestion from @mkulke Co-authored-by: Magnus Kulke <mkulke@gmail.com> Signed-off-by: Amanda Liem <aliem@amd.com>
1 parent e7e2b27 commit 3d83e03

3 files changed

Lines changed: 297 additions & 23 deletions

File tree

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
# Offline AMD VCEK Caching Guide
2+
3+
This document describes the process to pre-load VCEKs (Versioned Chip
4+
Endorsement Keys) into the trustee environment to allow normal attestation
5+
without connection to the AMD KDS. This guide mainly targets air-gapped
6+
environments.
7+
8+
> [!Note]
9+
> Currently this guide shows a method that builds on using
10+
> [docker](https://confidentialcontainers.org/docs/attestation/installation/docker/)
11+
> to manage kbs services. Additional deployment methods will be covered in future releases.
12+
13+
## Enabling Offline VCEK Store in Attestation Service
14+
15+
### 1. Set VCEK Sources Configuration Option
16+
17+
Update the attestation configuration file to use a predefined vcek store:
18+
19+
`kbs/config/as-config.json`:
20+
21+
```json
22+
{
23+
// ... other fields ...
24+
"verifier_config": {
25+
"snp_verifier": {
26+
// Configure VCEK sources to try, in order. Defaults to [KDS].
27+
"vcek_sources": [
28+
{
29+
"type": "OfflineStore",
30+
},
31+
// Optionally add a fallback to KDS. Leave out if KDS will not
32+
// be reachable.
33+
//{
34+
// "type": "KDS",
35+
//}
36+
]
37+
}
38+
}
39+
}
40+
```
41+
42+
With the `OfflineStore` configuration specified, Trustee will inspect the
43+
configured directory for VCEK values following the following format:
44+
45+
```
46+
/opt/confidential-containers/attestation-service/kds-store/vcek/{hwid}/vcek.der
47+
```
48+
49+
Where `{hwid}` is the hardware ID of the AMD EPYC server in lowercase hexadecimal.
50+
51+
### 2. Create and Populate VCEK directory
52+
53+
Create a `vcek` directory populated with the following structure:
54+
55+
```
56+
vcek/
57+
├── <Hex hardware ID>/ (ID must be lowercase)
58+
│ └── vcek.der (cert pre-downloaded from kdsintf.amd.com)
59+
├── <Hex hardware ID>/
60+
│ └── vcek.der
61+
├── <Hex hardware ID>/
62+
└── vcek.der
63+
```
64+
65+
Trustee requires one unique certificate per physical AMD EPYC server that the
66+
KBS will be servicing. The server's hardware ID and certificate's URL can be
67+
fetched using the [snphost tool](https://github.com/virtee/snphost).
68+
69+
On each AMD SNP host, with root/admin access run:
70+
```
71+
sudo snphost show vcek-url
72+
```
73+
74+
You should get a URL of the form:
75+
```
76+
https://kdsintf.amd.com/vcek/{version}/{machine}/{product_name}/{hwid}?{params}
77+
```
78+
79+
You may download it from a browser by pasting that URL, or you can run
80+
the following command on any server with network access to AMD's KDS.
81+
```
82+
sudo snphost fetch vcek der .
83+
```
84+
85+
> [!IMPORTANT]
86+
> - Note that the VCEK URL is specific to the hardware AMD firmware of the
87+
> machine. If the firmware is updated, the VCEK URL will change. See the
88+
> [AMD VCEK documentation](https://docs.amd.com/api/khub/documents/dWGhwYpo1Wv51rJN4d~47g/content)
89+
> for more information about the VCEK URL format.
90+
91+
### 3. Install `vcek` directory into trustee deployment
92+
93+
- **Install in running trustee deployment**
94+
95+
Use docker commands to copy your `vcek` folder into the configured directory:
96+
```
97+
sudo docker exec -it trustee-as-1 mkdir -p /opt/confidential-containers/attestation-service/kds-store/
98+
sudo docker cp ./vcek/ trustee-as-1:/opt/confidential-containers/attestation-service/kds-store/vcek/
99+
```
100+
101+
- **Mount shared directory**
102+
103+
You may also mount a shared directory from the host into the container by
104+
updating `docker-compose.yml` with a specified directory mapping:
105+
106+
```yaml
107+
as:
108+
... <existing configuration>
109+
volumes:
110+
... <existing volumes>
111+
- ./vcek:/opt/confidential-containers/attestation-service/kds-store/vcek:rw
112+
```
113+
114+
### Example:
115+
116+
For some number of AMD EPYC servers you wish for trustee to service:
117+
```
118+
ssh privileged-user@epyc-host "sudo snphost show vcek-url" >> urls.txt
119+
```
120+
121+
On a system with network access to AMD KDS:
122+
```bash
123+
124+
# Create the vcek folder that will be copied to trustee
125+
mkdir vcek
126+
127+
# Fetch certificates using the above URLs file
128+
# There should be one line for each EPYC host that kds will service
129+
cat urls.txt | while read line; do
130+
hwid="$(echo "$line" | cut -d/ -f7 | cut -d'?' -f1 | tr '[:upper:]' '[:lower:]')"
131+
mkdir vcek/$hwid
132+
cd vcek/$hwid
133+
sudo snphost fetch vcek der .
134+
cd ../..
135+
done
136+
137+
# Copy the archive to your air-gapped trustee attestation-service deployment
138+
scp -r vcek user@target-host:/path/to/trustee
139+
```
140+
141+
On the air-gapped trustee attestation-service host:
142+
```bash
143+
# Update as-config.json to enable Disk Caching
144+
cd /path/to/trustee
145+
vi kbs/config/as-config.json
146+
# Update the verifier_config section to:
147+
# "verifier_config": {
148+
# "snp_verifier": {
149+
# "vcek_sources": [
150+
# {
151+
# "type": "OfflineStore",
152+
# }
153+
# ]
154+
# }
155+
# }
156+
157+
# Start trustee
158+
docker compose up -d
159+
160+
# Copy the vcek store into the running attestation service container
161+
sudo docker exec -it trustee-as-1 mkdir -p /opt/confidential-containers/attestation-service/kds-store/
162+
sudo docker cp ./vcek/ trustee-as-1:/opt/confidential-containers/attestation-service/kds-store/vcek/
163+
164+
# Alternative to docker copy would be to add the following shared mount to
165+
# docker-compose.yml under as.volumes section:
166+
# - ./vcek:/opt/confidential-containers/attestation-service/kds-store/vcek:rw
167+
```
168+
169+
## Limitations
170+
171+
VCEK stores must be updated/rebuilt in the following events:
172+
- AMD EPYC host added to serviced cluster
173+
- AMD EPYC host firmware components updated
174+
- VCEK certificate revoked by CA
175+
176+
## Troubleshooting
177+
178+
Enable debug and check logs for `vcek` keyword. Ensure configured sources match
179+
expected values.
180+
181+
```
182+
echo "RUST_LOG=debug" > debug.env
183+
docker compose --env-file debug.env up -d
184+
docker logs trustee-as-1 | grep -i vcek
185+
```

deps/verifier/src/lib.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ pub struct VerifierConfig {
5656

5757
#[cfg(feature = "tpm-verifier")]
5858
tpm_verifier: Option<tpm::config::TpmVerifierConfig>,
59+
60+
#[cfg(feature = "snp-verifier")]
61+
snp_verifier: Option<snp::SnpVerifierConfig>,
5962
}
6063

6164
pub async fn to_verifier(
@@ -95,8 +98,8 @@ pub async fn to_verifier(
9598
Tee::Snp => {
9699
cfg_if::cfg_if! {
97100
if #[cfg(feature = "snp-verifier")] {
98-
let verifier = snp::Snp::default();
99-
Ok(Box::new(verifier) as Box<dyn Verifier + Send + Sync>)
101+
let snp_config = _config.map(|c| c.snp_verifier).unwrap_or(None);
102+
Ok(Box::<snp::Snp>::new(snp::Snp::new(snp_config).await?) as Box<dyn Verifier + Send + Sync>)
100103
} else {
101104
bail!("feature `snp-verifier` is not enabled for `verifier` crate.")
102105
}

0 commit comments

Comments
 (0)