Skip to content

Connection & Credential Naming Standard

A Hyperdrive config bakes in exactly one MySQL user and one password. So the moment a database needs both a read-only and a read-write role, the split propagates through the entire access chain: two MySQL users, two secrets, sometimes two origin hostnames, two Hyperdrive configs, and two Worker bindings. This standard fixes one name at every link so that, given a database, an environment, and an access mode, every name in the path is derivable without lookup.

This standard governs the console, aggregate, and billing databases and applies identically to any future database reached through Hyperdrive.

Every Worker-to-database connection runs the same path: a binding resolves to a Hyperdrive config, which connects to a public hostname that Cloudflare Access protects and cloudflared proxies to the private RDS or Aurora endpoint. The read-write binding carries the write grant and reaches the writer endpoint; the read-only binding carries only SELECT and, in production, reaches the Aurora reader endpoint.

The access chain, one database, two access modes (production console) WORKER DB_CONSOLE_RW DB_CONSOLE_RO HYPERDRIVE CONFIG adv-hd- console-rw-prd adv-hd- console-ro-prd CLOUDFLARE EDGE Access service-token auth on each db-* hostname, then the tunnel cloudflared on adv-cflared-prd (ASG) AURORA (PRODUCTION) Writer endpoint production.cluster-... Reader endpoint production.cluster-ro-... MySQL user hd_console_rw reaches the writer; hd_console_ro reaches the reader. Dev and staging collapse both lanes onto one instance.
Binding → Hyperdrive config → Access-protected hostname → tunnel → Aurora. The read-write lane reaches the writer; the read-only lane reaches the reader.

Two independent distinctions run through the whole chain, and keeping them separate is what makes the naming predictable.

The access mode, read-only (ro) or read-write (rw), is enforced by MySQL grants and therefore lives on the MySQL user. It is the same concept in every environment, so its name does not carry the environment.

The endpoint, writer or reader, is a property of the physical database and therefore lives on the origin hostname. Only Aurora clusters expose a separate reader endpoint, so only production has two hostnames per database; the single-instance environments have one.

Everything else in the chain (secret, Hyperdrive config, binding) carries whichever segments it needs to stay unique.

Logical DBContents
consoleUser and Adventive Console system tables
aggregateAggregate analytics rollups
billingResidual Adventive-side billing data (Stripe billing transition); shares the production Aurora cluster with console

Development and staging are each a single Standard MySQL instance that hosts all three databases (console, aggregate, billing). Production is two Aurora MySQL clusters: the production cluster hosts both console and billing, and the aggregate cluster hosts aggregate. Each Aurora cluster exposes a writer (cluster) endpoint and a reader (cluster-ro) endpoint.

EnvZoneEngineDatabases and endpoints
devadventive.devStandard MySQL instanceconsole, aggregate, billing on development.coi6rcntfbgg.us-east-1.rds.amazonaws.com
stgadventivestg.comStandard MySQL instanceconsole, aggregate, billing on staging.coi6rcntfbgg.us-east-1.rds.amazonaws.com
prdadventive.comAurora MySQL clustersproduction cluster (console + billing), writer production.cluster-coi6rcntfbgg.us-east-1.rds.amazonaws.com · reader production.cluster-ro-coi6rcntfbgg.us-east-1.rds.amazonaws.com; aggregate cluster (aggregate), writer aggregate.cluster-coi6rcntfbgg.us-east-1.rds.amazonaws.com · reader aggregate.cluster-ro-coi6rcntfbgg.us-east-1.rds.amazonaws.com

Because console and billing share the production cluster, their production credentials connect to the same writer and reader endpoints, they are distinguished by the Hyperdrive config’s database field and the MySQL user, not by a different host.

