Key takeaways
- The threat to signed software is not decrypt-later, it is forge-later. An attacker who records your ECDSA-signed firmware today can forge its signatures with a cryptographically relevant quantum computer later, and long-lived devices will accept the forgery at boot. That is why NSA’s CNSA 2.0 demands software signing prefer post-quantum algorithms by 2025 and use them exclusively by 2030, one of the earliest exclusive-use deadlines in the CNSA 2.0 suite.
- AWS’s two-part series (October 12, 2026) is the first end-to-end guide from a cloud provider for post-quantum signing across the supply chain: ML-DSA-87 root CA and ML-DSA-65 subordinate CA in AWS Private CA, ML-DSA code-signing keys in AWS KMS hardware modules, IAM Roles Anywhere for external build agents, and software bills of materials (SBOMs) wrapped in in-toto statements so the dependency manifest is cryptographically bound to the image it describes.
- The enforcement half is where policies live or die. All three ML-DSA variants share one signing algorithm (ML_DSA_SHAKE_256), so the
kms:SigningAlgorithmcondition key cannot tell them apart. Thekms:KeySpeccondition key can, on CreateKey, Sign, Verify, and GetPublicKey. A variant-targeted policy written against the wrong condition key is a documented process that enforces nothing.- A deny-list of the excluded variant leaves a default-allow gap: anything not yet evaluated passes. An allow-list of approved variants is fail-closed but needs a policy update for each new variant. That is the maintenance tradeoff the post calls cryptographic agility: changing what you allow without re-engineering how you enforce it.
Imagine a piece of firmware signed with ECDSA P-256 and shipped to a fleet of embedded devices in 2026. The devices check the signature on every boot. They will live in the field for 15 years, and nobody can recall them to re-sign. In 2035 a cryptographically relevant quantum computer comes online. An attacker produces a valid-looking signature over tampered firmware, and every device in the fleet accepts it as authentic on the next restart.
This is the scenario that opens Part 1 of AWS’s series, and it is the right opening. Almost every post-quantum conversation centers on confidentiality: harvest now, decrypt later. A recent thread on r/cryptography argued the priority is backwards, that authentication is the bigger worry, calling it “trust now, exploit later.” One commenter put the timing argument cleanly: confidentiality has to be fixed before the data is captured, while authentication only has to be fixed before the forgery. For signing, the dangerous window is the forgery, not the harvest. The artifacts you sign today must remain trustworthy for their full operational lifetime.
What AWS actually shipped
Part 1 builds the pipeline. Part 2 makes the algorithm choices stick. The signature scheme is ML-DSA, the Module-Lattice-Based Digital Signature Algorithm standardized as NIST FIPS 204. The architecture has five pillars, and each one replaces a classical dependency with a quantum-resistant one:
- ML-DSA key management in AWS KMS. Signing keys are generated and kept in FIPS 140-3 Security Level 3 hardware security modules. The private key never leaves the HSM.
- ML-DSA certificate hierarchy in AWS Private CA. An ML-DSA-87 root CA (10-year validity, NIST security category 5) issues to an ML-DSA-65 subordinate CA (5 years, category 3). The big key protects the longest-lived anchor; the smaller key signs the certificates issued every day.
- Quantum-resistant workload identity. Build agents outside AWS (Jenkins, self-hosted runners) usually authenticate with RSA or ECDSA credentials. IAM Roles Anywhere with ML-DSA certificates replaces that classical dependency, chaining the signer’s identity back to the same quantum-resistant root. One honest footnote: the TLS carrying the request still authenticates the AWS endpoint the classical way. Transport is out of scope here.
- Artifact signing. Binaries, container images, and packages are signed with the KMS ML-DSA key. Two message modes matter. Most artifacts are larger than the 4,096-byte KMS limit, so the pipeline’s default should be
EXTERNAL_MU: compute the 64-byte message representative externally with OpenSSL 3.5, then pass only that to KMS.RAWis safe only for fixed-size inputs, like the 71-character image manifest digest, because an artifact that fits today will outgrow the limit later. - SBOM attestation. The SBOM is wrapped in an in-toto Statement that names the artifact by digest, and the Statement is signed with the same code-signing key.
Two details in Part 1 deserve attention because they are the kind of thing a team gets wrong quietly. First, because the KMS private key never leaves the HSM, you cannot generate the code-signing CSR with OpenSSL locally. You construct the CSR’s to-be-signed structure, sign it remotely with aws kms sign, and assemble the result in code. There is no CLI-only path; the post points to a Java sample as the reference implementation.
Second, the SBOM binding. Signing the SBOM file proves the inventory has not been tampered with, but it does not prove which artifact the SBOM describes. An attacker holding a legitimately signed SBOM for a clean image could present it next to a different signed image. Attaching the SBOM as an OCI (Open Container Initiative) referrer does not close this, because the referrer’s subject field is set by whoever pushes it. It is a discovery mechanism, not a cryptographic binding. The binding has to be inside the signed bytes. That is what the in-toto Statement does: the image digest sits in the signed content, and the verifier checks the subject digest resolved from the registry, never from the Statement. A swapped SBOM or a swapped digest fails. On r/devsecops this month, a practitioner drew the line exactly there: the useful question is not whether you have an SBOM, it is whether the metadata survives into an enforcement decision, bound to the same asset identity as the decision. Teams are past the visibility bottleneck. They want enforcement, not another dashboard.
The verification half most teams skip
A signing pipeline is half building, half verifying. Part 1 gives the verifier workflow teeth: distribute the trust chain to every verification point, check the certificate with -purpose codesign (a chain check alone accepts the build-agent client certificates from the same CA, so purpose matters), pin the expected signer subject, and resolve the digest from the registry. At deployment time, a Kubernetes admission controller runs before any pod is scheduled and rejects images without a valid ML-DSA signature referrer or whose SBOM attestation does not name the image. One production note worth stealing: a registry lists referrers in no reliable order, and an image that has been re-signed has more than one. A verifier should check every referrer of the type and accept if at least one verifies. Taking only the first can reject a correctly signed image. It can never accept an unsigned one.
Break your own guardrail
Now the part this article is really about. Part 2 is written for the security and governance teams who decide which algorithms the pipeline, and everything else in the organization, may use. The core example policy: the organization has standardized on ML-DSA-65 and ML-DSA-87 and wants ML-DSA-44 kept out. Not because ML-DSA-44 is weak. It is a fully standardized, NIST category 2 parameter set, the smallest and fastest of the three, a good fit for constrained devices and high-volume signing. The exclusion is a standardization decision, and the post says so plainly.
The mechanism that makes the policy real is the kms:KeySpec condition key. This is the single most important technical detail in the series, so here it is twice. AWS KMS exposes three ML-DSA key specs, ML_DSA_44, ML_DSA_65, ML_DSA_87, and all three use one signing algorithm: ML_DSA_SHAKE_256. A policy condition written against kms:SigningAlgorithm therefore cannot distinguish the variants. kms:KeySpec reflects the key’s actual variant and is evaluated on CreateKey, Sign, Verify, GetPublicKey, and even ReplicateKey. Preventing the creation of ML-DSA-44 keys is the strongest single control: if no ML-DSA-44 KMS keys exist, none can be used, and none can become the subject key of a certificate.
The playground below is a teaching model of this enforcement logic. Pick a policy shape and a condition key, run five realistic signing requests through it, and watch what survives. The fifth request is a hypothetical ML-DSA-128, a stand-in for any variant nobody has evaluated yet.
Interactive: the policy playground
This is a teaching model of the enforcement half of AWS's series, not AWS itself. Pick how your algorithm policy is written, run five realistic signing requests through it, and watch what survives. Nothing here touches a real account; the evaluation logic below mirrors the policy semantics the post describes.
Calibration: in the AWS post, the policy excludes ML-DSA-44 while approving ML-DSA-65 and ML-DSA-87 (a standardization choice, not a claim that ML-DSA-44 is insecure). All three variants share one signing algorithm, ML_DSA_SHAKE_256. ML_DSA_128 is invented for the fifth request: a stand-in for any not-yet-evaluated variant.
| Request | Key spec | Result | Why |
|---|
What the blocked caller sees
An AccessDenied error naming an explicit deny in a service control policy. The error does not expose the policy contents, and the blocked person usually cannot see the SCPs attached above their account. That is why the post tells you to document the SCP ARN and its purpose internally, so support can map a denial quickly.
Two honest limits from the post. First, SCPs do not apply to the management account, so nothing above binds workloads run there. Second, none of this governs cryptography on compute you control: an ML-DSA-44 signature computed with OpenSSL on an EC2 instance is outside SCP and IAM reach.
The layers behind the playground
The simulator shows one SCP. The post layers four, each covering a different scope:
- Service control policy (SCP) at the organization root or organizational unit (OU). The broadest preventive control: deny
kms:CreateKeyand the usage trio (Sign,Verify,GetPublicKey) whereverkms:KeySpecisML_DSA_44. An explicit Deny in an SCP cannot be overridden by any IAM policy in member accounts. Two gotchas: keep the usage deny scoped to those three actions, notkms:*, or you lock yourself out ofDescribeKey,DisableKey, andScheduleKeyDeletionfor the very keys you want to remove. And SCPs do not apply to the management account, so do not run signing workloads there and expect the guardrail to hold. - IAM policy and permission boundaries. The principal-level counterpart for per-account or per-role control. A boundary opens with an allow on everything, then denies ML-DSA-44 creation; a Deny in a boundary cannot be overridden by an attached policy. But a boundary only binds principals that carry it, so you need a mechanism that forces it onto every principal: the post sketches an SCP that denies creating roles or users unless the approved boundary is set, denies deleting boundaries outright, and probes for drift.
- KMS key policies. A resource-side backstop on a specific key. Same
kms:KeySpecdeny, with aPrincipalelement added. Protects the key itself while the SCP gives organization-wide coverage. - Detective controls. CloudTrail logs the
KeySpeconCreateKeyand the signing algorithm onCreateCertificateAuthority, which makes it the effective creation-time detector. AWS Config custom rules flag drift. Deleting a key you cannot find is hard; AWS KMS has no server-side filter for key spec, so you enumerate withListKeysand inspect each one, or use Config to record the inventory. Remember what deletion costs: it is difficult to know what data a key has signed unless you tracked it, and deleting a used key makes its signatures unverifiable.
Where no condition key exists, the post is honest about the limits. acm-pca:CreateCertificateAuthority takes the algorithm at creation time but exposes no algorithm condition key, so the enforcement moves into the provisioning pipeline: restrict who can call it, hard-code the algorithm in the approved template, and detect drift with CloudTrail and Config. One quiet detail: Private CA copies the subject key from the CSR without validating its algorithm, so pin the CSR’s key algorithm in the same pipeline. Certificate import and upload (acm:ImportCertificate, iam:UploadServerCertificate) are not algorithm-aware at all; deny them where they are not required. Load balancer listeners reference certificates by ARN, so no SCP can inspect the certificate’s algorithm at binding time. The control is the material itself: with no ML-DSA-44 CA, no ML-DSA-44 KMS key, and import controlled, no ML-DSA-44 certificate can be issued or bound.
Then the agility question, which is really a maintenance question. A deny-list that names the excluded variant is an allow-list of everything it does not name. A new variant becomes usable until someone notices it and adds it. That is exactly what the playground’s ML-DSA-128 request demonstrates. The alternative writes the condition against the approved set instead: a Deny on any ML-DSA variant outside {ML_DSA_65, ML_DSA_87} fails closed on the unknown, at the cost of a policy update before anyone can use something new. Both shapes are legitimate. The choice is whether you would rather block first and approve later, or notice first and decide then.
The compliance homework
Three deadlines make this a now problem rather than a someday problem.
CNSA 2.0. NSA’s Commercial National Security Algorithm Suite 2.0 requires US National Security Systems to support and prefer quantum-resistant signatures for software and firmware by 2025 (in effect), makes all new NSS acquisitions CNSA 2.0 compliant from January 1, 2027, and mandates exclusive use by 2030. Signing carries one of the earliest exclusive-use deadlines in the CNSA 2.0 suite because firmware roots of trust are the hardest to update after deployment. One nuance for the cautious: when ML-DSA is used for signing on NSS, CNSA 2.0 permits only ML-DSA-87 (stateful hash-based LMS and XMSS are also approved for this purpose). The ML-DSA-65 used in the post’s code-signing examples is appropriate for commercial workloads but is not permitted on NSS.
EU Cyber Resilience Act. The regulation applies in full on December 11, 2027. Products placed on the EU market must protect the integrity of stored, transmitted, and processed data against unauthorized manipulation, and manufacturers must provide mechanisms to securely distribute updates. A signed SBOM accompanying every release, built the way Part 1 builds it, is what that obligation looks like in practice. The vulnerability-reporting duties have been live since September 11, 2026, so the window between now and full application is the migration period, not a grace period.
PCI DSS 4.0. Requirement 12.3.3 has mandated, since March 2025, that cryptographic cipher suites and protocols in use are documented and reviewed at least annually, with an up-to-date inventory. Tagging ML-DSA versus traditional keys in KMS and tracking migration progress turns the post’s architecture into the evidence for that requirement.
For artifacts that must stay verifiable beyond a certificate’s expiry, the post lists three approaches: longer certificate validity in private PKI, trusted timestamping per RFC 3161 from a time stamping authority (AWS does not run a managed one), or re-signing with a fresh certificate before expiry. Long-lived artifacts are precisely the ones the forge-later threat targets, so pick one deliberately.
The honest limits
Four caveats. The post states three of them; the fourth is mine.
First, ML-DSA-44 is not a villain. The post’s exclusion is standardization, and ML-DSA-44’s small signatures and speed make it the right call for constrained devices, high-volume signing, and bandwidth-sensitive workloads. A policy that excludes it should say why in plain language, or engineers will read it as a security judgment and route around it.
Second, the forge-later threat is scoped to the long-lived tail. A container image you redeploy weekly has a different window than firmware baked into a meter. Size your migration to the tail, not the average.
Third, the controls govern AWS service APIs, not cryptography on compute you control. ML-DSA-44 signing with OpenSSL on an EC2 instance, hybrid ssh-mldsa44-ed25519 public key authentication, and imported certificates are outside the reach of SCPs and IAM. The series is defense in depth for the services it covers, not a perimeter.
Fourth, the math being settled does not settle the engineering. A thread on r/crypto this summer machine-checked a deployed ML-DSA implementation against FIPS 204 and found a one-character bug in a hint decoder that accepted non-canonical hints. Practitioners split on what that means, but the practical takeaway survived the argument: standard algorithms still need hostile testing, and test-vector suites like Wycheproof are the mitigation. A migration plan that trusts the standard and skips the testing is half a plan.
One open question nobody can answer for you: the date. No credible source will tell you when a cryptographically relevant quantum computer arrives, and the deadlines above are priced against that unknown. That is why the earliest exclusivity dates target the longest-lived artifacts first.
Start where the post tells you to start: create one ML-DSA key in KMS and sign a test artifact. Then extend to the public key infrastructure (PKI) hierarchy, wire IAM Roles Anywhere for your external build agents, and add ML-DSA signatures to your container and SBOM workflows. The pipeline is half the work. The other half is the policy playground you just ran: making the algorithm choices stay in force as accounts, teams, and standards change.
The AWS series is vendor documentation for AWS services, which is both its strength and its limit. The enforcement patterns transfer: whatever your approved set is, and wherever your keys live, the question is the same. Can your policy name the variant you excluded, and would anything notice if it could not?
Primary sources
- Quantum-resistant signing on AWS, Part 1: Build a software supply chain with ML-DSA (AWS Security Blog)
- Quantum-resistant signing on AWS, Part 2: Enforce your ML-DSA algorithm policy with SCPs and IAM (AWS Security Blog)
- FIPS 204: Module-Lattice-Based Digital Signature Standard (NIST)
- CNSA 2.0: Complete Guide to NSA's PQC Requirements (postquantum.com)
- The EU Cyber Resilience Act: What Engineering Teams Need to Do to Be Compliant (Cloudsmith)
- ML-DSA keys in AWS KMS (AWS Documentation)
- No Matter What Anyone Else Tells You, Harvest Now, Decrypt Later Quantum Attacks Will Never Be a Big Problem (practitioner discussion) (Reddit)
- Is software supply chain security finally becoming more than just SBOMs? (practitioner discussion) (Reddit)
- Exploiting ML-DSA bugs (practitioner discussion) (Reddit)