Documentation

esc
    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 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/24 or 10.0.1.12/32 for one machine.
    • Nothing wider than a /8. 0.0.0.0/0 is 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

    ZoneA 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-1No 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.

    Terminal
    $ 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:

    Terminal
    $ 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/32

    With 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 /32 for 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.

    Terminal
    $ 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 tcp or all,
    • ports that include the engine's port (5432 or 3306): a single port, a range such as 3000-4000, or all ports,
    • an IPv4 CIDR of /8 or narrower.

    Every other rule is left out, and listed in the database's ignored_security_group_rules with the reason:

    reasonThe rule
    egress_ruleIs outbound
    protocol_not_tcpIs udp or icmp
    port_not_coveredDoes not include the engine's port, like a rule for SSH on 22
    cidr_too_wideIs 0.0.0.0/0 or wider than a /8
    cidr_not_ipv4Is 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:

    RuleCounts for the database?
    tcp 5432 from 10.250.7.0/24Yes: TCP, covers 5432, a /24
    tcp 22 from 203.0.113.0/24No: port_not_covered
    icmp from 10.250.0.0/20No: protocol_not_tcp
    tcp 5432 from 0.0.0.0/0No: cidr_too_wide
    all from 10.250.9.8/32Yes: all protocols and ports include TCP 5432
    Terminal
    $ 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:

    JSON
    {
      "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:

    Terminal
    $ pantech db security-groups set orders-db sg_app$ pantech db security-groups set orders-db --none

    When something is refused

    codeStatusWhat to do
    INVALID_DATABASE_SECURITY_GROUPS422At most 5 groups, each once
    DATABASE_SECURITY_GROUP_NOT_FOUND422Only your own groups can be attached
    DATABASE_SECURITY_GROUP_WRONG_ZONE422Attach groups from the database's zone
    DATABASE_SECURITY_GROUP_NOT_USABLE422The group is being deleted or has failed
    DATABASE_ACCESS_RANGE_LIMIT_EXCEEDED422More than 1,024 ranges in all; remove some
    SECURITY_GROUP_ATTACHED_TO_DATABASE409On deleting a group: detach it from the database named in detail first

    All the database codes are on the errors page.

    Was this page helpful?

    Updated