Skip to content

ACL Tags & Access Control

Tailscale ACLs use tag-based identity to control which machines and users can reach which services. Tags are managed in the Terraform Tailscale provider — never edit them in the Tailscale web console.


Tag Structure

Tags follow the pattern tag:cwiq-<scope>[-<service>]:

Tag Applied To Meaning
tag:cwiq-io All application servers (dev, demo, langfuse) General CWIQ server — gets full observability access
tag:cwiq-dev-account Servers and runners in the dev account Dev account resources
tag:cwiq-ss-account Servers in shared-services account Shared-services resources
tag:cwiq-ss-loki Loki server Loki receives log push
tag:cwiq-ss-prometheus Prometheus server Prometheus receives metric push
tag:cwiq-ss-vault Vault server Vault API
tag:cwiq-ss-nexus Nexus server Nexus artifact access
tag:subnet-router Tailscale subnet router instances Route advertisers
tag:dev-apps Dev application servers Access to shared-services

Key ACL Rules

Observability Cross-VPC Access

Dev and demo servers push logs and metrics to the shared-services observability stack:

// tag:cwiq-dev-account → Loki (log push)
{ "action": "accept", "src": ["tag:cwiq-dev-account"], "dst": ["tag:cwiq-ss-loki:3100"] }

// tag:cwiq-dev-account → Prometheus (metric push)
{ "action": "accept", "src": ["tag:cwiq-dev-account"], "dst": ["tag:cwiq-ss-prometheus:9009"] }

Without these rules, Alloy agents on dev/demo servers cannot push telemetry to the shared observability stack.

DevOps Full Access

{ "action": "accept", "src": ["group:devops"], "dst": ["*:*"] }

Members of group:devops can reach any machine on any port.

Dev Apps → Shared Services (SSO)

{ "action": "accept", "src": ["tag:dev-apps"], "dst": ["10.0.0.0/16:443", "10.0.0.0/16:80"] }

Allows dev applications to reach Authentik SSO (sso.shared.cwiq.io) via the Tailscale mesh.


Tag Owners

Tags are owned by the group:devops group. Only devops group members can assign tags to machines. This prevents machines from self-assigning elevated tags.

{
  "tagOwners": {
    "tag:subnet-router": ["group:devops"],
    "tag:dev-apps":      ["group:devops"],
    "tag:cwiq-io":       ["group:devops"]
  }
}

ACL Management

Manage ACLs via Terraform only

ACLs are defined in terraform-plan/ using the Tailscale Terraform provider. Never edit ACLs in the Tailscale web console (login.tailscale.com/admin/acls) — manual changes will be overwritten on the next terraform apply.

# Apply ACL changes
cd terraform-plan/organization/tailscale
terraform plan -var="tailscale_auth_key=$TAILSCALE_AUTH_KEY" -var="created_by=$CREATED_BY"
terraform apply -var="tailscale_auth_key=$TAILSCALE_AUTH_KEY" -var="created_by=$CREATED_BY"

Testing ACL Rules

# From a Tailscale client — test connectivity to a tagged host
tailscale ping loki-shared-cwiq-io

# Check what the current machine can reach
tailscale status

# Check if a specific port is reachable
curl -m 5 http://loki-shared-cwiq-io:3100/ready

Adding a New Server to Tailscale

When a new EC2 instance joins the tailnet via its user data script, it needs:

  1. A tag in the tailscale_tags Terraform variable for that module
  2. ACL rules granting any necessary access (e.g., if it needs to push to Loki/Prometheus)
  3. Documentation update in alloy/docs/README.md and docs/SLACK_ALERTING.md (mandatory co-change rule)
# Example in ec2-instances/<app>/variables.tf
variable "tailscale_tags" {
  default = "tag:cwiq-io,tag:cwiq-dev-account"
}