Security

Network Policy

Control network access to your AxiomDB Postgres instances with CIDR allowlists, port-level rules, and progressive security modes.

Network Policy

AxiomDB enforces a defense-in-depth network model. Every Postgres instance ships behind a managed firewall (UFW), a connection pooler (PgBouncer), and PostgreSQL's own pg_hba.conf. Network rules you define in the dashboard or API are propagated to all three layers atomically.


Security Modes

Every project starts in restricted mode. You can escalate to public access when your architecture requires it, but each escalation carries explicit confirmation and audit trails.

Restricted (default)

All connections require an allowlisted CIDR rule. No public ports are exposed. This is the recommended mode for production workloads.

Public Runtime

Port 6432 (PgBouncer) is opened to the internet. Port 5432 (direct Postgres) remains restricted to allowlisted IPs only.

Public All

Both port 6432 and 5432 are open to the internet. Requires owner role, typed confirmation, and an active audit event before activation.

Mode comparison

ModePort 6432 (runtime)Port 5432 (direct)Requires allowlistConfirmation
restrictedBlockedBlockedYesNo
public_runtimeOpenBlockedDirect onlyNo
public_allOpenOpenNoOwner + typed confirmation

Public All requires explicit confirmation

Switching to public_all requires the owner to type the project name verbatim. This action is logged as network.policy.changed with the actor's identity, timestamp, and previous mode.


CIDR Rules

A CIDR rule defines which IP ranges may connect to your instance. Each rule carries metadata that controls its scope, port access, and lifetime.

Rule schema

{
  "id": "rule_2kF9x3mZ",
  "label": "Office VPN",
  "cidr": "203.0.113.0/24",
  "ports": "both",
  "scope": "project",
  "expires_at": "2026-06-01T00:00:00Z",
  "created_at": "2025-01-15T10:30:00Z",
  "created_by": "usr_8xK2mP"
}

Field reference

FieldTypeDescription
labelstringHuman-readable name. Shown in audit logs and the dashboard.
cidrstringValid CIDR notation (e.g., 10.0.0.0/8, 192.168.1.0/24). Single IPs use /32.
portsruntime | direct | bothWhich port(s) this rule opens. runtime = 6432, direct = 5432, both = both.
scopeproject | branchproject applies to all branches. branch applies only to the specified branch.
expires_atISO 8601Optional. Rule is automatically removed after this time. Null means no expiry.

Creating a rule via CLI

axiom network rule create \
  --project my-project \
  --label "CI Runner" \
  --cidr "198.51.100.0/24" \
  --ports both \
  --scope project \
  --expires "72h"

Creating a rule via API

curl -X POST "https://api.axiom.cloud/v1/projects/prj_abc123/network/rules" \
  -H "Authorization: Bearer ptk_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "label": "Staging server",
    "cidr": "192.0.2.0/24",
    "ports": "runtime",
    "scope": "branch",
    "branch_id": "br_def456",
    "expires_at": "2026-03-01T00:00:00Z"
  }'

Listing active rules

axiom network rule list --project my-project
ID            LABEL              CIDR               PORTS   SCOPE    EXPIRES
rule_2kF9x3mZ Office VPN         203.0.113.0/24     both    project  2026-06-01
rule_7pQ4nR8w CI Runner          198.51.100.0/24    both    project  2025-01-22
rule_aB3xK9mL Staging server     192.0.2.0/24       runtime branch   2026-03-01

How Rules Are Applied

When you create, update, or delete a network rule, AxiomDB orchestrates a multi-layer update:

┌─────────────────────────────────────────────────────────┐
│                    AxiomDB Control Plane                 │
│                                                         │
│  1. Validate CIDR syntax                                │
│  2. Check role permission (admin+ for project scope)    │
│  3. Write rule to metadata store                        │
│  4. Emit audit event                                    │
│                                                         │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────┐ │
│  │  UFW Rules   │  │ pg_hba.conf │  │ PgBouncer.ini   │ │
│  │  (iptables)  │  │ (managed    │  │ (managed        │ │
│  │              │  │  block)     │  │  block)         │ │
│  └──────┬──────┘  └──────┬──────┘  └───────┬─────────┘ │
│         │                │                  │           │
│         ▼                ▼                  ▼           │
│  ┌─────────────────────────────────────────────────┐    │
│  │           PostgreSQL Instance                    │    │
│  │  • UFW: port-level allow/deny                   │    │
│  │  • pg_hba.conf: hostssl rules with client cert  │    │
│  │  • PgBouncer: connection-level filtering        │    │
│  └─────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────┘

pg_hba.conf managed block

AxiomDB owns a clearly delimited section of pg_hba.conf. Never edit this block manually — your changes will be overwritten on the next rule update.

-- === AXIOMDB MANAGED BLOCK — DO NOT EDIT ===
hostssl mydb axiom_pooler 203.0.113.0/24 scram-sha-256
hostssl mydb axiom_pooler 198.51.100.0/24 scram-sha-256
hostssl mydb axiom_direct 203.0.113.0/24 scram-sha-256
-- === END AXIOMDB MANAGED BLOCK ===

UFW rules

# Managed by AxiomDB — do not edit manually
ufw allow from 203.0.113.0/24 to any port 6432 proto tcp
ufw allow from 203.0.113.0/24 to any port 5432 proto tcp
ufw allow from 198.51.100.0/24 to any port 6432 proto tcp
ufw allow from 198.51.100.0/24 to any port 5432 proto tcp

Propagation latency

Rule changes typically propagate within 5–15 seconds. During propagation, both the old and new rule sets are active to avoid dropping existing connections.


TLS Enforcement

Every public-facing connection requires TLS. AxiomDB sets sslmode=require on all pooler and direct endpoints. Self-signed certificates are rotated automatically every 90 days.

EndpointTLSsslmode
pooler.axiom.cloud:6432Requiredrequire
direct.axiom.cloud:5432Requiredrequire
Internal (private networking)Optionalprefer

To use certificate verification with your client:

psql "host=direct.axiom.cloud port=5432 dbname=mydb sslmode=verify-full sslrootcert=/path/to/ca.pem"

Scope: Project vs Branch

Project-scoped rules apply to every branch in the project — main, preview branches, and any future branches. Use these for infrastructure that needs access to all environments.

Branch-scoped rules apply only to a single branch. Use these for preview deployments or staging environments that should not share network access with production.

# Project-wide rule: CI runners can reach all branches
axiom network rule create \
  --project my-project \
  --label "CI" \
  --cidr "198.51.100.0/24" \
  --scope project

# Branch-specific rule: preview deploy only
axiom network rule create \
  --project my-project \
  --branch preview/pr-42 \
  --label "PR #42 deploy" \
  --cidr "192.0.2.50/32" \
  --scope branch \
  --expires "168h"

Expiry and Cleanup

Rules with expires_at are automatically removed when their expiry passes. The removal triggers a network.rule.deleted audit event with reason: "expired".

You can also manually delete a rule at any time:

axiom network rule delete --project my-project --rule rule_7pQ4nR8w

Grace period

Expired rules enter a 5-minute grace period during which existing connections are maintained but no new connections are accepted. After the grace period, active connections are terminated.


Combining Rules with Security Modes

The effective access control is the intersection of the security mode and your CIDR rules:

ModeCIDR rule existsPort 6432 accessPort 5432 access
restrictedYesAllowedAllowed
restrictedNoBlockedBlocked
public_runtimeYesAllowed (anyone)Allowed
public_runtimeNoAllowed (anyone)Blocked
public_allYesAllowed (anyone)Allowed (anyone)
public_allNoAllowed (anyone)Allowed (anyone)

Best Practices

  1. Start restricted. Only move to public modes when your architecture genuinely requires it.
  2. Use labels. Descriptive labels make audit logs and rule lists scannable.
  3. Set expiry on temporary rules. CI runners, preview deploys, and contractor access should all have expiry.
  4. Prefer project scope for infrastructure. VPNs, CI systems, and monitoring tools typically need access to all branches.
  5. Monitor audit logs. Set up alerts for network.policy.changed events.
  6. Rotate CIDRs. If your cloud provider changes IP ranges, update rules promptly and remove stale entries.

Troubleshooting

Connection refused

psql: connection to server at "direct.axiom.cloud" (203.0.113.1), port 5432 failed:
Connection refused

Cause: No CIDR rule covers your current IP, or the security mode blocks the port.

Fix: Check your public IP and add a rule:

curl -s https://api.axiom.cloud/v1/network/my-ip
# {"ip": "198.51.100.42"}

axiom network rule create \
  --project my-project \
  --label "My machine" \
  --cidr "198.51.100.42/32" \
  --ports both

Connection timed out

Cause: Firewall rule has not propagated yet, or the rule has expired.

Fix: Wait 15 seconds, then verify the rule is active:

axiom network rule get --project my-project --rule rule_2kF9x3mZ

SSL error

FATAL: no pg_hba.conf entry for host "198.51.100.42", user "axiom_pooler", database "mydb", SSL off

Cause: Client is not using TLS.

Fix: Add sslmode=require to your connection string.


On this page