Where each database lives, and which endpoint each mode reaches DEV / STAGING Single Standard MySQL instance one writer · no reader endpoint console aggregate billing ro and rw share one host; the reader endpoint appears only when a replica is added. PRODUCTION Two Aurora clusters, writer + reader each production cluster console billing writer ← rw reader ← ro production.cluster-... production.cluster-ro-... aggregate cluster aggregate writer ← rw reader ← ro aggregate.cluster-... aggregate.cluster-ro-...
Dev and staging put all three databases on one instance; production splits into two Aurora clusters, with console and billing sharing the production cluster.

The Aurora reader endpoint is the writer endpoint with cluster- replaced by cluster-ro-; it load-balances across the cluster’s replicas. Read-only traffic in production targets the reader endpoint so that read load stays off the writer.

An Aurora cluster publishes more than one hostname, and the difference is a failover-correctness issue, not a preference:

  • Cluster (writer) endpoint: <cluster>.cluster-<hash>.<region>.rds.amazonaws.com. Always resolves to the current writer and follows failover automatically. The read-write target.
  • Reader endpoint: <cluster>.cluster-ro-<hash>.<region>.rds.amazonaws.com. Load-balances across the cluster’s replicas and follows failover. The read-only target. In a single-instance cluster it resolves to the writer until a replica is added.
  • Instance endpoints: <instance-id>.<hash>.<region>.rds.amazonaws.com (no cluster in the name). Each points to one specific instance regardless of that instance’s current role, and does not move on failover. AWS documents these for diagnosis and tuning only.

The aggregate cluster, for example, publishes all of these; only the first two are valid Hyperdrive origins:

HostnameTypeHyperdrive origin?
aggregate.cluster-coi6rcntfbgg.us-east-1.rds.amazonaws.comcluster / writer endpointYes, rw
aggregate.cluster-ro-coi6rcntfbgg.us-east-1.rds.amazonaws.comreader endpointYes, ro
aggregate.coi6rcntfbgg.us-east-1.rds.amazonaws.cominstance endpointNo
aggregate-us-east-1a.coi6rcntfbgg.us-east-1.rds.amazonaws.cominstance endpointNo

The production cluster (hosting console and billing) publishes the same four shapes. Never point a Hyperdrive origin at an instance endpoint. An instance’s writer/reader role is current-state only: after a failover the instance behind …-us-east-1a… can become a replica and the instance behind the bare aggregate… name can become the writer. A config bound to an instance endpoint would then be writing to a read-only replica (errors) or sending reads to the writer (no offload), and would not recover when the roles move. The cluster and reader endpoints exist precisely to abstract this away, they always track the writer and the replica pool. In this standard the rw hostname maps to the cluster endpoint and the ro hostname to the reader endpoint, so the cloudflared ingress rule is the only place an Aurora endpoint is named, and it names the two failover-aware ones.

Four users per logical database, a read-only and a read-write user, env-agnostic. The same names exist on every host that carries that database, so one idempotent GRANT script runs identically on the dev instance, the staging instance, and the production Aurora clusters.

UserModeGrants (scoped to its own schema only)
hd_console_roread-onlySELECT on console.*
hd_console_rwread-writeSELECT, INSERT, UPDATE, DELETE, EXECUTE on console.*
hd_aggregate_roread-onlySELECT on aggregate.*
hd_aggregate_rwread-writeSELECT, INSERT, UPDATE, DELETE, EXECUTE on aggregate.*
hd_billing_roread-onlySELECT on billing.*
hd_billing_rwread-writeSELECT, INSERT, UPDATE, DELETE, EXECUTE on billing.*

Rules that make the users safe and portable:

  • Schema-scoped grants only. Each user is granted on its own database (console.*, aggregate.*, or billing.*), never *.*. This matters wherever one host carries multiple databases: the dev and staging instances hold all three, and the production cluster holds both console and billing, so hd_console_ro must not be able to read billing.
  • No DDL. Neither role may CREATE, ALTER, or DROP. Schema migrations run under a separate, deliberately elevated migration credential that is out of scope for this standard. The read-write role is for application DML, not schema change.
  • Host-scope to the tunnel. All connections arrive from cloudflared inside the VPC, so scope the user host to the tunnel’s private-subnet CIDR (for example 'hd_console_ro'@'10.0.%') rather than '...'@'%'. Use @'%' only where the source range cannot be pinned, and record that as a known gap.
  • Env-agnostic. The username never carries the environment. The environment is unambiguous from the hostname, the Hyperdrive config name, and the secret name; encoding it a fourth time on the user only multiplies names and breaks the single-GRANT-script property.

