Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 22 additions & 8 deletions docs/amd-sev-snp.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,18 +130,32 @@ for production TEE deployments.
## AMD KDS collateral

The verifier obtains AMD certificate collateral from the built-in AMD KDS URL
when the attestation evidence does not already contain the required chain. An
operator can set an AMD-KDS-compatible mirror or cache:
when the attestation evidence does not already contain the required chain. The
public endpoint may be temporarily unavailable because of maintenance,
outage, routing restrictions, or a disconnected deployment. An operator can
set an AMD-KDS-compatible mirror or cache for both the KMS CVM and application
CVMs during installation:

```sh
sudo dstackup install --platform amd-sev-snp \
--sev-snp-kds-url "https://mirror.example.com/vcek/v1"
```

The value is rendered into the KMS configuration as:

```toml
[core]
amd_kds_base_url = "https://mirror.example.com/vcek/v1"
[core.attestation.urls]
amd_kds = "https://mirror.example.com/vcek/v1"
```

Leave the value empty to use the built-in default. A custom endpoint is part of
the verification trust and availability boundary: use a controlled mirror,
preserve TLS validation, and do not make verification succeed without valid
AMD signatures.
The same value is passed to application CVMs as
`collateral_urls.amd_kds`. Leave the option unset to use the built-in default.
A custom endpoint is part of the verification trust and availability boundary:
use a controlled mirror, preserve TLS validation, and do not make verification
succeed without valid AMD signatures. The endpoint must implement the AMD KDS
API, including certificate-chain and chip/TCB-specific VCEK requests. A
pre-populated cache can continue serving known collateral during a public KDS
maintenance window or outage; cache misses must fail closed.

## Troubleshooting

Expand Down
18 changes: 16 additions & 2 deletions dstack/crates/dstack-cli-core/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ pub struct HostConfig {
pub verify_os_image: bool,
/// confidential-computing platform (selects SNP-specific KMS settings).
pub platform: Platform,
/// AMD KDS-compatible collateral mirror/cache URL as seen from CVMs.
pub sev_snp_kds_url: String,
}

