Groups and access rules
Control access without a policy file: put machines and users into groups, write allow-only access rules between them, and check the access graph.
Slopscale can enforce access without a policy file. Machines and users go into named groups, and access rules say which groups may reach which on what protocol and ports. The admin console edits both under Access controls, and the same operations are on the API and the CLI. The model follows NetBird’s groups and policies: allow rules only, no ordering, and a tailnet that turns default-deny as soon as one rule is enabled.
Groups
A group is a named set of machines. A machine belongs to it in one of two ways:
- directly, when an operator adds the machine to the group, and
- through its owner, when the operator adds the user to the group. Every machine the user owns is then a member, including machines the user registers later.
Tagged machines have no owner, so they join groups directly. A machine can be
in any number of groups. Two builtin groups cannot be renamed, edited or
deleted: All holds every machine and lists no members, and Own machines
is a rule destination only. It is Tailscale’s autogroup:self: in a rule it
means the machines owned by the same user as the source, so it has no
members of its own, cannot be a source, cannot be in a bidirectional rule
and cannot be given to a network, a DNS rule or a pre-auth key. Tagged
machines have no user and are never reached through it.
Groups can also come from the identity provider: with oidc.groups.sync
on, a user’s groups claim is mirrored into groups of the same name at every
sign-in, and those groups show Synced in the console. Their users follow
the claim and cannot be edited by hand; see OIDC.
Pre-auth keys carry groups too. A key created with groupIds enrols every
machine it registers into those groups, the way a NetBird setup key does with
its auto-groups. A group that has been deleted since is skipped.
Deleting a user or a machine drops its memberships. A group an access rule names cannot be deleted; take it out of the rule first.
Access rules
A rule has a name, a description, an enabled switch, a protocol (all,
tcp, udp or icmp), ports for tcp and udp (22,80,8000-8100, empty
for every port), source groups and destination groups. It lets the members of
the source groups open connections to the members of the destination groups.
The destination cannot open connections back unless the rule is
bidirectional, which allows both directions.
Rules only allow. While no rule is enabled and the policy file has no acls or grants, every machine sees every other. The first enabled rule makes everything not allowed by a rule (or by the policy file) unreachable, so create the rules a tailnet needs before turning them on, or start with one rule from All to All and narrow it down. The console asks before the last enabled rule is disabled or deleted when that would open the tailnet.
A new server does not start open. The first time it runs it seeds one builtin rule, Own machines, from All to Own machines on every protocol: each machine reaches the other machines of its own user and nothing else, and machines of different users do not see each other. A builtin rule has only its enabled switch: it cannot be renamed, narrowed or deleted. Switch it off to open the tailnet, or add rules next to it. On a database that already has machines when it is upgraded the rule is seeded switched off, so an open tailnet stays open until an operator turns it on.
Rules and the policy file combine: the rules compile into grants that sit next
to the file’s own, and a connection is allowed when either admits it. The
file’s tests run against the combined result. Capability grants have no
equivalent among the rules and are written in the policy file; the grant that
allows peer relays is one.
Temporary access
A rule and a membership can carry an expiry, and a group can be marked requestable so users ask to join it for a while and an approver decides. See Temporary access.
Structuring groups
Groups work best when each one answers one question. Groups of users describe
who: engineering, support, contractors. Groups of machines describe what:
production-servers, office-printers, ci-runners. A rule then reads as a
sentence, “engineering may reach production-servers on tcp 22 and 443”, and
a new engineer or a new server needs a group change, not a rule change.
API and CLI
Groups live at /api/v1/group and rules at /api/v1/access-rule; both need
the policy_file scope (policy_file:read for listing). A group is created
with POST /api/v1/group and {"name": "Engineering", "userIds": ["3"]},
changed with PATCH /api/v1/group/{id}, which replaces the members it names
and keeps the ones it omits, and deleted with DELETE. Single members are
added with POST /api/v1/group/{id}/member and {"nodeId": "7"} or
{"userId": "3"}, and removed with DELETE /api/v1/group/{id}/node/{nodeId}
or DELETE /api/v1/group/{id}/user/{userId}.
A rule is created with POST /api/v1/access-rule:
{
"name": "SSH to servers",
"protocol": "tcp",
"ports": "22",
"sourceGroupIds": ["2"],
"destinationGroupIds": ["3"]
}
PUT /api/v1/access-rule/{id} replaces every field,
PATCH /api/v1/access-rule/{id} with {"enabled": false} flips only the
switch (the rest of the rule is read on the server, so a stale copy cannot
overwrite someone else’s edit), and DELETE removes the rule. The list
carries policyFileEnforces, which is false when no policy file restricts
traffic: then the rules are all that keeps the tailnet from allow-all, and
disabling the last one opens it. Every change is audited as group.* or
access_rule.* and reaches connected clients at once.
The CLI mirrors the API:
$ slopscale groups create --name Engineering
$ slopscale groups add-user --identifier 2 --user 3
$ slopscale groups add-node --identifier 3 --node 7
$ slopscale access-rules create --name "SSH to servers" --src 2 --dst 3 --protocol tcp --ports 22
$ slopscale access-rules disable --identifier 1
Access graph
slopscale nodes access-graph --node <id>, GET /api/v1/access-graph?node=
(requiring policy_file:read) and the console’s Access controls › Graph page
show, for a machine, which peers it can reach and which can reach it, with the
ports, routes and SSH logins:
$ slopscale nodes access-graph --node 7
The access graph is computed from the compiled policy exactly as the clients receive it, showing effective connectivity across the tailnet.