A password value is never standardized, only how it is generated, stored, and rotated.

  • One distinct password per (database, mode, environment). No password is reused across environments or across the read-only and read-write roles. For console, aggregate, and billing that is eighteen secrets in total.
  • Generated, never chosen. Generate with aws secretsmanager get-random-password --exclude-punctuation --require-each-included-type --password-length 32. Punctuation is excluded so the value survives every connection-string and URL-encoding path Hyperdrive and tooling put it through, with no escaping edge cases.
  • Never committed, never pasted. Password values do not appear in Git, in Terraform state as plaintext, in CI logs, in runbooks, or in this repository. They live only in AWS Secrets Manager and, encrypted, inside the Hyperdrive config.
  • Rotate at least every 90 days and on any personnel change. Rotation updates the value in two places: the Secrets Manager secret and the Hyperdrive config’s baked-in copy, plus ALTER USER on the database. The procedure is in Credential provisioning.

Every database credential’s system of record is AWS Secrets Manager, out-of-band from Cloudflare, consistent with the existing Adventive AWS keystore. Hyperdrive keeps its own encrypted copy for connection-time use; Secrets Manager is where the value is owned, versioned, audited, and rotated from.

Secret name: adventive-db-<db>-<mode>-<env>, lowercase and hyphenated, matching the adventive-<domain>-… convention already used for adventive-idp-recovery-*.

Secret value (JSON): the shape the infra/cloudflare-hyperdrive/ module already writes, unchanged.

{
"username": "hd_console_ro",
"password": "",
"host": "production.cluster-ro-coi6rcntfbgg.us-east-1.rds.amazonaws.com",
"port": 3306,
"database": "console"
}

The host field records the actual RDS/Aurora endpoint the credential is meant for, the writer endpoint for a rw secret, the reader endpoint for a production ro secret. Examples: adventive-db-console-ro-dev, adventive-db-aggregate-rw-prd, adventive-db-billing-ro-prd. For a production billing secret the host is the production cluster endpoint (shared with console).

This is distinct from Cloudflare Secrets Store, which remains the home for Worker runtime secrets such as the New Relic license key. Hyperdrive origin credentials are configuration on the Hyperdrive resource, not Worker-bound secrets, and are never set with wrangler secret put.

Hyperdrive connects to a public hostname that Cloudflare Access protects and cloudflared proxies to the private database endpoint. The hostname tracks the endpoint, not the access mode, because read-only and read-write connections to the same endpoint differ only by MySQL user.

Single-endpoint environments (dev, stg). One hostname per database; the ro and rw Hyperdrive configs both point at it and differ only by user.

  • db-console-dev.adventive.dev, db-aggregate-dev.adventive.dev, db-billing-dev.adventive.dev
  • db-console-stg.adventivestg.com, db-aggregate-stg.adventivestg.com, db-billing-stg.adventivestg.com

Multi-endpoint environment (prd). Two hostnames per database, one per Aurora endpoint, so read-only traffic reaches the replicas. billing gets its own hostnames even though they resolve to the same production-cluster endpoints as console, keeping the per-database naming uniform.

