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
| Mode | Port 6432 (runtime) | Port 5432 (direct) | Requires allowlist | Confirmation |
|---|---|---|---|---|
restricted | Blocked | Blocked | Yes | No |
public_runtime | Open | Blocked | Direct only | No |
public_all | Open | Open | No | Owner + 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
| Field | Type | Description |
|---|---|---|
label | string | Human-readable name. Shown in audit logs and the dashboard. |
cidr | string | Valid CIDR notation (e.g., 10.0.0.0/8, 192.168.1.0/24). Single IPs use /32. |
ports | runtime | direct | both | Which port(s) this rule opens. runtime = 6432, direct = 5432, both = both. |
scope | project | branch | project applies to all branches. branch applies only to the specified branch. |
expires_at | ISO 8601 | Optional. 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-projectID 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-01How 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 tcpPropagation 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.
| Endpoint | TLS | sslmode |
|---|---|---|
pooler.axiom.cloud:6432 | Required | require |
direct.axiom.cloud:5432 | Required | require |
| Internal (private networking) | Optional | prefer |
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_7pQ4nR8wGrace 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:
| Mode | CIDR rule exists | Port 6432 access | Port 5432 access |
|---|---|---|---|
restricted | Yes | Allowed | Allowed |
restricted | No | Blocked | Blocked |
public_runtime | Yes | Allowed (anyone) | Allowed |
public_runtime | No | Allowed (anyone) | Blocked |
public_all | Yes | Allowed (anyone) | Allowed (anyone) |
public_all | No | Allowed (anyone) | Allowed (anyone) |
Best Practices
- Start restricted. Only move to public modes when your architecture genuinely requires it.
- Use labels. Descriptive labels make audit logs and rule lists scannable.
- Set expiry on temporary rules. CI runners, preview deploys, and contractor access should all have expiry.
- Prefer project scope for infrastructure. VPNs, CI systems, and monitoring tools typically need access to all branches.
- Monitor audit logs. Set up alerts for
network.policy.changedevents. - 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 refusedCause: 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 bothConnection 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_2kF9x3mZSSL error
FATAL: no pg_hba.conf entry for host "198.51.100.42", user "axiom_pooler", database "mydb", SSL offCause: Client is not using TLS.
Fix: Add sslmode=require to your connection string.