Skip to main content

dxaws-acm / usage

·493 words·3 mins

Usage
#

dxaws-acm manages DNS-validated ACM certificates and can optionally converge the required Route53 validation records.

The primary public entry point is the manager:

  • AcmManager.execute(desired, options=...)

Basic example
#

Request (or converge) a DNS-validated certificate for a single domain.

from dxaws_acm.manager import AcmManager, ExecuteOptions, ApplyOptions
from dxaws_acm.models import AcmDesired

# AWS is the default provider.
mgr = AcmManager()

desired = AcmDesired(
    domain_name="example.test.dxaws.com",
    subject_alternative_names=[],
    # Prefer zone_name; the manager will resolve the hosted zone id.
    zone_name="test.dxaws.com",
    # CloudFront certificates must be in us-east-1.
    region="us-east-1",
    tags={"dxaws:module": "acm"},
)

opts = ExecuteOptions(
    apply_options=ApplyOptions(
        # waiting controls for DNS publication + issuance
        max_wait_seconds=900,
        poll_interval_seconds=15,
    )
)

result = mgr.execute(desired, options=opts)
print(result.outputs.certificate_arn)

Notes:

  • The manager waits for ACM to publish DNS validation records, converges the validation records via the DNS integration, then waits for ISSUED.
  • Re-running the same call is idempotent.

With Subject Alternative Names (SANs)
#

desired = AcmDesired(
    domain_name="example.test.dxaws.com",
    subject_alternative_names=[
        "www.example.test.dxaws.com",
        "static.example.test.dxaws.com",
    ],
    zone_name="test.dxaws.com",
    # CloudFront certificates must be in us-east-1.
    region="us-east-1",
    tags={"dxaws:module": "acm"},
)

result = mgr.execute(desired, options=opts)
print(result.outputs.certificate_arn)

Overriding providers
#

Most callers should use AcmManager() directly and treat providers as an internal implementation detail.

Providers exist primarily for dependency injection (testing, recording providers, alternate backends). If you need to override providers explicitly:

from dxaws_core import AwsSession

from dxaws_acm.manager import AcmManager
from dxaws_acm.models import AcmDesired
from dxaws_acm.providers.aws import AwsProvider
from dxaws_acm.providers.route53 import Route53RecordProvider

aws = AwsSession(region_name="us-east-1")
acm = AwsProvider(aws=aws)
dns = Route53RecordProvider(aws=aws)

mgr = AcmManager(provider=acm, dns_provider=dns)

desired = AcmDesired(
    domain_name="example.test.dxaws.com",
    subject_alternative_names=[],
    zone_name="test.dxaws.com",
    region="us-east-1",
    tags={"dxaws:module": "acm"},
)

result = mgr.execute(desired)
print(result.outputs.certificate_arn)

If you find yourself needing direct access to a provider method from application or composition code, prefer exposing that capability via the manager interface instead.


Recommended acceptance workflow (real AWS)#

Acceptance tests are opt-in and only run when DXAWS_AWS_TESTS=1.

Recommended environment variables (export once in your shell):

  • DXAWS_ACCEPTANCE_ACCOUNT – dedicated test account id
  • DXAWS_ACCEPTANCE_ZONE_NAME – hosted zone used for validation (e.g. test.dxaws.com)
  • DXAWS_TEST_REGION – AWS region for the run (e.g. ca-central-1, us-east-1 for cloudfront)

Run:

DXAWS_AWS_TESTS=1 make accept-acm

To keep resources for debugging:

DXAWS_AWS_TESTS=1 DXAWS_ACCEPTANCE_CLEANUP=0 make accept-acm

Troubleshooting
#

Certificate is stuck in PENDING_VALIDATION
#

Common causes:

  • The hosted zone is wrong (or not delegated correctly)
  • Route53 validation records were not created
  • You are requesting in the wrong AWS region

What to check:

  • Confirm the test is running in the expected AWS account (the acceptance output prints STS identity)
  • Confirm DXAWS_ACCEPTANCE_ZONE_NAME resolves to the correct public hosted zone
  • Confirm the validation CNAME exists in the hosted zone

ResourceNotFoundException during drift tests
#

ACM is eventually consistent: certificates can appear in list results but fail describe calls briefly.

dxaws-acm hardens this by skipping certificates that disappear between list/describe when enriching list results.


Patch for tests/acceptance/test_website_sequential_acceptance.py
#

assert bucket_name_out_2 == bucket_name_out, (
    f"Expected same bucket name on idempotent apply; first={bucket_name_out!r} second={bucket_name_out_2!r}"
)

# Step gate: default to stopping after S3 while we build this up incrementally.
# Set DXAWS_ACCEPTANCE_STEP=acm (or later steps) to continue.
step = (os.getenv("DXAWS_ACCEPTANCE_STEP") or "s3").strip().lower()
if step in {"s3", "bucket"}:
    return