# Design Notes for dxaws-acm ## Position in the dxaws Architecture `dxaws-acm` is a certificate lifecycle module in the dxaws ecosystem. It manages the lifecycle of **DNS-validated ACM certificates**, but it does not directly manage Route53 validation records. Validation record creation and hosted zone resolution are delegated to the `dxaws-dns` module. This makes `dxaws-acm` a composed module that depends on DNS rather than a fully standalone primitive. It does **not** orchestrate higher-level infrastructure such as CloudFront distributions or website stacks. Those concerns live in higher-level modules (e.g., `dxaws-website`). This separation enforces clean service boundaries, explicit module dependencies, and stable contracts. --- ## Declarative Convergence Model This module follows the dxaws **declarative convergence** pattern. Callers describe the *desired state*: ```python AcmDesired( domain_name="example.test.dxaws.com", region="ca-central-1", tags={...}, ) ``` The module then: 1. **Reads current state** (via provider) 2. **Plans** differences (planner) 3. **Applies** changes (manager + provider) 4. Optionally **waits** for convergence (`ISSUED`) No imperative "create certificate" calls are exposed directly to consumers. --- ## Certificate Scope Model `dxaws-acm` issues **one certificate per FQDN**. The public contract does **not** support Subject Alternative Names (SANs). If multiple hostnames require certificates (e.g., `www.example.com` and `api.example.com`), they must be requested separately. This constraint ensures: - Independent lifecycle management - Simpler drift detection - Cleaner rotation and replacement workflows - Stable and predictable planner behavior The module always treats `domain_name` as the fully qualified domain name to certify. Hosted zone resolution is delegated to the DNS module using a **longest-suffix match** strategy: - The DNS module determines the authoritative Route53 hosted zone - Validation records are written to that zone - ACM never interacts with Route53 directly This avoids ambiguity between zone names and hostnames and keeps service boundaries clean. --- ## Layering Rules ### 1. Planner The planner: - Compares `AcmDesired` with `AcmCurrent` - Determines the action (`noop`, `request`, `recreate`) - Produces a stable, deterministic plan The planner contains **no boto3 logic**. ### 2. Manager The manager: - Coordinates execution of the plan - Handles polling (DNS publication + certificate issuance) - Emits observability events - Ensures idempotency and drift recovery The manager does **not** contain AWS SDK calls directly. ### 3. Provider The provider encapsulates all AWS-specific behavior: - `list_certificates` - `describe_certificate` - `request_dns_validated_certificate` - `delete_certificate` - `get_dns_validation_records` It also normalizes AWS responses into internal models. This keeps AWS shapes and eventual consistency handling out of higher layers. --- ## DNS Validation Handling ACM DNS validation is inherently asynchronous. After requesting a certificate: - ACM may not immediately publish `DomainValidationOptions.ResourceRecord` - ACM may take time to reach `ISSUED` The manager therefore: 1. Polls until validation records appear 2. Converges Route53 CNAME records 3. Polls until certificate status becomes `ISSUED` Timeout behavior is controlled via `ApplyOptions`. --- ## Eventual Consistency Hardening Acceptance tests revealed several AWS edge cases: - Certificates may appear in `list_certificates` but fail `describe_certificate` - Certificates deleted out-of-band may still appear temporarily in listings - Validation records may not be immediately available The module explicitly tolerates these cases: - `describe_certificate` failures during list are treated as transient - Poll loops handle delayed validation record publication - Drift (deleted cert) triggers clean re-request This ensures stable convergence under real AWS timing behavior. --- ## Normalization Rules To ensure deterministic planner behavior: - Domain names are lowercased and stripped of trailing dots - Validation record FQDNs are canonicalized with trailing dots - Idempotency tokens are deterministic, <=32 chars, alphanumeric Planner diffs must remain stable across repeated executions. --- ## Acceptance Guarantees The acceptance suite proves that the module: - Creates DNS-validated certificates - Converges validation records - Reaches `ISSUED` - Is idempotent - Recovers from drift (certificate deleted externally) - Leaves AWS clean after teardown Acceptance runs only when explicitly enabled (`DXAWS_AWS_TESTS=1`). --- ## Explicit Non-Goals This module intentionally does **not**: - Create or delegate Route53 hosted zones - Manage CloudFront distributions - Manage application DNS beyond validation records - Expose imperative certificate APIs - Support multi-domain (SAN) certificates Keeping the primitive narrow ensures composability and contract stability.