diff --git a/pulumi/__main__.py b/pulumi/__main__.py index f8d4dde..33f3d0d 100644 --- a/pulumi/__main__.py +++ b/pulumi/__main__.py @@ -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) diff --git a/pulumi/policy.hujson b/pulumi/policy.hujson index 3178f6c..580aade 100644 --- a/pulumi/policy.hujson +++ b/pulumi/policy.hujson @@ -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"], }, ], }