DEV Community

Cover image for Service-Based Access in Homelab with Tailscale ACL
Mustafa ERBAY
Mustafa ERBAY

Posted on • Originally published at mustafaerbay.com.tr

Service-Based Access in Homelab with Tailscale ACL

In a homelab environment or small business networks, using Tailscale Access Control Lists (ACLs) to control access to devices and services on the network is an effective way to implement Zero-Trust principles. Tailscale ACLs allow you to define detailed authorization rules based on the user's identity, device, and the service they want to access, thus applying the principle of least privilege for each access request. This approach reduces potential security vulnerabilities in your network and ensures that only authorized users can access specific resources over specific ports.

This guide will explain step-by-step how to configure service-specific access rules in your homelab using Tailscale ACLs. I will provide practical information ranging from the configuration file format to user and device grouping, and port-based access restrictions. Our goal is to ensure that each service on your network is accessible only by the people or automated systems that truly need it.

ℹ️ ACLs vs. Grants

Tailscale offers both ACLs and Grants for access control. Grants are a next-generation access control policy syntax that provides all the functionality of ACLs plus additional capabilities. While Tailscale will continue to support ACLs indefinitely, they will not receive new features, so Tailscale recommends migrating to Grants for new tailnet policy file configurations.

What is Tailscale ACL and Why is it Important?

Tailscale Access Control Lists (ACLs) are a set of security rules that determine access between devices and users within a Tailscale network. These rules are written in JSON or HCL format and uploaded to the Tailscale coordinator to be enforced across the network. ACLs allow you to precisely define who can access which device, over which port, and with which protocol.

When a Tailscale network is first created, it starts with a policy that, by default, allows all devices to access each other. However, when an ACL policy file is defined, Tailscale applies a deny-by-default principle; meaning all connections not explicitly permitted are blocked. This reduces security risks in homelab environments, especially when running multiple services for different purposes (NAS, media server, development environment, automation control). For example, it's important for home guests or automation systems to only access a specific web interface, while being unable to access sensitive file servers or management interfaces. ACLs enable the detailed segmentation and authorization required in such scenarios.

ℹ️ Zero-Trust and ACLs

In a Zero-Trust architecture, no user or device is trusted by default, and every access request is verified. Tailscale ACLs play a central role in implementing this principle. By checking identity and authorization for every connection, they significantly reduce the risk of lateral movement in your network.

Thanks to ACLs, no matter how complex your network topology, you can apply the "least privilege" principle for each service. This limits the resources an attacker can access in the event of a breach and minimizes potential damage.

Basic Tailscale ACL Configuration: Getting Started

To configure Tailscale ACLs, we use the administration panel at admin.tailscale.com. In the "Access Controls" section, you can directly edit your ACL rules or paste them from a file. Initially, we can start with a simple configuration where all users have SSH access to all devices.

The ACL file can be in json or hcl format. Tailscale generally recommends the HCL format because it is more readable and easier to interpret. The example below shows what a basic HCL ACL file looks like:

// acl.hcl
// General ACL file
{
  // Contains IP addresses and names of defined hosts.
  // These names are used for easy reference in ACL rules.
  "hosts": {
    "homelab-nas": "100.100.100.100", // Example IP address
    "web-server": "100.100.100.101", // Example IP address
    "dev-machine": "100.100.100.102" // Example IP address
  },

  // Contains defined user groups.
  // These groups are used to grant bulk permissions to users.
  "groups": {
    "admin": ["mustafa@example.com", "yönetici@example.com"],
    "developers": ["developer1@example.com", "developer2@example.com"]
  },

  // Main section for ACL rules.
  // This section defines which users can access which devices with which protocol.
  "acls": [
    // General rule: Allows all users SSH (port 22) access to all devices.
    {
      "action": "accept",
      "src": ["autogroup:member"], // autogroup:member represents all Tailscale members.
      "dst": ["*:22"] // Access to all devices (Wildcard *) on port 22 (SSH).
    },
    // Allows the admin group full access to all devices on all ports.
    {
      "action": "accept",
      "src": ["group:admin"],
      "dst": ["*:*"] // Access to all devices on all ports.
    }
  ],

  // Rules for tag-based access control.
  // This allows you to group devices by tagging them.
  "tagOwners": {
    "tag:server": ["group:admin"],
    "tag:dev": ["group:developers"]
  },

  // SSH access control rules.
  // This section allows you to add additional security layers for SSH connections.
  "ssh": [
    {
      "action": "accept",
      "src": ["group:admin"],
      "dst": ["tag:server"],
      "users": ["root", "adminuser"] // SSH access only as specified users.
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

In this basic configuration, the hosts block is used to easily reference specific devices, while the groups block collects users into logical groups. The acls block defines the actual access rules. The autogroup:member expression represents all active users in your Tailscale network. This prevents us from having to constantly update the ACL file when a new user is added or removed.

⚠️ ACL File Validation

Before uploading the ACL file to the Tailscale admin panel, it is important to validate it locally with the tailscale validate <acl_file.hcl> command. This helps detect syntax errors and potential configuration issues in advance, preventing unexpected access disruptions in your network.

After editing the ACL file, you can apply the changes by pasting it into the Tailscale admin panel and clicking the "Save" button. From this moment on, all devices and users in your Tailscale network will be authorized according to the new rules.

Advanced ACL Rules for Service-Based Access Control

While basic ACL configuration provides general access control, real security and flexibility in a homelab environment are achieved with service-based access control. This means that specific users or groups can access only specific services (i.e., ports and protocols) on particular devices. For example, a media server might need to be accessible only on ports 80 and 443 (HTTP/HTTPS), but not on SSH (22) or other management ports.

In advanced ACL rules, we use the dst (destination) field to specify the target device and port in detail. The tag mechanism allows us to logically group devices, which simplifies management in large networks or with frequently changing device lists. To tag a device, you can assign a tag from the Tailscale admin panel or with the command tailscale up --advertise-tags=tag:webserver.

// acl.hcl - Advanced Service-Based Access Control
{
  "hosts": {
    "nas-server": "100.100.100.100", // Example IP address
    "web-dev-server": "100.100.100.101", // Example IP address
    "home-assistant": "100.100.100.102" // Example IP address
  },

  "groups": {
    "admin": ["mustafa@example.com"],
    "family": ["esim@example.com", "cocuk@example.com"],
    "guests": ["misafir@example.com"]
  },

  "tagOwners": {
    "tag:nas": ["group:admin"],
    "tag:webserver": ["group:admin", "group:developers"],
    "tag:smarthome": ["group:admin"]
  },

  "acls": [
    // 1. Full access for the admin group to all devices on all ports
    {
      "action": "accept",
      "src": ["group:admin"],
      "dst": ["*:*"]
    },

    // 2. Allow family members to access NAS only via SMB (445) and SFTP (22)
    {
      "action": "accept",
      "src": ["group:family"],
      "dst": ["nas-server:445", "nas-server:22"]
    },

    // 3. Allow developers to access web development server (tag:webserver) only via HTTP/HTTPS (80, 443) and SSH (22)
    {
      "action": "accept",
      "src": ["group:developers"],
      "dst": ["tag:webserver:80", "tag:webserver:443", "tag:webserver:22"]
    },

    // 4. Allow guests to access only the Home Assistant interface (8123)
    {
      "action": "accept",
      "src": ["group:guests"],
      "dst": ["home-assistant:8123"]
    }
    // Tailscale by default denies all connections not explicitly permitted.
    // Therefore, a "deny" rule is generally not needed explicitly.
  ]
}
Enter fullscreen mode Exit fullscreen mode

In the example above, each acl rule addresses a specific scenario:

  • The admin group is granted full access.
  • The family group is allowed to access nas-server only on SMB and SFTP ports.
  • The developers group has access to servers tagged with tag:webserver only on web and SSH ports.
  • The guests group is only allowed access to the home-assistant web interface.

This detailed control significantly strengthens your network's security posture. Each rule provides clear answers to the questions "who, where, with what." This way, unauthorized access attempts are automatically blocked, and your services become more secure.

Subnet Router and ACL Integration

Tailscale offers the Subnet Router feature to make not only devices connected to its own network but also other devices on a physical network accessible. When a Tailscale node is configured as a Subnet Router, IP addresses and services on the local network to which that node is connected can be accessed via the Tailscale network. This ensures that some devices in your homelab (e.g., older NAS devices or IoT devices that cannot have Tailscale directly installed) are also securely accessible.

ℹ️ Subnet Router vs. Exit Node

Subnet Routers allow devices on your Tailscale network to access other devices on the local network (without a Tailscale client installed) to which the Subnet Router is connected. Exit Nodes, on the other hand, allow the Tailscale client to route all internet traffic through a specific Tailscale device. These two features serve different purposes.

ACLs also apply to these local network resources accessed via the Subnet Router. This means we can determine whether a user can access a local NAS via the Subnet Router using ACL rules. This allows you to extend the zero-trust principle to your physical network.

Diagram

To enable a Subnet Router, you need to run the following command on the relevant Tailscale node after enabling IP forwarding:

tailscale up --advertise-routes=192.168.1.0/24
Enter fullscreen mode Exit fullscreen mode

This command announces that all IPs in the 192.168.1.0/24 network will be accessible via the Tailscale network. Afterwards, you need to approve this route on the "Machines" page in the Tailscale admin panel.

To control access via the Subnet Router in the ACL file, we use local network IP ranges in the dst field:

// acl.hcl - Subnet Router with ACL Integration
{
  // ... (hosts, groups, tagOwners definitions) ...

  "acls": [
    // ... (previous ACL rules) ...

    // Access rules for devices on the local network via Subnet Router
    // Allow the admin group access to all devices on the 192.168.1.0/24 network on all ports
    {
      "action": "accept",
      "src": ["group:admin"],
      "dst": ["192.168.1.0/24:*"]
    },

    // Allow the family group access to device 192.168.1.10 (local NAS IP) only on port 445 (SMB)
    {
      "action": "accept",
      "src": ["group:family"],
      "dst": ["192.168.1.10:445"]
    },

    // Deny guests access to any resource on the local network
    {
      "action": "deny",
      "src": ["group:guests"],
      "dst": ["192.168.1.0/24:*"]
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

In this example, the admin group is granted access to the entire local network via the Subnet Router, while the family group's access is restricted to a specific local IP and port. The guests group is completely blocked from accessing the local network. This flexibility allows you to apply a consistent security policy, regardless of your homelab's network architecture.

Security Best Practices and Common Mistakes

When using Tailscale ACLs, it's important to follow some best practices and avoid common mistakes to maximize network security. The principle of least privilege forms the foundation of network security, and ACLs are a powerful tool for implementing this principle.

Best Practices:

  1. Principle of Least Privilege (PoLP): Grant each user or device the absolute minimum access privileges necessary to perform their tasks. Never use broad permissions like *:*, reserving them only for special cases like group:admin if truly necessary.
  2. Default Deny: Tailscale ACLs operate on a default-deny principle; meaning everything not explicitly permitted is blocked. However, in complex ACL files, adding an action: "deny" rule at the end of each rule or as a general rule can make your security posture more explicit and help catch accidentally granted broad permissions.
  3. User and Device Grouping: Organize users (e.g., admin, family, developers) and devices (e.g., tag:webserver, tag:nas) into logical groups. This makes the ACL file more readable and manageable. When a new user is added or a device's role changes, you only need to update the relevant group definition.
  4. Clear and Detailed Rules: Clearly state what each ACL rule permits or denies. Add comments if necessary to explain the purpose of the rules. In the dst field, specify not only the device name but also the port or port range (e.g., web-server:80, nas-server:22,445).
  5. Regular Review: Review your ACL rules regularly. As users, devices, and services in your network change, your ACLs must also remain up-to-date. Remove unnecessary or no longer valid rules. This reduces accumulated "security debt" over time.

Common Mistakes:

  1. Broad Wildcard Usage: Using overly broad wildcards like dst: ["*:*"] or src: ["*"] can lead to security vulnerabilities. Especially using * in the src (source) field means anyone in the Tailscale network can access the specified destination. Instead, target specific groups or devices.
  2. Forgotten Ports: Forgetting that a service uses multiple ports can cause access issues. For example, assume a web application uses both ports 80 (HTTP) and 443 (HTTPS). Allowing only 80 will block HTTPS access. Make sure to include all necessary ports in the ACL.
  3. Incorrect Group Definitions: Assigning users or devices to the wrong groups can lead to unauthorized access or access blocks. Ensure you correctly type user emails or device tags.
  4. ACL Ordering Misconception: Tailscale ACLs evaluate all accept rules and allow access if any accept rule matches. Therefore, the order of accept rules is not critical. However, for readability, it's good practice to write more specific rules before more general ones. For SSH access rules, more restrictive policies are checked first (e.g., check rules before accept rules).
  5. Neglecting to Test: Not testing ACL changes before deploying them live can cause network outages. In addition to using the tailscale validate command, perform tests from different users and devices after applying changes to verify that access works as expected.

These practical applications and strategies for avoiding mistakes will ensure that your Tailscale ACLs in your homelab are both effective and secure.

Managing ACL Changes and Troubleshooting

The ACL file is the heart of your network's security policies, so properly managing changes and troubleshooting potential issues is critically important. A misconfigured ACL can lead to service outages or security vulnerabilities.

Managing ACL Changes:

  1. Version Control: Keeping your ACL file under a version control system (e.g., Git) is the best approach. This allows you to keep a record of all changes made, see when and by whom changes were made, and revert to a previous version if necessary. This is indispensable, especially in environments where multiple people manage the ACL file.
  2. Test Environment: If possible, it can be beneficial to test ACL changes first in a test Tailscale network or an isolated environment. While this may not always be feasible in a homelab, in large corporate structures, such preparation minimizes potential issues in live systems.
  3. Small and Incremental Changes: Instead of making too many changes at once, update the ACL in small, manageable chunks. Test and verify each change. This simplifies the troubleshooting process, as you can focus only on the last change made when a problem occurs.
  4. Change Notification: Especially in a shared homelab or team environment, notify relevant users of ACL changes. This ensures users are informed when they experience unexpected access issues.

Troubleshooting:

When you encounter an issue with Tailscale ACLs, you can diagnose and resolve the problem by following these steps:

  1. tailscale validate: Run this command first before uploading the ACL file to the Tailscale admin panel or whenever you experience an issue. It will help you detect syntax errors, invalid IP addresses, or incorrect group names.

    tailscale validate /path/to/your/acl.hcl
    

    If valid, you will see "ACL file is valid". Otherwise, you will receive a message indicating where the error is.

  2. tailscale status: This command shows the status, IP addresses, and connections of all devices in your Tailscale network. Check if the device you are trying to access is connected to the Tailscale network and has the expected IP address.

    tailscale status
    
  3. tailscale ping: Test accessibility by pinging a specific Tailscale IP address or hostname.

    • tailscale ping --tsmp: This command tests basic connectivity between devices using Tailscale's own TSMP protocol and bypasses ACL rules.
    • tailscale ping --icmp (or standard ping command): This command tests end-to-end connectivity and checks whether Tailscale ACL rules are being applied. If TSMP ping is successful but ICMP ping fails, the connection is most likely being blocked by ACL policies.
    tailscale ping homelab-nas --icmp
    
  4. Tailscale Logs: Checking your Tailscale device's logs can provide valuable information about connection attempts and access denied by ACLs. On Linux systems, you can use journalctl -u tailscaled, or on Windows/macOS, use the Tailscale application's own log interface. Denied connections usually appear in logs with messages like "access denied" or "ACL drop".

  5. Access Attempt Details: In the "Access Controls" section of the Tailscale admin panel, you'll find tools like "ACL test" or "Policy checker". You can use these tools to simulate how an access attempt from a specific user to a specific device and port would be evaluated by your ACLs. This helps you understand which rule is blocking or allowing access.

These management and troubleshooting steps provide a roadmap to ensure your ACLs work securely and efficiently.

Conclusion

Providing service-based access control in a homelab environment is one of the most important steps you can take for your network security. Tailscale ACLs allow you to implement this control flexibly and in detail by applying zero-trust principles. By grouping users and devices, restricting access over specific ports, and even protecting local network resources via Subnet Routers, you can ensure that each service in your network is accessible only by authorized individuals.

The basic and advanced ACL configurations, Subnet Router integration, best practices, and troubleshooting methods covered in this guide provide the necessary information to set up a secure homelab environment with Tailscale. Keeping the ACL file under version control, reviewing it regularly, and carefully testing changes are critical for ensuring the long-term security of your network. Remember, security is a dynamic process, and you need to keep your security policies updated with changes in your network.

Official Resources

- tailscale.com

Top comments (0)