← Week 2: ACM Private CA — architecture + API

Day 9: ACM PCA API — Creating and Activating a CA

Phase 5 · September 3, 2026

← Week 2: ACM Private CA — architecture + API

Agenda (2–3 hours)

  • Read (45 min): ACM PCA API Reference — CreateCertificateAuthority, ActivateCertificateAuthority
  • Study (60 min): The CA creation lifecycle; root vs. subordinate activation flow
  • Write (45 min): Map API calls to your hierarchy design
← Week 2: ACM Private CA — architecture + API

The CA Lifecycle in ACM PCA

Creating a CA is a multi-step process:

1. CreateCertificateAuthority
   └── CA enters PENDING_CERTIFICATE state
       (key generated in HSM; CSR ready; but no cert issued yet)

2. GetCertificateAuthorityCsr
   └── Download the CA's CSR

   [For Root CA]                    [For Subordinate CA]
   3a. IssueCertificate             3b. Pass CSR to parent CA for signing
       (self-sign the CSR)               (ACM PCA or external)

4. ImportCertificateAuthorityCertificate
   └── Upload the signed CA cert
   └── CA transitions to ACTIVE state

5. CA is now active — ready to issue leaf certs
← Week 2: ACM Private CA — architecture + API

Step 1: CreateCertificateAuthority

// Rust SDK: aws-sdk-acmpca
use aws_sdk_acmpca::types::{
    CertificateAuthorityConfiguration, CertificateAuthorityType,
    KeyAlgorithm, SigningAlgorithm, Subject,
};

let config = CertificateAuthorityConfiguration::builder()
    .key_algorithm(KeyAlgorithm::EcPrime256V1)
    .signing_algorithm(SigningAlgorithm::Sha256Withecdsa)
    .subject(
        Subject::builder()
            .common_name("Leo Provisioning Subordinate CA")
            .organization("Amazon")
            .country("US")
            .build()
    )
    .build()?;

let resp = acmpca_client
    .create_certificate_authority()
    .certificate_authority_configuration(config)
    .certificate_authority_type(CertificateAuthorityType::Subordinate)
    .send()
    .await?;

let ca_arn = resp.certificate_authority_arn().unwrap();
println!("CA ARN: {ca_arn}");
// CA is now in PENDING_CERTIFICATE state
← Week 2: ACM Private CA — architecture + API

Step 2: Download the CSR

let csr_resp = acmpca_client
    .get_certificate_authority_csr()
    .certificate_authority_arn(ca_arn)
    .send()
    .await?;

let csr_pem = csr_resp.csr().unwrap();
// csr_pem is the CSR in PEM format
// For a subordinate CA: send this CSR to the parent CA for signing
// For a root CA: self-sign via IssueCertificate (same CA, or offline)

std::fs::write("subordinate-ca.csr", csr_pem)?;
println!("CSR written to subordinate-ca.csr");
← Week 2: ACM Private CA — architecture + API

Step 3a: Self-Sign a Root CA

If the CA is a Root CA, use IssueCertificate with the root CA itself as issuer:

// For a Root CA: issue against itself
// validity is specified via the Validity struct
use aws_sdk_acmpca::types::{Validity, ValidityPeriodType};

let issue_resp = acmpca_client
    .issue_certificate()
    .certificate_authority_arn(root_ca_arn)
    .csr(root_ca_csr_bytes)  // the root CA's own CSR
    .signing_algorithm(SigningAlgorithm::Sha256Withecdsa)
    .template_arn("arn:aws:acm-pca:::template/RootCACertificate/V1")
    .validity(
        Validity::builder()
            .r#type(ValidityPeriodType::Years)
            .value(15)
            .build()?
    )
    .send()
    .await?;
← Week 2: ACM Private CA — architecture + API

Step 3b: Sign a Subordinate CA CSR

If you have an offline root, sign the CSR using your offline CA tooling:

# Using OpenSSL to sign the subordinate CA CSR with an offline root:
openssl ca \
  -keyfile root-ca.key \
  -cert root-ca.crt \
  -extensions v3_ca \
  -days 1825 \
  -in subordinate-ca.csr \
  -out subordinate-ca.crt

# Or using your toy-pki from Phase 2:
toy-pki sign-ca --csr subordinate-ca.csr --out subordinate-ca.crt

The signed certificate is then imported back into ACM PCA in Step 4.

← Week 2: ACM Private CA — architecture + API

Step 4: ImportCertificateAuthorityCertificate

// Import the signed certificate to activate the CA
let cert_pem = std::fs::read("subordinate-ca.crt")?;
let chain_pem = std::fs::read("root-ca.crt")?;

acmpca_client
    .import_certificate_authority_certificate()
    .certificate_authority_arn(ca_arn)
    .certificate(aws_smithy_types::Blob::new(cert_pem))
    .certificate_chain(aws_smithy_types::Blob::new(chain_pem))
    .send()
    .await?;

println!("CA activated successfully");
// CA transitions from PENDING_CERTIFICATE to ACTIVE

After import, DescribeCertificateAuthority should return Status = ACTIVE.

← Week 2: ACM Private CA — architecture + API

Useful AWS CLI Commands

When you don't have a Rust binary yet, the CLI is faster for exploration:

# Create a CA
aws acm-pca create-certificate-authority \
  --certificate-authority-configuration \
    "KeyAlgorithm=EC_prime256v1,SigningAlgorithm=SHA256WITHECDSA,\
     Subject={CommonName=Test CA,Organization=TestOrg,Country=US}" \
  --certificate-authority-type SUBORDINATE

# Check CA status
aws acm-pca describe-certificate-authority --certificate-authority-arn <ARN>

# Download CSR
aws acm-pca get-certificate-authority-csr \
  --certificate-authority-arn <ARN> \
  --output text

# List CAs
aws acm-pca list-certificate-authorities
← Week 2: ACM Private CA — architecture + API

Challenge Assignment

Map each ACM PCA API call to your hierarchy design:

For each CA in your §1 hierarchy (root, subordinate, issuance tier(s)):

  1. Which API call creates it? (CreateCertificateAuthority parameters)
  2. How is it activated? (self-signed root, offline-signed sub, or ACM PCA parent-signed sub)
  3. What is its initial status? And what triggers the transition to ACTIVE?

Write this as a table in acm-pca-design.md §2 (preview):

CA Type KeyAlgorithm Activation method Validity
Leo Root CA ROOT EC_prime256v1 Self-signed 15y
Leo Sub CA SUBORDINATE EC_prime256v1 Signed by root (offline) 5y
Leo Device Issuance CA SUBORDINATE EC_prime256v1 Signed by sub CA 2y
← Week 2: ACM Private CA — architecture + API

Resources

  • ACM PCA API Reference: docs.aws.amazon.com/privateca/latest/APIReference
  • aws-sdk-acmpca Rust crate: docs.rs/aws-sdk-acmpca
  • CA lifecycle: docs.aws.amazon.com/privateca/latest/userguide/ca-lifecycle.html
  • Certificate templates: docs.aws.amazon.com/privateca/latest/userguide/UsingTemplates.html