Hostnamecloudflared ingress target
db-console-rw-prd.adventive.comproduction.cluster-coi6rcntfbgg.us-east-1.rds.amazonaws.com:3306 (writer)
db-console-ro-prd.adventive.comproduction.cluster-ro-coi6rcntfbgg.us-east-1.rds.amazonaws.com:3306 (reader)
db-billing-rw-prd.adventive.comproduction.cluster-coi6rcntfbgg.us-east-1.rds.amazonaws.com:3306 (writer, shared with console)
db-billing-ro-prd.adventive.comproduction.cluster-ro-coi6rcntfbgg.us-east-1.rds.amazonaws.com:3306 (reader, shared with console)
db-aggregate-rw-prd.adventive.comaggregate.cluster-coi6rcntfbgg.us-east-1.rds.amazonaws.com:3306 (writer)
db-aggregate-ro-prd.adventive.comaggregate.cluster-ro-coi6rcntfbgg.us-east-1.rds.amazonaws.com:3306 (reader)

The existing dev hostnames (db-console-dev.adventive.dev, db-aggregate-dev.adventive.dev, db-billing-dev.adventive.dev) already match the single-endpoint pattern, so no dev hostname changes. If a read replica is later added in dev or staging, the read-only configs move to a new -ro hostname without any rename elsewhere.

Per-role connectors use the resource-type prefix adv-hd- (Hyperdrive) followed by <db>-<mode>-<env>. A Hyperdrive config is shared infrastructure bound by ID, so it is named for what it is — a Hyperdrive config for one database role — rather than for any one consuming Worker.

Config name: adv-hd-<db>-<mode>-<env>, eighteen configs for console, aggregate, and billing across three environments.

adv-hd-console-ro-dev adv-hd-console-ro-stg adv-hd-console-ro-prd
adv-hd-console-rw-dev adv-hd-console-rw-stg adv-hd-console-rw-prd
adv-hd-aggregate-ro-dev adv-hd-aggregate-ro-stg adv-hd-aggregate-ro-prd
adv-hd-aggregate-rw-dev adv-hd-aggregate-rw-stg adv-hd-aggregate-rw-prd
adv-hd-billing-ro-dev adv-hd-billing-ro-stg adv-hd-billing-ro-prd
adv-hd-billing-rw-dev adv-hd-billing-rw-stg adv-hd-billing-rw-prd

A Hyperdrive config is a shared resource: any Worker binds it by ID, so the adv-hd- prefix names the resource type, not an owning project. The three legacy single-user configs — adv-svc-public-api-console-dev, adv-svc-public-api-aggregate-dev, and adv-svc-public-api-billing-dev, each carrying a full-access DB user (conn-limit 60) — were superseded by the -ro/-rw pairs and have since been retired. The public API Worker now binds the read-only adv-hd-*-ro connectors. 02 covers the cutover.

Bindings are SCREAMING_SNAKE_CASE with no environment suffix, each [env.*] block in wrangler.toml points the same binding name at that environment’s Hyperdrive ID.

BindingBound to (per env)
DB_CONSOLE_ROadv-hd-console-ro-<env>
DB_CONSOLE_RWadv-hd-console-rw-<env>
DB_AGGREGATE_ROadv-hd-aggregate-ro-<env>
DB_AGGREGATE_RWadv-hd-aggregate-rw-<env>
DB_BILLING_ROadv-hd-billing-ro-<env>
DB_BILLING_RWadv-hd-billing-rw-<env>

A Worker binds only the modes it uses. A read-only service binds DB_CONSOLE_RO and nothing else, so the read-write credential is never even present in its runtime, a compromised read path cannot write. The public API Worker is read-path: its DB_CONSOLE / DB_AGGREGATE bindings now resolve to the read-only adv-hd-*-ro connectors, and adopt the explicit _RO binding names as they are renamed. A read-only service never holds a write credential at runtime.

One row per (database, mode, environment). Every name in a row is derivable from its first three columns.

