Skip to content

Operations & security

fdyno is the data plane only. It does not terminate TLS, implement IAM, or run a management console. Run it inside a trusted boundary and configure it through environment variables. It exposes health, readiness, and metrics endpoints for orchestration, and can run opt-in background maintenance workers.

Configuration

Variable Default Purpose
DYNODB_LISTEN_ADDR :8000 Data-plane listen address.
FDB_CLUSTER_FILE FoundationDB default Path to the cluster file.
DYNODB_CREDENTIALS dev defaults SigV4 keyId:secret pairs (comma-separated). When set, these replace the built-in dev credentials.
DYNODB_PPROF_ADDR unset (disabled) Private address for pprof, if needed.
DYNODB_ACCESS_LOG unset (disabled) When set, log one line per request (method, action, status, duration).
DYNODB_READ_HEADER_TIMEOUT 10s Slow-header (Slowloris) defense.
DYNODB_READ_TIMEOUT 60s Maximum time to read a request.
DYNODB_WRITE_TIMEOUT 120s Maximum time to write a response.
DYNODB_IDLE_TIMEOUT 120s Keep-alive idle timeout.

Health checks and readiness

fdyno separates liveness from readiness so an orchestrator can tell "the process is up" apart from "the process can serve traffic".

Endpoint Checks FoundationDB Use for
GET /, /healthz, /livez No Liveness probes. Returns 200 whenever the process is running; never touches FoundationDB.
GET /readyz, /health/ready Yes Readiness probes / load-balancer health. Performs a lightweight FoundationDB round-trip (reads the cluster read version within a short timeout) and returns 200 when reachable, 503 when not.

Keeping liveness static is deliberate: a transient FoundationDB blip takes an instance out of the load-balancer pool (via /readyz) instead of restarting the process. Point liveness probes at /livez and readiness probes at /readyz.

Observability

  • GET /metrics returns a JSON document: process uptime, requests_total, errors_total, and per-action request counts and average latencies. When background workers are enabled it also reports, per worker, whether this instance holds the worker lease, how many times it has run, how many items it has processed, and how long since its last run. Counters are process-local and reset on restart.
  • Access log (DYNODB_ACCESS_LOG) emits one structured line per request for debugging and audit, complementing the aggregate /metrics counters.
  • pprof is served only when DYNODB_PPROF_ADDR is set, on a separate listener (see Hardening).

Background maintenance workers

These workers are opt-in — each is disabled unless its interval variable is set — and are safe to run across many instances. Each takes a lease stored in FoundationDB, so with multiple instances exactly one runs a given worker at a time (no redundant full-table scans), and each persists its scan cursor in FoundationDB so a restart resumes rather than rescanning from the start. Their transactions run at FoundationDB's batch priority, so under contention they defer to foreground client requests and never steal read/write throughput from the data plane.

Variable Worker Purpose
DYNODB_TTL_SWEEP_INTERVAL TTL sweeper Reclaims storage for expired items that are never read again. Read paths already hide and lazily delete expired items on access, so this only affects items that are never touched. DYNODB_TTL_SWEEP_MAX_SCAN bounds items scanned per pass.
DYNODB_CDC_TRIM_INTERVAL Change-stream trimmer Trims change-stream (CDC) records older than DYNODB_CDC_RETENTION (default 24h). DYNODB_CDC_TRIM_MAX_SCAN bounds items scanned per pass.
DYNODB_TXN_TOKEN_GC_INTERVAL Idempotency-token GC Reclaims expired TransactWriteItems idempotency tokens. DYNODB_TXN_TOKEN_GC_MAX_SCAN bounds items scanned per pass.

Authentication

fdyno verifies AWS SigV4 signatures on every request against a map from access key ID to secret.

The built-in credentials are not secret

The default local, alternator, and cassandra credentials exist for development and conformance testing. Any deployment that keeps them is effectively unauthenticated. Set your own, which replaces the defaults:

DYNODB_CREDENTIALS="AKIDEXAMPLE:your-secret,AKIDOTHER:another-secret"

Serving on a non-loopback address without DYNODB_CREDENTIALS set logs a startup warning, because the well-known dev keys would otherwise remain valid.

fdyno does not implement authorization: there are no IAM policies and no resource-policy enforcement. Any caller with a valid signature can access any table. Treat the network boundary as your authorization boundary.

Hardening

  • pprof is disabled by default. It is served only when DYNODB_PPROF_ADDR is set, on a separate listener and mux. Bind it to a private address such as 127.0.0.1:6060 and never expose it publicly.
  • HTTP timeouts are set by default to bound connection lifetime and defend against slow-client attacks; all are tunable via the variables above.
  • Request size is capped at 16 MB (DynamoDB's maximum request size), including after decompression; larger requests are rejected with 413 before the body is buffered, so a malformed or compressed-bomb payload cannot exhaust memory.
  • TLS is not terminated by fdyno; run it behind a reverse proxy or load balancer that terminates TLS.
  • CORS: fdyno mirrors DynamoDB and returns Access-Control-Allow-Origin: * for requests carrying an Origin header. It never sets Access-Control-Allow-Credentials, and every request still requires a valid SigV4 signature, so this alone does not grant cross-origin access to data.

Deployment shape

flowchart LR
    C["Clients"] --> LB["TLS terminator<br/>(reverse proxy / LB)"]
    LB --> F1["fdyno"]
    LB --> F2["fdyno"]
    LB --> F3["fdyno"]
    F1 --> FDB[("FoundationDB cluster")]
    F2 --> FDB
    F3 --> FDB

Because fdyno holds no durable state, you can run as many instances as you like behind a load balancer; they all share one consistent view through FoundationDB. Scale the FoundationDB cluster for storage and throughput. Background workers stay correct at any instance count because they coordinate through FoundationDB leases.

Capacity and limits

fdyno reproduces DynamoDB's API, not its provisioning model. Operators should understand where the two intentionally differ:

  • No request throttling. fdyno does not impose request-unit or throughput caps and never raises ProvisionedThroughputExceededException or ThrottlingException. It scales with the FoundationDB cluster; backpressure surfaces only if FoundationDB itself is overloaded.
  • At-rest encryption is a property of the FoundationDB cluster. Configure encryption there (FoundationDB 7.x supports native encryption); fdyno does not add an encryption layer of its own.
  • Transaction limits. A single write is bounded by FoundationDB's per-transaction limits (10 MB, 5 s). A BatchWriteItem/TransactWriteItems whose items plus index and stream entries exceed those limits is rejected with a ValidationException so the client can split the request.

Durability

All durable state lives in FoundationDB, so operational durability is FoundationDB's durability. A fdyno process can be restarted or replaced at any time without data loss. TTL configuration also survives a restart, so item expiry continues correctly. For point-in-time and on-demand backups see Backup & restore. See also Transactions & consistency.

Throughput and latency

The numbers below come from cmd/perfbench against a single fdyno process backed by a single-node FoundationDB cluster using the in-memory storage engine, on an Apple M3 Max (14 cores), over loopback. Items are about 200 bytes with a composite key. These are local single-node figures that show the relative cost of each operation; a multi-node FoundationDB cluster on SSD storage behaves differently.

Eight concurrent clients:

Operation Throughput p50 p99
GetItem 4,659 ops/s 1.7 ms 2.3 ms
Query (10 items) 3,415 ops/s 2.3 ms 3.0 ms
UpdateItem 925 ops/s 8.0 ms 16 ms
PutItem 916 ops/s 8.0 ms 16 ms

A read is served by a single FoundationDB read. Write latency is dominated by FoundationDB's commit, which is why PutItem and UpdateItem sit near 8 ms at p50 on this setup.

Reporting security issues

Please report vulnerabilities privately through the repository's GitHub Security advisories rather than a public issue.