Harden Tailscale ACL policy with least-privilege grants #23

Merged
eblume merged 3 commits from pulumi-tailscale-security-hardening into main 2026-01-17 11:58:05 -08:00
Owner

Summary

  • Replace permissive wildcard ACL with role-based grants using autogroup:admin and autogroup:member
  • Admins: full access to all services via autogroup:admin with dst: ["*"]
  • Members: user-facing services only (Kiwix, Forge, PyPI, Miniflux, PostgreSQL) - no Grafana/Loki/NAS
  • SSH hardening: remove root access, use "check" action with 12h re-auth period
  • Add ACL tests to validate policy behavior
  • Tag indri (homelab) and sifaka (NAS) via Pulumi

Important lesson learned: Don't tag user-owned devices (like gilbert) via Pulumi - tagging converts them to "tagged devices" which lose user
identity and break user-based SSH rules.

Deployment and Testing

  • Pulumi preview passes
  • HuJSON syntax validated
  • ACL tests defined and passing
  • Deploy with mise run tailnet-up
  • Verify SSH access from gilbert to indri
  • Verify all services healthy with mise run indri-services-check
  • Verify Allison cannot access Grafana/Loki/NAS

🤖 Generated with Claude Code

## Summary - Replace permissive wildcard ACL with role-based grants using `autogroup:admin` and `autogroup:member` - **Admins**: full access to all services via `autogroup:admin` with `dst: ["*"]` - **Members**: user-facing services only (Kiwix, Forge, PyPI, Miniflux, PostgreSQL) - no Grafana/Loki/NAS - SSH hardening: remove root access, use "check" action with 12h re-auth period - Add ACL tests to validate policy behavior - Tag indri (homelab) and sifaka (NAS) via Pulumi **Important lesson learned:** Don't tag user-owned devices (like gilbert) via Pulumi - tagging converts them to "tagged devices" which lose user identity and break user-based SSH rules. ## Deployment and Testing - [x] Pulumi preview passes - [x] HuJSON syntax validated - [x] ACL tests defined and passing - [x] Deploy with `mise run tailnet-up` - [x] Verify SSH access from gilbert to indri - [x] Verify all services healthy with `mise run indri-services-check` - [ ] Verify Allison cannot access Grafana/Loki/NAS 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Replace permissive wildcard ACL with specific service grants:
- Admin: full access to all services including NAS
- Member: user-facing services only (no Grafana/Loki/NAS)
- Infrastructure tags for device-to-device communication

Add device tagging via Pulumi:
- gilbert (workstation) - informational tag only
- sifaka (NAS) - backup target for homelab, admin-only access
- indri already tagged as homelab with service tags

SSH hardening:
- Remove root SSH access
- Use "check" action with MFA for all SSH rules
- Admin can SSH to homelab, workstation, nas, self

Add ACL tests to validate policy behavior on save.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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>
The previous commit incorrectly assumed autogroup:admin and dst:["*"]
didn't work. The actual issue was that tagging gilbert converted it
from a user-owned device to a tagged device, losing user identity.

Now that gilbert remains untagged, autogroup:admin works correctly.
This simplifies the policy and allows future admins to inherit access.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
eblume merged commit e6d302b40b into main 2026-01-17 11:58:05 -08:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
eblume/blumeops!23
No description provided.