DBModeEnvMySQL userSecretOrigin hostnameHyperdrive configBinding
consolerodevhd_console_roadventive-db-console-ro-devdb-console-dev.adventive.devadv-hd-console-ro-devDB_CONSOLE_RO
consolerwdevhd_console_rwadventive-db-console-rw-devdb-console-dev.adventive.devadv-hd-console-rw-devDB_CONSOLE_RW
consolerostghd_console_roadventive-db-console-ro-stgdb-console-stg.adventivestg.comadv-hd-console-ro-stgDB_CONSOLE_RO
consolerwstghd_console_rwadventive-db-console-rw-stgdb-console-stg.adventivestg.comadv-hd-console-rw-stgDB_CONSOLE_RW
consoleroprdhd_console_roadventive-db-console-ro-prddb-console-ro-prd.adventive.comadv-hd-console-ro-prdDB_CONSOLE_RO
consolerwprdhd_console_rwadventive-db-console-rw-prddb-console-rw-prd.adventive.comadv-hd-console-rw-prdDB_CONSOLE_RW
aggregaterodevhd_aggregate_roadventive-db-aggregate-ro-devdb-aggregate-dev.adventive.devadv-hd-aggregate-ro-devDB_AGGREGATE_RO
aggregaterwdevhd_aggregate_rwadventive-db-aggregate-rw-devdb-aggregate-dev.adventive.devadv-hd-aggregate-rw-devDB_AGGREGATE_RW
aggregaterostghd_aggregate_roadventive-db-aggregate-ro-stgdb-aggregate-stg.adventivestg.comadv-hd-aggregate-ro-stgDB_AGGREGATE_RO
aggregaterwstghd_aggregate_rwadventive-db-aggregate-rw-stgdb-aggregate-stg.adventivestg.comadv-hd-aggregate-rw-stgDB_AGGREGATE_RW
aggregateroprdhd_aggregate_roadventive-db-aggregate-ro-prddb-aggregate-ro-prd.adventive.comadv-hd-aggregate-ro-prdDB_AGGREGATE_RO
aggregaterwprdhd_aggregate_rwadventive-db-aggregate-rw-prddb-aggregate-rw-prd.adventive.comadv-hd-aggregate-rw-prdDB_AGGREGATE_RW
billingrodevhd_billing_roadventive-db-billing-ro-devdb-billing-dev.adventive.devadv-hd-billing-ro-devDB_BILLING_RO
billingrwdevhd_billing_rwadventive-db-billing-rw-devdb-billing-dev.adventive.devadv-hd-billing-rw-devDB_BILLING_RW
billingrostghd_billing_roadventive-db-billing-ro-stgdb-billing-stg.adventivestg.comadv-hd-billing-ro-stgDB_BILLING_RO
billingrwstghd_billing_rwadventive-db-billing-rw-stgdb-billing-stg.adventivestg.comadv-hd-billing-rw-stgDB_BILLING_RW
billingroprdhd_billing_roadventive-db-billing-ro-prddb-billing-ro-prd.adventive.comadv-hd-billing-ro-prdDB_BILLING_RO
billingrwprdhd_billing_rwadventive-db-billing-rw-prddb-billing-rw-prd.adventive.comadv-hd-billing-rw-prdDB_BILLING_RW

Because this is a Cloudflare design standard, it is measured against the six platform pillars.

PillarHow the standard addresses it
RedundancyProduction read-only traffic targets the Aurora reader endpoint, spreading reads across replicas and keeping the writer for writes.
ResiliencyRead-only and read-write are separate MySQL users bound separately; a compromised or buggy read path holds no write grant, so its blast radius is read-only.
Disaster recoveryEvery credential’s source of truth is AWS Secrets Manager, out-of-band from Cloudflare, so a Cloudflare-side incident does not lock the credentials away.
BackupSecrets Manager versions every credential; the previous version is retained across rotation for rollback.
DeploymentConfigs, secrets, and Access apps are provisioned by the infra/cloudflare-hyperdrive/ Terraform module and promoted dev → stg → prd; see 02.
ObservabilityOne config per (db, mode, env) means connection metrics and logs attribute cleanly to a single database, environment, and access mode.

See also: Credential provisioning · Workers naming conventions · AWS Secrets Manager