impl Default for HostConfig {
Expand All @@ -113,6 +115,7 @@ impl Default for HostConfig {
image_download_url: DEFAULT_IMAGE_DOWNLOAD_URL.to_string(),
verify_os_image: true,
platform: Platform::Tdx,
sev_snp_kds_url: String::new(),
}
}
}
Expand Down Expand Up @@ -162,8 +165,14 @@ port = 8000
// `sev_snp_key_release`, which defaults to false — so it must be set on
// SNP or the KMS refuses to release keys. Harmless/ignored on TDX.
sev_snp = match cfg.platform {
Platform::AmdSevSnp => "sev_snp_key_release = true\namd_kds_base_url = \"\"\n",
Platform::Tdx => "",
Platform::AmdSevSnp if cfg.sev_snp_kds_url.trim().is_empty() => {
"sev_snp_key_release = true\n".to_string()
}
Platform::AmdSevSnp => format!(
"sev_snp_key_release = true\n\n[core.attestation.urls]\namd_kds = {:?}\n",
cfg.sev_snp_kds_url
),
Platform::Tdx => String::new(),
},
verify = cfg.verify_os_image,
download_url = cfg.image_download_url,
Expand Down Expand Up @@ -272,6 +281,8 @@ pub struct VmmRender {
pub key_provider_port: u32,
/// KMS URLs injected into app CVMs (the guest-visible KMS address).
pub kms_urls: Vec<String>,
/// AMD KDS-compatible collateral mirror/cache URL injected into app CVMs.
pub sev_snp_kds_url: String,
/// confidential-computing platform (selects qemu/share-mode for the CVMs).
pub platform: Platform,
/// gate the management API behind a bearer/Basic token (`[auth] enabled`).
Expand All @@ -296,6 +307,7 @@ impl Default for VmmRender {
key_provider_addr: "127.0.0.1".to_string(),
key_provider_port: 3443,
kms_urls: Vec::new(),
sev_snp_kds_url: String::new(),
platform: Platform::Tdx,
auth_enabled: false,
auth_token: String::new(),
Expand Down Expand Up @@ -334,6 +346,7 @@ qemu_path = "{qemu_path}"
kms_urls = [{kms_urls}]
gateway_urls = []
pccs_url = ""
sev_snp_kds_url = "{sev_snp_kds_url}"
docker_registry = ""
cid_start = {cid_start}
cid_pool_size = {cid_pool_size}
Expand Down Expand Up @@ -423,6 +436,7 @@ port = {kp_port}
.map(|u| format!("\"{u}\""))
.collect::<Vec<_>>()
.join(", "),
sev_snp_kds_url = r.sev_snp_kds_url,
cid_start = r.cid_start,
cid_pool_size = r.cid_pool_size,
supervisor_exe = r.supervisor_exe,
Expand Down
4 changes: 4 additions & 0 deletions dstack/crates/dstackup/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,10 @@ pub(crate) struct InstallOpts {
#[arg(long, default_value = config::DEFAULT_KMS_IMAGE)]
pub(crate) kms_image: String,

/// AMD KDS-compatible collateral mirror/cache URL, as seen from CVMs.
#[arg(long, value_name = "URL")]
pub(crate) sev_snp_kds_url: Option<String>,

/// host port for the KMS RPC (default: an auto-picked free port).
#[arg(long)]
pub(crate) kms_port: Option<u16>,
Expand Down
2 changes: 2 additions & 0 deletions dstack/crates/dstackup/src/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ pub(crate) async fn cmd_install(mut o: InstallOpts, release_api_base_url: &str)
key_provider_addr: kp_addr,
key_provider_port: kp_port as u32,
kms_urls: kms_urls.clone(),
sev_snp_kds_url: o.sev_snp_kds_url.clone().unwrap_or_default(),
platform,
auth_enabled: true,
auth_token: vmm_token.clone(),
Expand All @@ -186,6 +187,7 @@ pub(crate) async fn cmd_install(mut o: InstallOpts, release_api_base_url: &str)
os_image_hash: os_image_hash.unwrap_or_default(),
verify_os_image: false,
platform,
sev_snp_kds_url: o.sev_snp_kds_url.clone().unwrap_or_default(),
..Default::default()
};
let kms = config::kms_toml(&host_cfg);
Expand Down
9 changes: 8 additions & 1 deletion dstack/vmm/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2024,7 +2024,10 @@ pub(crate) fn make_sys_config(
"gateway_urls": gateway_urls,
"gateway_clusters": gateway_clusters,
"pccs_url": cfg.cvm.pccs_url,
"collateral_urls": { "pccs": cfg.cvm.pccs_url },
"collateral_urls": {
"pccs": cfg.cvm.pccs_url,
"amd_kds": cfg.cvm.sev_snp_kds_url,
},
"nvidia_attestation_proxy_url": cfg.cvm.nvidia_attestation_proxy_url,
"docker_registry": cfg.cvm.docker_registry,
"host_api_url": format!("vsock://2:{}/api", cfg.host_api.port),
Expand Down Expand Up @@ -3560,6 +3563,10 @@ mod tests {
}
assert_eq!(sys_config["pccs_url"], config.cvm.pccs_url);
assert_eq!(sys_config["collateral_urls"]["pccs"], config.cvm.pccs_url);
assert_eq!(
sys_config["collateral_urls"]["amd_kds"],
config.cvm.sev_snp_kds_url
);
let vm_config: serde_json::Value = serde_json::from_str(
sys_config["vm_config"]
.as_str()
Expand Down
7 changes: 7 additions & 0 deletions dstack/vmm/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,9 @@ pub struct CvmConfig {
/// The URL of the PCCS server
#[serde(default)]
pub pccs_url: String,
/// Optional AMD KDS-compatible collateral mirror/cache URL passed to guests.
#[serde(default)]
pub sev_snp_kds_url: String,
/// Node-local credentials and collateral settings used when an individual
/// VM requests a simulated TEE platform.
#[serde(default)]
Expand Down Expand Up @@ -943,6 +946,10 @@ impl Config {
}
for (name, value) in [
("cvm.pccs_url", Some(self.cvm.pccs_url.as_str())),
(
"cvm.sev_snp_kds_url",
Some(self.cvm.sev_snp_kds_url.as_str()),
),
(
"cvm.nvidia_attestation_proxy_url",
self.cvm.nvidia_attestation_proxy_url.as_deref(),
Expand Down
Loading