diff --git a/docs/security/cvm-boundaries.md b/docs/security/cvm-boundaries.md index b0a106eef..e5ecbc4dc 100644 --- a/docs/security/cvm-boundaries.md +++ b/docs/security/cvm-boundaries.md @@ -33,7 +33,7 @@ This is the main configuration file for the application in JSON format: | kms_enabled | 0.3.1 | boolean | Enable/disable KMS | | gateway_enabled | 0.3.1 | boolean | Enable/disable gateway | | local_key_provider_enabled | 0.3.1 | boolean | Use a local key provider | -| key_provider_id | 0.5.1 | string | Optional pin for the key provider identity (hex-encoded bytes). For `kms` this is the KMS CA public key; for `local` the sealing-provider MR. For `tpm` and `none` it must be an empty string — the TPM app-root public key is instance-specific and is not used as a provider id or measured as one. | +| key_provider_id | 0.5.1 | string | Optional pin for the key provider identity (hex-encoded bytes). For `kms` this is the KMS CA public key; for `local` the sealing-provider MR. For `tpm` and `none` it must be an empty string — the TPM app-root public key is instance-specific and is not used as a provider id or measured as one. When empty, any provider is accepted; its identity is still recorded in the `key-provider` launch event. | | public_logs | 0.3.3 | boolean | Whether logs are publicly visible | | public_sysinfo | 0.3.3 | boolean | Whether system info is public. Covers the guest dashboard and `/metrics`, including the `dstack_gpu_*` series (since 0.6.0), which expose each GPU's UUID and PCI bus address alongside utilization, memory, temperature and power. | | public_tcbinfo | 0.5.1 | boolean | Whether TCB info is public | @@ -128,7 +128,7 @@ dstack uses encrypted environment variables to allow app developers to securely - CVM performs basic regex validation on values - Final result is stored as /dstack/.hostshared/.decrypted-env and loaded system-wide via app-compose.service -This file is not measured to RTMRs. But it is highly recommended to add application-specific integrity checks on encrypted environment variables at the application layer. See [security-best-practices.md](./security-best-practices.md) for more details. +This file is not measured to RTMRs, and the envelope is not bound to an instance or compose hash: the KMS derives `env_crypt_key` from the app ID alone, so the host can withhold the file or replay any earlier ciphertext for the same app. It is highly recommended to add application-specific integrity checks, such as a version or expiry inside the plaintext, at the application layer. See [security-best-practices.md](./security-best-practices.md) for more details. ### .user-config This is an optional application-specific configuration file that applications inside the CVM can access. dstack OS simply stores it at /dstack/.host-shared/.user-config without any measurement or additional processing, unless `requirements.launch_token_hash` is set in app-compose.json — in that case the guest reads the launch token from JSON path `dstack.launch_token` in this file and fails closed at boot, before key provisioning, unless its SHA-256 matches the pinned hash. diff --git a/dstack/dstack-util/src/system_setup.rs b/dstack/dstack-util/src/system_setup.rs index 5e22d319e..946434832 100644 --- a/dstack/dstack-util/src/system_setup.rs +++ b/dstack/dstack-util/src/system_setup.rs @@ -3101,12 +3101,11 @@ impl Stage1<'_> { ciphertext: &[u8], allowed: &BTreeSet, ) -> Result> { - let vars = if !key.is_empty() && !ciphertext.is_empty() { + let vars = if !ciphertext.is_empty() { info!("Processing encrypted env"); - let env_crypt_key: [u8; 32] = key - .try_into() - .ok() - .context("Invalid env crypt key length")?; + let env_crypt_key: [u8; 32] = key.try_into().ok().context( + "encrypted env is present but the key provider gave no valid env crypt key", + )?; let decrypted_json = dh_decrypt(env_crypt_key, ciphertext).context("Failed to decrypt env file")?; crate::parse_env_file::parse_env(&decrypted_json, allowed)?