Databases / Access rules
Access rules and security groups
Each database's allow-list of the address ranges that may connect to it, from its own rules and from security groups you attach.
How access rules work
A database accepts connections only from the address ranges in its allow-list. Everything else is dropped before it reaches the engine. The list has two sources:
- the database's own access rules, and
- the ranges of any security groups you attach.
The database's effective_access_rules is the list as it is applied, each range with its source: access_rule, or security_group: and the group's id.
An access rule is:
- One CIDR per rule, IPv4 only, such as
10.0.1.0/24or10.0.1.12/32for one machine. - Nothing wider than a
/8.0.0.0.0/0is always refused: a database is never open to everyone, even on a private network. - At most 50 rules on a database.
- TCP to the engine's port only. A rule cannot open any other port.
Rules are enforced in more than one place: in the network (the subnet's network ACL in af-abj-2, a security group of the database's own in af-abj-1), on the database machine's own firewall, and in the engine's own access configuration.
The default
| Zone | A new database starts with |
|---|---|
af-abj-2 (VPC) | One rule: your VPC's whole range, so every machine in the VPC can connect |
af-abj-1 | No rules: nothing can connect until you add one, usually a VPS's private_network_ip as a /32 (see connecting from a standard VPS) |
Set your own starting list with access_rules when you create the database, or [] for none.
Change the rules
In the console, the database's Access rules card lists the ranges. Add one (IPv4, /8 or narrower; one server is its address with /32), remove one, then press Save access rules.
With the API, rules are replaced as a whole: send the complete new list.
$ curl -X PUT https://api.pantechdynamics.com/public/v1/databases/db_…/access-rules \ -H "Authorization: Bearer $PANTECH_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"rules": [{"cidr": "10.0.1.0/24"}, {"cidr": "10.0.2.15/32"}]}'The change is asynchronous: follow the returned operation until it is succeeded. The database's observed_generation catches up with its generation once the new rules are in force.
{"rules": []} removes every rule, which closes the database to everyone, except ranges its security groups still add.
With the CLI, access-rules set takes the whole list of CIDRs, or --none. add and remove change some ranges and keep the rest:
$ pantech db access-rules set orders-db 10.0.1.0/24 10.0.2.15/32$ pantech db access-rules add orders-db 10.250.4.23/32$ pantech db access-rules remove orders-db 10.0.2.15/32With Terraform, access_rules on pantechdynamics_database is the whole list.
Choosing ranges
- Narrowest that works. A subnet's range for an application tier, or a
/32for each machine that should connect. - In a VPC, keep databases in a subnet of their own. A network ACL rule applies to the whole subnet, so the database's rules also open its port on every other machine in that subnet. See connecting.
Attach security groups
If you already keep your trusted ranges in security groups, attach them to the database instead of copying the ranges into its rules. When you change a group's rules, every database it is attached to follows automatically.
$ curl -X PUT https://api.pantechdynamics.com/public/v1/databases/db_…/security-groups \ -H "Authorization: Bearer $PANTECH_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"security_group_ids": ["sg_…"]}'The list replaces the attached groups as a whole; [] detaches them all. At most 5 groups, each one of your own, in the database's zone.
A group is only a source of address ranges here. It is never put on the database's machine, so it cannot open SSH or any other port. From each attached group, only the ingress rules that could admit a client to the engine count:
- protocol
tcporall, - ports that include the engine's port (
5432or3306): a single port, a range such as3000-4000, or all ports, - an IPv4 CIDR of
/8or narrower.
Every other rule is left out, and listed in the database's ignored_security_group_rules with the reason:
reason | The rule |
|---|---|
egress_rule | Is outbound |
protocol_not_tcp | Is udp or icmp |
port_not_covered | Does not include the engine's port, like a rule for SSH on 22 |
cidr_too_wide | Is 0.0.0.0/0 or wider than a /8 |
cidr_not_ipv4 | Is not IPv4 |
So a typical web tier's group, allowing 443 from everywhere and 22 from your office, adds nothing to a database: neither rule covers the database's port. For a group to admit a range to the database, it needs an ingress rule for the database's port from that range. The range is matched against the address a client connects from, which is its private address on the database's network.
The database's own rules plus the ranges its groups add may come to at most 1,024. A change to a group that would take an attached database past that is refused. A group cannot be deleted while a database uses it (409 SECURITY_GROUP_ATTACHED_TO_DATABASE): detach it first.
A worked example
A database db_… in af-abj-1 has one access rule of its own, 10.250.4.23/32, and you attach a group sg_app with these inbound rules:
| Rule | Counts for the database? |
|---|---|
tcp 5432 from 10.250.7.0/24 | Yes: TCP, covers 5432, a /24 |
tcp 22 from 203.0.113.0/24 | No: port_not_covered |
icmp from 10.250.0.0/20 | No: protocol_not_tcp |
tcp 5432 from 0.0.0.0/0 | No: cidr_too_wide |
all from 10.250.9.8/32 | Yes: all protocols and ports include TCP 5432 |
$ curl -X PUT https://api.pantechdynamics.com/public/v1/databases/db_…/security-groups \ -H "Authorization: Bearer $PANTECH_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"security_group_ids": ["sg_app"]}'Once the operation has succeeded, the database reads:
{
"security_group_ids": ["sg_app"],
"effective_access_rules": [
{ "cidr": "10.250.4.23/32", "protocol": "tcp", "port": 5432, "source": "access_rule" },
{ "cidr": "10.250.7.0/24", "protocol": "tcp", "port": 5432, "source": "security_group:sg_app" },
{ "cidr": "10.250.9.8/32", "protocol": "tcp", "port": 5432, "source": "security_group:sg_app" }
],
"ignored_security_group_rules": [
{ "security_group_id": "sg_app", "direction": "ingress", "protocol": "tcp", "port_range": "22", "cidr": "203.0.113.0/24", "reason": "port_not_covered" },
{ "security_group_id": "sg_app", "direction": "ingress", "protocol": "icmp", "port_range": "", "cidr": "10.250.0.0/20", "reason": "protocol_not_tcp" },
{ "security_group_id": "sg_app", "direction": "ingress", "protocol": "tcp", "port_range": "5432", "cidr": "0.0.0.0/0", "reason": "cidr_too_wide" }
]
}A range listed both in the database's rules and in a group appears once, under its first source: the database's own rules first, then the groups in the order you attached them.
effective_access_rules is what the database applies once observed_generation equals generation. When you later change sg_app's rules, the database follows on its own: no call to the database is needed.
With the CLI:
$ pantech db security-groups set orders-db sg_app$ pantech db security-groups set orders-db --noneWhen something is refused
code | Status | What to do |
|---|---|---|
INVALID_DATABASE_SECURITY_GROUPS | 422 | At most 5 groups, each once |
DATABASE_SECURITY_GROUP_NOT_FOUND | 422 | Only your own groups can be attached |
DATABASE_SECURITY_GROUP_WRONG_ZONE | 422 | Attach groups from the database's zone |
DATABASE_SECURITY_GROUP_NOT_USABLE | 422 | The group is being deleted or has failed |
DATABASE_ACCESS_RANGE_LIMIT_EXCEEDED | 422 | More than 1,024 ranges in all; remove some |
SECURITY_GROUP_ATTACHED_TO_DATABASE | 409 | On deleting a group: detach it from the database named in detail first |
All the database codes are on the errors page.