server/cloud/mobile/iot tags, funnel scoped to servers+cloud, mobile limited to HA/Mattermost/Syncthing/DSM, pre-allowed agent+metrics flows, policy tests included.
131 lines
5.0 KiB
Plaintext
131 lines
5.0 KiB
Plaintext
// PROPOSED tailnet policy — Phase 2 of docs/security-plan.md. DRAFT for
|
|
// Kyle's review, 2026-11-01. NOT LIVE. Baseline it replaces:
|
|
// docs/tailscale-acl.hujson.
|
|
//
|
|
// Design: single-user tailnet. Kyle's interactive machines stay UNTAGGED
|
|
// (they speak as isomk@ → full access via autogroup:members). Tags exist to
|
|
// constrain the devices that are NOT him-at-a-keyboard: phones/TV, IoT, and
|
|
// the server fleet. Tagging a device removes its user identity, which is
|
|
// exactly the point.
|
|
//
|
|
// Tag assignments (apply on the Machines page before saving this policy):
|
|
// tag:server (home) : rift, orion, dixie, butler, sk, talos
|
|
// tag:cloud (public-facing remote): phobos, deimos (Hetzner colo, web),
|
|
// fs (devlogs/primers, remote dev), svc
|
|
// tag:mobile : iphone-15-pro, ipad-pro-11-gen-3, pixel-8a, apple-tv
|
|
// tag:iot : homeassistant, synology
|
|
// UNtagged (full access, by design): straylight, titan, callisto, io,
|
|
// wntrmute (agent host).
|
|
//
|
|
// Known flows pre-allowed (expect a first-week breakage pass anyway):
|
|
// - agents on tagged servers → Mattermost on straylight (serve 443)
|
|
// - orion VictoriaMetrics → node exporters (*:9100, *:8420)
|
|
// - server agents → wntrmute Hermes peer API (:8642)
|
|
// - Syncthing mesh on :22000 for every device incl. tagged
|
|
//
|
|
// Unresolved: fs also ADVERTISES exit node — deliberate? (dst
|
|
// autogroup:internet below covers use; drop the advertisement if unwanted.)
|
|
|
|
{
|
|
"tagOwners": {
|
|
"tag:server": ["autogroup:admin"],
|
|
"tag:cloud": ["autogroup:admin"],
|
|
"tag:mobile": ["autogroup:admin"],
|
|
"tag:iot": ["autogroup:admin"],
|
|
},
|
|
|
|
"acls": [
|
|
// Kyle's own (untagged) devices: full access. NOTE: autogroup:members
|
|
// = every tailnet member; safe only while this stays a single-user
|
|
// tailnet. Revisit if anyone is ever invited.
|
|
{"action": "accept", "src": ["autogroup:members"], "dst": ["*:*"]},
|
|
|
|
// Exit-node egress for user devices (fs currently advertises).
|
|
{"action": "accept", "src": ["autogroup:members"], "dst": ["autogroup:internet:*"]},
|
|
|
|
// Syncthing mesh: every device, both directions, one port.
|
|
{"action": "accept", "src": ["*"], "dst": ["*:22000"]},
|
|
|
|
// Server ↔ server ↔ cloud: agents, metrics, compose, DBs.
|
|
{"action": "accept", "src": ["tag:server", "tag:cloud"],
|
|
"dst": ["tag:server:*", "tag:cloud:*"]},
|
|
|
|
// Tagged servers reach the untagged hub hosts only on specific flows:
|
|
// Mattermost (straylight serve 443 + direct 8065), exporters anywhere.
|
|
{"action": "accept", "src": ["tag:server", "tag:cloud"],
|
|
"dst": [
|
|
"straylight.scylla-hammerhead.ts.net:443",
|
|
"straylight.scylla-hammerhead.ts.net:8065",
|
|
]},
|
|
{"action": "accept", "src": ["tag:server"], "dst": ["*:9100", "*:8420"]},
|
|
|
|
// Server agents → wntrmute Hermes peer API only (Kyle: outbound +
|
|
// maybe inbound peer API).
|
|
{"action": "accept", "src": ["tag:server"],
|
|
"dst": ["wntrmute.scylla-hammerhead.ts.net:8642"]},
|
|
|
|
// Phones / tablet / TV: HA is a must; Mattermost, Syncthing, and DSM
|
|
// nice-to-have. Nothing else — no SSH, no DBs, no exporters.
|
|
{"action": "accept", "src": ["tag:mobile"],
|
|
"dst": [
|
|
"homeassistant.scylla-hammerhead.ts.net:8123",
|
|
"straylight.scylla-hammerhead.ts.net:443",
|
|
"synology.scylla-hammerhead.ts.net:5000",
|
|
"synology.scylla-hammerhead.ts.net:5001",
|
|
]},
|
|
// (Syncthing for mobile arrives via the *:22000 mesh rule above.)
|
|
|
|
// tag:iot initiates nothing except the Syncthing mesh above.
|
|
],
|
|
|
|
// Tailscale SSH: unchanged default (members → own devices). Once P1
|
|
// adopts --ssh fleet-wide, consider narrowing dst to tag:server and
|
|
// adding a checkPeriod so sessions re-auth instead of persisting.
|
|
"ssh": [
|
|
{
|
|
"action": "accept",
|
|
"src": ["autogroup:members"],
|
|
"dst": ["autogroup:self"],
|
|
"users": ["autogroup:nonroot", "root"],
|
|
},
|
|
],
|
|
|
|
"nodeAttrs": [
|
|
// Funnel: servers and cloud boxes may publish; user desktops,
|
|
// phones, and IoT may not. (straylight is untagged by design and so
|
|
// loses Funnel eligibility — it runs serve, tailnet-only, which
|
|
// needs no attr.)
|
|
{
|
|
"target": ["tag:server", "tag:cloud"],
|
|
"attr": ["funnel"],
|
|
},
|
|
],
|
|
|
|
// Run on every save; the console executes these before accepting.
|
|
"tests": [
|
|
{
|
|
"src": "tag:mobile",
|
|
"accept": ["homeassistant.scylla-hammerhead.ts.net:8123",
|
|
"straylight.scylla-hammerhead.ts.net:443",
|
|
"100.95.252.120:22000"],
|
|
"deny": ["rift.scylla-hammerhead.ts.net:22",
|
|
"rift.scylla-hammerhead.ts.net:8000",
|
|
"dixie.scylla-hammerhead.ts.net:5432",
|
|
"orion.scylla-hammerhead.ts.net:9100"],
|
|
},
|
|
{
|
|
"src": "tag:server",
|
|
"accept": ["dixie.scylla-hammerhead.ts.net:11434",
|
|
"rift.scylla-hammerhead.ts.net:8000",
|
|
"straylight.scylla-hammerhead.ts.net:443",
|
|
"wntrmute.scylla-hammerhead.ts.net:8642"],
|
|
"deny": ["titan.scylla-hammerhead.ts.net:22"],
|
|
},
|
|
{
|
|
"src": "tag:iot",
|
|
"accept": ["synology.scylla-hammerhead.ts.net:22000"],
|
|
"deny": ["rift.scylla-hammerhead.ts.net:22"],
|
|
},
|
|
],
|
|
}
|