Skip to content

Commit 9ed633a

Browse files
authored
Merge pull request #753 from Dstack-TEE/aws-attestation-platform-spec
Add AWS EC2 NitroTPM attestation and guest OS support
2 parents eb4a357 + 6bd4e6d commit 9ed633a

67 files changed

Lines changed: 4873 additions & 593 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# AWS EC2 Instance Attestation Security Evaluation
2+
3+
This document evaluates dstack attestation on AWS EC2 with NitroTPM
4+
(Attestable AMIs) under the account-admin-untrusted threat model. It states
5+
the security properties dstack requires from a platform and how the AWS
6+
NitroTPM path satisfies them in the current implementation. For the
7+
operational relying-party workflow (verifier deployment, allowlists, key
8+
release), see `docs/aws-ec2-production-verifier-runbook.md`.
9+
10+
The threat model is:
11+
12+
- Trusted root: AWS Nitro system and NitroTPM attestation signing
13+
infrastructure.
14+
- Verified, not blindly trusted: dstack OS images, dstack KMS instances,
15+
dstack verifier code, and governance policy. The relying party accepts these
16+
only after checking reproducible build outputs, attested measurements, event
17+
logs, and policy state. A published AMI ID or a running KMS endpoint is not
18+
sufficient evidence by itself.
19+
- Untrusted: the workload AWS account administrator/operator. They may launch,
20+
stop, replace, snapshot, reconfigure, and network-interpose EC2 resources in
21+
their account. AWS KMS keys controlled by that account are also untrusted for
22+
secret authority because the account administrator may be able to change key
23+
policy, create grants, or route secret-bearing calls through policies they
24+
control.
25+
- Out of scope: availability. The operator can always deny service.
26+
27+
## Platform Security Property Spec
28+
29+
The following properties are the readiness gates for any platform claiming the
30+
same security level as dstack under this threat model, and how the AWS
31+
NitroTPM path meets them today.
32+
33+
| ID | Required property | dstack mechanism | AWS NitroTPM status |
34+
| --- | --- | --- | --- |
35+
| P1 | Verifiable platform root of trust | TDX/SNP/Nitro quote verification against vendor root; debug rejected; TCB surfaced | NitroTPM Attestation Documents are verified against the AWS Nitro Attestation PKI, including document timestamp sanity. AWS exposes no TDX/SNP-style TCB advisory field, so a verified attestation is normalized to `tcbStatus = "UpToDate"` and passes the standard authorization gate unchanged. |
36+
| P2 | Reproducible or independently computable base image measurement | meta-dstack rebuild plus `dstack-mr` computes `MRTD`/`RTMR0-2` | The unified `os/build.sh` flow emits the AWS image archive with `sha256sum.txt`, `digest.txt`, and `measurement.aws.cbor`; its output directory also contains the reference-PCR side-car `aws-pcrs.json`. `os_image_hash = sha256(sha256sum.txt)` is the same identity used on all platforms; the verifier recomputes it from the downloaded image directory (`dstack/verifier/src/verification.rs`). The hardening audit script `os/yocto/tools/aws/audit-aws-ec2-image-hardening.sh` checks the image for operator mutation channels. |
37+
| P3 | Boot command line and root filesystem integrity are measured | `RTMR1/2`, rootfs hash, dm-verity, measured initrd/cmdline | The UKI commits kernel, initrd, and embedded cmdline into `PCR4`; the rootfs is dm-verity-protected. `VmConfig.aws_measurement` is required and must bind `boot_pcr_digest = sha256(PCR4||PCR7||PCR12)` to the attested PCRs, so `PCR12` (external cmdline) is always part of the bound digest — a missing-PCR12 bypass is not expressible. Enforced in guest quote generation (`dstack/dstack-attest/src/attestation.rs`), `verify_os_image_hash_for_aws_nitro_tpm` (`dstack/verifier/src/verification.rs`), and the KMS pipeline via the same verifier check. |
38+
| P4 | Runtime application identity is cryptographically bound | RTMR3 `compose-hash`, `app-id`, `instance-id`, `key-provider`; event log replay | SHA384 `PCR14` event-log replay is the authoritative binding (RTMR3 analogue; non-resettable). Launch events: `system-preparing`, `app-id`, `compose-hash`, `instance-id`, `boot-mr-done`, `key-provider`, `storage-fs`, `system-ready` (`dstack/dstack-util/src/system_setup.rs`). `dstack-attest`, `dstack-verifier`, and KMS reject missing/mismatched PCR14 and bad replay. Optionally, the guest extends the raw `MrConfig` V2 `config_id` into `PCR8` once (`PCR8 = sha384(0^48 || config_id)`) so a lightweight third-party verifier can check compose hash + key provider without event-log replay; dstack's own verifier and KMS do not check PCR8. |
39+
| P5 | Challenge/liveness and caller key binding | `report_data` challenge or RA-TLS public key hash in quote | RA-TLS binds `report_data` to the TLS certificate public key. KMS key release is bound to the live RA-TLS handshake; external `/verify` callers supply and check their own `report_data` challenge. The low-level NitroTPM document verifier also rejects stale or far-future document timestamps. |
40+
| P6 | Secret release only to attested code | dstack KMS verifies attestation, checks auth policy, derives per-app keys | dstack KMS verifies the NitroTPM attestation, runs the same `verify_os_image_hash_for_aws_nitro_tpm` binding check as the verifier, builds `BootInfo` from verified boot PCRs plus PCR14 launch events, and checks auth policy before deriving app keys (`dstack/kms/src/main_service.rs`). AWS NitroTPM key release is gated behind the opt-in `aws_nitro_tpm_key_release` flag (default false in `kms.toml`). |
41+
| P7 | Key-release policy is not controlled by the untrusted account admin | KMS runs inside TEE; policy from auth API/contracts; KMS identity measured | Satisfied with dstack KMS or another verifiable secret authority outside the untrusted AWS account admin's control. A NitroTPM-backed dstack KMS keeps root material out of account-admin snapshots and clones. The policy backend (auth-simple in a trusted control plane, or on-chain `DstackKms`/`DstackApp`) must be outside the workload account admin's control. Same-account AWS KMS fails this property if the admin can change key policy, create grants, or call secret-bearing operations through a policy they control. |
42+
| P8 | Operator cannot inject boot-time or runtime inputs that affect secrets without detection | Host-shared files are measured or independently authenticated; KMS URLs not trusted, KMS key identity measured | App TPM access is enforced by measurement, not by a container sandbox: `init_script`, `pre_launch_script`, and the docker-compose are measured into the app-compose hash, hence into the governed app identity, and replayed into non-resettable `PCR14`, so an operator cannot alter app inputs without changing the measured identity and being denied key release. Production dstack-os AWS images exclude SSH, cloud-init, SSM, EC2 Instance Connect, and serial login (checked by `audit-aws-ec2-image-hardening.sh`). IMDS/operator-provided config must not be a secret-affecting input unless measured or authenticated. |
43+
| P9 | Persistent state confidentiality from account admin | dstack disk key derived after attestation; encrypted env vars decrypted only inside CVM | The local TPM key provider seals the disk seed under a SHA384 PCR policy over `[4, 7, 8, 12, 14]` (`AWS_NITRO_PCRS` in `dstack/tpm-attest/src/lib.rs`), so the sealed seed survives same-instance stop/start but does not transfer with cloned EBS volumes to another instance. EBS snapshots and volumes remain account-admin visible at the AWS control plane, so persisted confidential state must stay encrypted inside the instance and AMIs must contain no secrets. |
44+
| P10 | Network and TLS endpoint identity is attestation-bound | RA-TLS / Zero Trust HTTPS / gateway attestation; TLS keys generated in TEE | The Rust RA-TLS verifier exposes `verify_der`/`verify_pem`, which extract the certificate's embedded attestation, verify it with the platform verifier (including AWS NitroTPM), and require `report_data = QuoteContentType::RaTlsCert(SubjectPublicKeyInfo)`. `dstack-verifier --verify-cert` provides an operator/relying-party certificate evidence path that also binds `os_image_hash`. AWS attestation alone does not protect DNS, load balancers, or admin-controlled proxies; clients must require this RA-TLS check, signed responses, or an attested gateway. |
45+
| P11 | Upgrade governance is explicit and non-bypassable | DstackApp/DstackKms whitelists compose hashes, OS images, KMS aggregate MRs | auth-simple and the unchanged on-chain `DstackKms`/`DstackApp` contracts pin OS image hash, app compose hash, device ID, and KMS identity. KMS auth pins the early `mrAggregated` (the `boot-mr-done` launch-event snapshot). AWS reuses the standard gate via `tcbStatus = "UpToDate"` normalization with no AWS-specific on-chain field, plus the opt-in `aws_nitro_tpm_key_release` KMS flag. Secure Boot PCR7 certificate policies need explicit rotation/revocation handling so old AMIs do not remain authorized. |
46+
| P12 | Verifier is independent and complete | `dstack-verifier`, DCAP/QVL, RTMR replay, KMS/app/governance checks | `dstack-verifier` verifies the NitroTPM document against the AWS Nitro PKI, enforces the required `aws_measurement`/`boot_pcr_digest` binding against the unified `os_image_hash`, replays the PCR14 launch-event chain, and emits the canonical auth-policy object as `details.boot_info` for the same policy logic used by `/bootAuth/app` and `/bootAuth/kms`. The relying-party deployment workflow is `docs/aws-ec2-production-verifier-runbook.md`; each deployment must instantiate it with real OS-image, PCR, and compose-hash allowlists. |
47+
48+
## Sources
49+
50+
- AWS EC2 instance attestation:
51+
https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/nitrotpm-attestation.html
52+
- AWS Attestable AMIs:
53+
https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/attestable-ami.html
54+
- AWS custom AMI PCR computation:
55+
https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/create-pcr-compute.html
56+
- AWS NitroTPM Attestation Document:
57+
https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/attestation-get-doc.html
58+
- AWS NitroTPM Attestation Document validation:
59+
https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/nitrotpm-attestation-document-validate.html
60+
- AWS NitroTPM Attestation Document contents:
61+
https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/nitrotpm-attestation-document-content.html
62+
- AWS KMS attested calls:
63+
https://docs.aws.amazon.com/kms/latest/developerguide/attested-calls.html
64+
- AWS NitroTPM samples:
65+
https://github.com/aws/nitrotpm-attestation-samples
66+
- AWS advisory on PCR12:
67+
https://github.com/aws/nitrotpm-attestation-samples/security/advisories/GHSA-xrv8-2pf5-f3q7
68+
- dstack security model: `docs/security/security-model.md`
69+
- dstack TDX attestation guide: `docs/attestation-tdx.md`
70+
- dstack KMS protocol: `dstack/kms/README.md`
71+
- dstack Nitro Enclave flow: `docs/attestation-nitro-enclave.md`
72+
- dstack GCP TDX + TPM flow: `docs/attestation-gcp.md`
73+
- AWS EC2 production verifier runbook:
74+
`docs/aws-ec2-production-verifier-runbook.md`

0 commit comments

Comments
 (0)