Tailscale - ACL file

Tailscale - ACL file

Structure

The policy file uses HuJSON format (JSON with comments) and includes several key sections:

1. Groups

Define groups of users for easier access management:

{
  "groups": {
    "group:devops": [
      "alice@example.com",
      "bob@example.com"
    ],
    "group:developers": [
      "charlie@example.com",
      "diana@example.com"
    ]
  }
}

2. Tag Owners

Define which users or groups can assign specific tags to devices. Tags are used to identify and group connectors:

{
  "tagOwners": {
    "tag:terraform": [],  // Only OAuth clients can create
    "tag:k8s": ["tag:terraform"],  // Only terraform-tagged devices can create
    "tag:production-eks-example-com": ["tag:terraform"],
    "tag:staging-eks-example-com": ["tag:terraform"]
  }
}

3. Auto Approvers

Automatically approve route advertisements from tagged devices. This eliminates manual approval for trusted connectors:

{
  "autoApprovers": {
    "routes": {
      "10.0.0.0/8": ["tag:k8s"],        // All RFC1918 10.x networks
      "172.16.0.0/12": ["tag:k8s"],     // All RFC1918 172.16-31.x networks
      "192.168.0.0/16": ["tag:k8s"]     // All RFC1918 192.168.x networks
    }
  }
}

4. Grants

Define access permissions using the grants system. Grants are more flexible than traditional ACLs:

{
  "grants": [
    {
      "src": ["group:devops"],        // Source: who can access
      "dst": ["*"],                    // Destination: all devices
      "ip": ["*"]                      // All ports
    },
    {
      "src": ["group:developers"],
      "dst": ["tag:staging-eks-example-com"],
      "ip": ["*"]
    }
  ]
}

5. App Connectors

Configure app connectors to expose specific services (like Kubernetes API servers or internal applications) through Tailscale:

{
  "nodeAttrs": [
    {
      "target": ["*"],
      "app": {
        "tailscale.com/app-connectors": [
          {
            "name": "eks-production",
            "connectors": ["tag:production-eks-example-com"],
            "domains": [
              "ABCD1234.gr7.eu-west-1.eks.amazonaws.com",  // EKS API endpoint. Note: the domain needs to be in capitals
              "grafana.example.com",
              "prometheus.example.com"
            ]
          }
        ]
      }
    }
  ]
}

Example Complete Policy File

Here’s a simplified example for a customer setup:

{
  "groups": {
    "group:admins": [
      "admin@example.com"
    ],
    "group:developers": [
      "dev1@example.com",
      "dev2@example.com"
    ]
  },
  "tagOwners": {
    "tag:terraform": [],
    "tag:k8s": ["tag:terraform"],
    "tag:production-eks-example-com": ["tag:terraform"],
    "tag:staging-eks-example-com": ["tag:terraform"]
  },
  "autoApprovers": {
    "routes": {
      "10.0.0.0/8": ["tag:k8s"],
      "192.168.0.0/16": ["tag:k8s"]
    }
  },
  "grants": [
    {
      "src": ["group:admins"],
      "dst": ["*"],
      "ip": ["*"]
    },
    {
      "src": ["group:developers"],
      "dst": ["tag:staging-eks-example-com"],
      "ip": ["*"]
    }
  ],
  "nodeAttrs": [
    {
      "target": ["*"],
      "app": {
        "tailscale.com/app-connectors": [
          {
            "name": "eks-production",
            "connectors": ["tag:production-eks-example-com"],
            "domains": [
              "ABC123.gr7.eu-west-1.eks.amazonaws.com"
            ]
          },
          {
            "name": "eks-staging",
            "connectors": ["tag:staging-eks-example-com"],
            "domains": [
              "DEF456.gr7.eu-west-1.eks.amazonaws.com"
            ]
          }
        ]
      }
    }
  ]
}

Setting Up ACL Management with GitHub Actions

  1. Add the policy file as tailscale/policy.hujson in the repository
  2. Configure GitHub Actions with the GitHub OAuth Client credentials:
    • Add TAILSCALE_OAUTH_CLIENT_ID as a GitHub secret
    • Add TAILSCALE_OAUTH_CLIENT_SECRET as a GitHub secret
  3. Create a workflow to automatically push policy changes to Tailscale on commits
  4. Disable manual ACL editing in the Tailscale admin console to enforce GitOps practices: https://login.tailscale.com/admin/settings/policy-file-management and set the External reference to the URL of your repository: https://github.com/skyscrapers//blob/master/tailscale/policy.hujson

Example GitHub Actions workflow:

name: Update Tailscale ACL

on:
  push:
    branches: ["master", "main"]
    paths:
      - 'tailscale/policy.hujson'
  pull_request:
    branches: ["master", "main"]
    paths:
      - 'tailscale/policy.hujson'

jobs:
  acls:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3

      - name: Deploy ACL
        if: github.event_name == 'push'
        id: deploy-acl
        uses: tailscale/gitops-acl-action@v1
        with:
          oauth-client-id: ${{ secrets.TS_OAUTH_ID }}
          oauth-secret: ${{ secrets.TS_OAUTH_SECRET}}
          tailnet: ${{ secrets.TS_TAILNET }}
          action: apply
          policy-file: tailscale/policy.hujson

      - name: Test ACL
        if: github.event_name == 'pull_request'
        id: test-acl
        uses: tailscale/gitops-acl-action@v1
        with:
          oauth-client-id: ${{ secrets.TS_OAUTH_ID }}
          oauth-secret: ${{ secrets.TS_OAUTH_SECRET}}
          tailnet: ${{ secrets.TS_TAILNET }}
          action: test
          policy-file: tailscale/policy.hujson

Important Notes

  • Tag Naming: Tags should follow the pattern tag:<cluster-name> for consistency
  • Route Approval: Auto-approvers eliminate the need for manual route approval in the Tailscale admin console
  • App Connectors: Required for accessing Kubernetes API servers and internal services through Tailscale
  • Testing: Always test ACL changes in a non-production environment first
  • Version Control: Keep your ACL policy file in version control for audit history and easy rollback
Last updated on