+++ title = "Route 53" description = "AWS Route 53 DNS provider plugin" weight = 2 +++ The `mlf-dns-route53` plugin reconciles `_lexicon.*` TXT records using the [AWS Route 53 API](https://docs.aws.amazon.com/Route53/latest/APIReference/Welcome.html), via `aws-sdk-route53`. ## Install ```bash cargo install --path dns-plugins/mlf-dns-route53 ``` ## Credentials Options schema: | Field | Type | Required | Notes | |---|---|---|---| | `access_key` | secret | yes | AWS access key ID | | `secret_key` | secret | yes | AWS secret access key | | `session_token` | secret | no | Optional STS session token for temporary credentials | | `region` | non-secret | no | SDK region. Route 53 is global but a region is needed for signing. Defaults to `us-east-1`. | ### IAM policy Minimum permissions on the hosted zone(s) you publish under: ```json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "route53:ListHostedZonesByName", "route53:ListResourceRecordSets", "route53:ChangeResourceRecordSets" ], "Resource": "*" } ] } ``` Scope the last resource to specific hosted-zone ARNs in production. ## Log in ```bash mlf login dns route53 ``` Prompts for the two required fields (`access_key`, `secret_key`), optionally `session_token`, and defaults `region` to `us-east-1`. Verifies credentials by calling `ListHostedZones` with a limit of 1. Non-interactive (CI): ```bash mlf login dns route53 \ --access-key $AWS_ACCESS_KEY_ID \ --secret-key $AWS_SECRET_ACCESS_KEY \ --project ``` ## Use in mlf.toml ```toml [publish] dns = "route53" ``` ## Quirks - **No per-record IDs.** Route 53 addresses records by `(zone, name, type)`, not numeric ID. The host's `record_id` slot is set to the record's fully-qualified name for round-tripping, but it isn't meaningful outside that one call. - **UPSERT is atomic.** `ChangeResourceRecordSets` with a single `UPSERT` change completes the create-or-replace in one call — no separate read-then-write. - **TXT quoting.** Route 53 wraps TXT values in double quotes and escapes `\` and `"` inside. The plugin handles escape/unescape transparently; values you pass in via `upsert_txt` should be the raw `did=did:plc:…` string.