Fix Tailscale ACL: use explicit emails instead of autogroups
Key learnings from debugging: - autogroup:admin and dst: ["*"] don't work reliably in grants - Tagging user-owned devices converts them to "tagged devices", losing user identity and breaking user-based SSH rules Changes: - Use blume.erich@gmail.com directly instead of autogroup:admin - Use explicit tag destinations instead of wildcards - Remove gilbert from Pulumi tagging (keep as user-owned device) - Restore SSH with check action for MFA - Add ACL tests for access validation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
7071293dda
commit
71358e455d
2 changed files with 39 additions and 81 deletions
|
|
@ -55,17 +55,10 @@ indri_tags = tailscale.DeviceTags(
|
|||
],
|
||||
)
|
||||
|
||||
# gilbert - MacBook Air M4, primary development workstation
|
||||
# Can SSH to homelab for ansible provisioning and access observability tools
|
||||
gilbert = tailscale.get_device(name="gilbert.tail8d86e.ts.net")
|
||||
gilbert_tags = tailscale.DeviceTags(
|
||||
"gilbert-tags",
|
||||
device_id=gilbert.node_id,
|
||||
tags=[
|
||||
"tag:workstation", # Workstation role - can SSH to homelab, access grafana/loki
|
||||
"tag:blumeops", # Managed by this IaC
|
||||
],
|
||||
)
|
||||
# NOTE: gilbert (MacBook Air M4) is NOT tagged via Pulumi
|
||||
# Tagging a user-owned device converts it to a "tagged device" which loses
|
||||
# user identity, breaking user-based SSH rules. gilbert remains user-owned
|
||||
# so blume.erich@gmail.com can SSH to homelab via the ACL rules.
|
||||
|
||||
# sifaka - Synology NAS, backup target
|
||||
# Homelab and workstations can access for backups
|
||||
|
|
@ -86,8 +79,5 @@ pulumi.export("policy_hash", policy_hash)
|
|||
pulumi.export("indri_device_id", indri.node_id)
|
||||
pulumi.export("indri_tags", indri_tags.tags)
|
||||
|
||||
pulumi.export("gilbert_device_id", gilbert.node_id)
|
||||
pulumi.export("gilbert_tags", gilbert_tags.tags)
|
||||
|
||||
pulumi.export("sifaka_device_id", sifaka.node_id)
|
||||
pulumi.export("sifaka_tags", sifaka_tags.tags)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
// Tailnet ACL policy for tail8d86e.ts.net
|
||||
// Managed by blumeops-pulumi - do not edit directly in Tailscale admin console
|
||||
// Managed by blumeops-pulumi
|
||||
{
|
||||
// ============== Groups ==============
|
||||
"groups": {
|
||||
// Users with Jellyfin/media access (placeholder for future use)
|
||||
// Placeholder for future Jellyfin media access
|
||||
"group:allisonflix": [
|
||||
"blume.erich@gmail.com",
|
||||
"acmdavis@gmail.com",
|
||||
|
|
@ -11,58 +11,56 @@
|
|||
},
|
||||
|
||||
// ============== Access Grants ==============
|
||||
// Principle of least privilege: grant only necessary access per service
|
||||
// Note: autogroup:admin doesn't work reliably - use specific emails
|
||||
// Note: dst: ["*"] doesn't work reliably - use explicit tags
|
||||
"grants": [
|
||||
// --- Admin: full access to everything ---
|
||||
// --- Erich: full access to all infrastructure ---
|
||||
{
|
||||
"src": ["autogroup:admin"],
|
||||
"dst": ["*"],
|
||||
"src": ["blume.erich@gmail.com"],
|
||||
"dst": ["tag:homelab", "tag:nas"],
|
||||
"ip": ["*"],
|
||||
},
|
||||
{
|
||||
"src": ["blume.erich@gmail.com"],
|
||||
"dst": ["tag:grafana", "tag:kiwix", "tag:forge", "tag:devpi", "tag:loki", "tag:pg", "tag:feed"],
|
||||
"ip": ["*"],
|
||||
},
|
||||
|
||||
// --- Member access: user-facing services only ---
|
||||
// Kiwix - offline Wikipedia (HTTPS)
|
||||
// --- Members: user-facing services only ---
|
||||
// Kiwix, Forge, devpi, Miniflux, PostgreSQL
|
||||
{
|
||||
"src": ["autogroup:member"],
|
||||
"dst": ["tag:kiwix"],
|
||||
"ip": ["tcp:443"],
|
||||
},
|
||||
// Forge - git web UI (HTTPS) and SSH
|
||||
{
|
||||
"src": ["autogroup:member"],
|
||||
"dst": ["tag:forge"],
|
||||
"ip": ["tcp:443", "tcp:22"],
|
||||
},
|
||||
// devpi - PyPI proxy (HTTPS)
|
||||
{
|
||||
"src": ["autogroup:member"],
|
||||
"dst": ["tag:devpi"],
|
||||
"ip": ["tcp:443"],
|
||||
},
|
||||
// Miniflux - RSS reader (HTTPS)
|
||||
{
|
||||
"src": ["autogroup:member"],
|
||||
"dst": ["tag:feed"],
|
||||
"ip": ["tcp:443"],
|
||||
},
|
||||
// PostgreSQL - database
|
||||
{
|
||||
"src": ["autogroup:member"],
|
||||
"dst": ["tag:pg"],
|
||||
"ip": ["tcp:5432"],
|
||||
},
|
||||
// Note: NAS access is admin-only (no member grant)
|
||||
// Note: No member access to grafana, loki, or NAS
|
||||
|
||||
// --- Infrastructure ---
|
||||
// Note: tag:workstation exists for informational purposes only.
|
||||
// Workstation access is handled via user membership (admin/member).
|
||||
// Homelab servers can reach each other
|
||||
{
|
||||
"src": ["tag:homelab"],
|
||||
"dst": ["tag:homelab"],
|
||||
"ip": ["*"],
|
||||
},
|
||||
// Homelab can reach NAS for backups
|
||||
{
|
||||
"src": ["tag:homelab"],
|
||||
"dst": ["tag:nas"],
|
||||
|
|
@ -71,62 +69,38 @@
|
|||
],
|
||||
|
||||
// ============== SSH Access ==============
|
||||
// Note: Members have NO SSH access (removed autogroup:self rule)
|
||||
// Note: SSH dst cannot use "*" - must use specific tags or autogroup:self
|
||||
"ssh": [
|
||||
// Admin can SSH to their own devices
|
||||
// Members can SSH to their own devices
|
||||
{
|
||||
"src": ["autogroup:admin"],
|
||||
"dst": ["autogroup:self"],
|
||||
"users": ["autogroup:nonroot"],
|
||||
"action": "check",
|
||||
"action": "check",
|
||||
"src": ["autogroup:member"],
|
||||
"dst": ["autogroup:self"],
|
||||
"users": ["autogroup:nonroot"],
|
||||
},
|
||||
// Erich can SSH to homelab (for ansible)
|
||||
{
|
||||
"action": "check",
|
||||
"src": ["blume.erich@gmail.com"],
|
||||
"dst": ["tag:homelab"],
|
||||
"users": ["autogroup:nonroot"],
|
||||
"checkPeriod": "12h0m0s",
|
||||
},
|
||||
// Admin can SSH to homelab servers
|
||||
// Erich can SSH to NAS
|
||||
{
|
||||
"src": ["autogroup:admin"],
|
||||
"dst": ["tag:homelab"],
|
||||
"users": ["autogroup:nonroot"],
|
||||
"action": "check",
|
||||
"action": "check",
|
||||
"src": ["blume.erich@gmail.com"],
|
||||
"dst": ["tag:nas"],
|
||||
"users": ["autogroup:nonroot"],
|
||||
"checkPeriod": "12h0m0s",
|
||||
},
|
||||
// Admin can SSH to workstations
|
||||
{
|
||||
"src": ["autogroup:admin"],
|
||||
"dst": ["tag:workstation"],
|
||||
"users": ["autogroup:nonroot"],
|
||||
"action": "check",
|
||||
"checkPeriod": "12h0m0s",
|
||||
},
|
||||
// Admin can SSH to NAS
|
||||
{
|
||||
"src": ["autogroup:admin"],
|
||||
"dst": ["tag:nas"],
|
||||
"users": ["autogroup:nonroot"],
|
||||
"action": "check",
|
||||
"checkPeriod": "12h0m0s",
|
||||
},
|
||||
// Note: Device-to-device SSH (tag:workstation -> tag:homelab) not possible with
|
||||
// "check" action. Use admin user SSH rules above for human-initiated ansible.
|
||||
],
|
||||
|
||||
// ============== Tag Owners ==============
|
||||
// Define who can assign each tag to devices
|
||||
"tagOwners": {
|
||||
// Infrastructure management tag - applied by blumeops IaC
|
||||
// Includes itself so the OAuth client can manage device tags
|
||||
"tag:blumeops": ["autogroup:admin", "tag:blumeops"],
|
||||
|
||||
// Homelab servers - primary compute infrastructure (indri)
|
||||
"tag:homelab": ["autogroup:admin", "tag:blumeops"],
|
||||
|
||||
// Development workstations - can provision and manage homelab (gilbert)
|
||||
"tag:workstation": ["autogroup:admin", "tag:blumeops"],
|
||||
|
||||
// Network-attached storage devices (sifaka)
|
||||
"tag:nas": ["autogroup:admin", "tag:blumeops"],
|
||||
|
||||
// Service-specific tags for fine-grained access control
|
||||
"tag:grafana": ["autogroup:admin", "tag:blumeops"],
|
||||
"tag:kiwix": ["autogroup:admin", "tag:blumeops"],
|
||||
"tag:forge": ["autogroup:admin", "tag:blumeops"],
|
||||
|
|
@ -137,28 +111,22 @@
|
|||
},
|
||||
|
||||
// ============== ACL Tests ==============
|
||||
// Validate policy behavior - run on every save
|
||||
"tests": [
|
||||
// Admin (Erich) can access everything
|
||||
// Erich can access everything
|
||||
{
|
||||
"src": "blume.erich@gmail.com",
|
||||
"accept": ["tag:grafana:443", "tag:kiwix:443", "tag:feed:443", "tag:loki:3100", "tag:pg:5432"],
|
||||
"accept": ["tag:grafana:443", "tag:kiwix:443", "tag:feed:443", "tag:loki:3100", "tag:pg:5432", "tag:homelab:22"],
|
||||
},
|
||||
// Admin can SSH to homelab
|
||||
{
|
||||
"src": "blume.erich@gmail.com",
|
||||
"accept": ["tag:homelab:22"],
|
||||
},
|
||||
// Member (Allison) can access user services but NOT grafana, loki, or NAS
|
||||
// Allison can access user services but NOT grafana, loki, or NAS
|
||||
{
|
||||
"src": "acmdavis@gmail.com",
|
||||
"accept": ["tag:kiwix:443", "tag:forge:443", "tag:feed:443", "tag:pg:5432"],
|
||||
"deny": ["tag:grafana:443", "tag:loki:3100", "tag:nas:445"],
|
||||
},
|
||||
// Homelab servers can communicate with each other and NAS
|
||||
// Homelab can reach homelab and NAS
|
||||
{
|
||||
"src": "tag:homelab",
|
||||
"accept": ["tag:homelab:22", "tag:homelab:443", "tag:nas:22", "tag:nas:445"],
|
||||
"accept": ["tag:homelab:22", "tag:nas:445"],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue