refactor: mint self-issued RA-TLS client certificates for KMS calls - #1108
Draft
kvinwang wants to merge 3 commits into
Draft
refactor: mint self-issued RA-TLS client certificates for KMS calls#1108kvinwang wants to merge 3 commits into
kvinwang wants to merge 3 commits into
Conversation
kvinwang
force-pushed
the
feat/ratls-guest-self-signed
branch
2 times, most recently
from
August 23, 2026 16:52
fec32d7 to
c1cfe16
Compare
kvinwang
force-pushed
the
feat/ratls-guest-self-signed
branch
from
August 23, 2026 16:57
c1cfe16 to
2f6a1f9
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
refactor: mint self-issued RA-TLS client certificates for KMS calls
Client-side half of #1106, for both callers: guests at boot, and KMS↔KMS onboarding.
Stacked on #1106 — review that first. Draft: targets 0.6.1 or later, not 0.6.0 (see
Version requirement).
Problem
A client cannot present an RA-TLS certificate to the KMS without first asking the KMS for
a CA private key:
request_app_keys_from_kms_urlcallsGetTempCaCertand mints from it;onboard_service.rsdoes the same beforeGetKmsKey.Both do it purely so rustls' pinned-CA check passes. #1106 removed that pin — the KMS
authenticates the attestation inside the certificate and ignores the issuer — so the fetch
is now pure ceremony. It is not free:
.appkeys.json(system_setup.rs:2557-2558), and reused for the CVM's lifetime(
cert-client/src/lib.rs:79);(#561,
#619);
generate_ra_certtakes a fresh TDX quote on everyCertRequestClient::create, toproduce a certificate whose issuer nobody checks.
Fix
generate_self_signed_ra_certmints the same certificate without a CA. The quote'sreport_databinds the certificate's own SPKI, which is the whole identity.Onboarding gets its own self-signing path rather than reusing that helper, because the KMS
takes its quote through the guest agent (
app_attest) rather thanra_tls's direct quotepath — its attestation has to carry the agent's app info.
The KMS root CA now comes from
GetMetainstead ofGetTempCaCert. Same trust posture asbefore, not a new one: learned over the same unauthenticated connection, pinned
immediately afterwards by
verify_key_provider_id(system_setup.rs:2202-2215) againstthe measured
app_compose.key_provider_id, beforesetup_fswrites keys or mounts thedata disk.
GetMetaResponseis byte-identical across every 0.5.x release andnext.Removing onboarding's
GetTempCaCertcall also removed the round trip that itscert_validatorneeded in order to capture the source KMS's attestation — the validatorfires on a response, not on client construction, and
ensure_kms_allowedran before thekey fetch. Rather than re-add a call purely for that side effect, onboarding now runs over
a single client that carries both the client certificate and the validator, and
re-checks the source against local policy after
GetKmsKeyinstead of before it.That is a net improvement over what is there today, not just a wash.
RaClient::new_mtls— onboarding's only user, now removed — set no
cert_validator, andtry_validate_attestationreturnsOk(())immediately when there is none(
client.rs:132-134). So the mTLS connection that actually carries the root CA privatekey performed no server attestation verification at all; the source was verified only
on a separate earlier connection, with nothing binding the two. Now the handshake that
carries the key is the one that is verified.
ensure_kms_allowedmoves after the fetch. The source decides whether to release keys tous, and the validator has already verified its attestation on this connection, so the
check is a defence-in-depth one against our own policy rather than the thing standing
between a peer and the keys.
KeyProvider::Kmslosestmp_ca_key/tmp_ca_cert..appkeys.jsonis regenerated fromthe KMS on every boot and
AppKeysis notdeny_unknown_fields, so a file written by anolder image still parses.
docs/encrypted-env-spec.mdis updated to match.GetTempCaCertnow has no caller in this tree. It is retained, and the temp CA isstill generated and served, so guest images built before this change keep booting. The
proto and handler notes from #1106 are updated to say so.
Version requirement
A self-issued certificate is refused at the handshake by any KMS that still pins the temp
CA — every release up to and including 0.5.11. So:
This is why it targets 0.6.1+ rather than 0.6.0: #1106 ships in 0.6.0, so by the time this
lands every KMS in the field already accepts self-issued certificates.
The residual constraint is that a cluster still on 0.5.x upgrades through 0.6.0 as a
bridge hop rather than jumping straight to 0.6.1+. That is the same two-hop shape 0.5.4
already requires today (TC-KMS-UPGRADE-001). Direct 0.5.8/0.5.11 → 0.6.0 onboarding
(TC-KMS-UPGRADE-003/004) is unaffected, because 0.6.0 does not contain this change.
For reference, what changes for a client built from this PR, measured against PR #841's
upgrade matrix:
ra-tls/src/oids.rshas noPHALA_RATLS_ATTESTATION(.8), so it cannot read the versioned attestationtmp-ca.crt, so the handshake is refusedThe 0.5.4 row already matches TC-KMS-UPGRADE-005 ("The 0.5.4 source rejects the versioned
attestation certificate").
Verification
A KMS built from this branch, probed with
curl(client certificates carry asyntactically valid but deliberately non-binding attestation, so
invalid quote: report data mismatchis the app layer proving it still verifies quotes after the handshake):invalid quote: report data mismatchinvalid quote: report data mismatchGetMetaca_certGetTempCaCertRow 2 and row 5 are the compatibility guarantee for guest images built before this change.
cargo fmt --check, the CI clippy invocation, and the touched crates' suites are clean.Still to do before this leaves draft: boot a real CVM against a KMS carrying #1106 and
confirm
GetMeta→ self-issued cert →GetAppKey→verify_key_provider_idend to end,plus a
cert-clientSignCertround trip and one real KMS↔KMS onboard. None of that isrunnable without TDX hardware.