Securely Access Your CrowdSec Manager Anywhere Using Tailscale (and Lock It Down with ACLs)

Securely Access Your CrowdSec Manager Anywhere Using Tailscale (and Lock It Down with ACLs)

why tailscale

  • Backup Stratagy: Even if pangolin goes down and you don’t have immediate access to your computer you can restart and diagnose pangolin and get your home access back..

If you are running CrowdSec in a Docker environment, you already know how vital it is for securing your infrastructure. But when it comes to checking your manager dashboard or logs, you face a common dilemma: how do you access it remotely without opening vulnerable ports to the public internet?

The answer is Tailscale.

By using a “Sidecar” pattern in Docker Compose, we can seamlessly attach a CrowdSec manager container directly to your private Tailscale network (Tailnet). This gives you secure, encrypted access to your container from any device in the world, while perfectly preserving your local network routing and Traefik configurations.

Here is exactly how to set it up—and how to lock it down using strict Role-Based Access Control (RBAC).


Part 1: The Docker Compose Configuration

Prerequisites

Before diving into the Compose file, you will need:

  1. Docker and Docker Compose installed on your host.
  2. A free Tailscale account.
  3. A Tailscale Auth Key (Generate a reusable, non-expiring key in your Tailscale Admin console under Settings > Keys).

Deploying the Tailscale Sidecar

The magic of this setup lies in the network_mode: service:tailscale directive. Instead of putting our CrowdSec manager on the standard Docker network, we are hiding it behind a dedicated Tailscale container.

Here is the docker-compose.yml file you need:

services:
  # 1. The Tailscale Sidecar
  tailscale:
    image: tailscale/tailscale:latest
    container_name: tailscale-crowdsec
    hostname: crowdsec-manager-ts # This name appears in your Tailscale dashboard
    environment:
      - TS_AUTHKEY=tskey-auth-xxxxx # Replace with your actual Auth Key!
      - TS_STATE_DIR=/var/lib/tailscale
    volumes:
      - tailscale-data:/var/lib/tailscale
      - /dev/net/tun:/dev/net/tun
    cap_add:
      - net_admin
      - sys_module
    ports:
      - "127.0.0.1:8080:8080" # Preserves safe localhost access on the host
    networks:
      pangolin:
        aliases:
          - crowdsec-manager # Crucial: Allows Traefik/other containers to route traffic here
    restart: unless-stopped

  # 2. Your CrowdSec Manager
  crowdsec-manager:
    image: hhftechnology/crowdsec-manager:latest
    container_name: crowdsec-manager
    network_mode: service:tailscale # Merges this container's network with Tailscale
    depends_on:
      - tailscale
    restart: unless-stopped
    environment:
      - PORT=8080
      - ENVIRONMENT=production
      - TRAEFIK_DYNAMIC_CONFIG=/etc/traefik/dynamic_config.yml
      - TRAEFIK_CONTAINER_NAME=traefik
      - TRAEFIK_STATIC_CONFIG=/etc/traefik/traefik_config.yml
      - CROWDSEC_METRICS_URL=http://crowdsec:6060/metrics
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /root/config:/app/config
      - /root/docker-compose.yml:/app/docker-compose.yml
      - ./backups:/app/backups
      - ./data:/app/data

networks:
  pangolin:
    external: true

volumes:
  tailscale-data:

Why We Did It This Way

  • Backup Stratagy: Even if pangolin goes down and you don’t have immediate access to your computer you can restart and diagnose pangolin and get your home access back..
  • Zero Open Ports: Your CrowdSec manager is completely invisible to the public internet. It only talks to Tailscale.
  • No Broken Routing: By giving the Tailscale container the network alias crowdsec-manager, other containers on your pangolin network (like Traefik) can still talk to it using the hostname they always have. Nothing breaks.
  • Persistent Authentication: The tailscale-data volume ensures that when you restart or update your containers, your node doesn’t forget its Tailscale identity.

How to Access Your Container

Once you run docker-compose up -d, your container will join your Tailnet. You now have three distinct ways to access it:

  1. From Anywhere in the World (via Tailscale): Navigate to the MagicDNS name: http://crowdsec-manager-ts:8080
  2. From the Local Server (Localhost): The port mapping in the Compose file specifically binds to your local loopback address: http://127.0.0.1:8080
  3. From Inside Docker: Other containers use the internal Docker network alias: http://crowdsec-manager:8080

Part 2: Advanced Security - Hardening Access with Tailscale ACLs

If you are running a multi-user Tailnet (such as a shared homelab or a corporate team environment), a “default-allow” policy isn’t enough. You need to restrict exactly who can access your CrowdSec manager.

Tailscale manages network traffic rules using Access Control Lists (ACLs) defined in HuJSON. To strictly control access to the CrowdSec container, we will transition from identity-based human access to Role-Based Access Control (RBAC) using Tailscale groups and tags.

Step 1: Conceptualizing the Access Model

To enforce the principle of least privilege, we must implement the following architecture:

  1. Groups: Define a specific group of human users (e.g., group:secops) authorized to view the dashboard.
  2. Tags: Servers and containers should not authenticate as human users. We will assign a machine tag (tag:crowdsec) to the Docker container.
  3. Policies: Write a strict ACL rule that explicitly permits traffic only from group:secops to tag:crowdsec on port 8080.

Step 2: Preparing the Tailscale Auth Key and Tags

Before modifying the ACLs, we need to ensure the CrowdSec Tailscale sidecar is properly tagged.

  1. Go to the Access Controls page in your Tailscale Admin Console.
  2. Define the tag owner so your security team has the authority to assign it:
"tagOwners": {
    "tag:crowdsec": ["group:secops"]
},

  1. Generate a new Auth Key in the Tailscale dashboard, and explicitly apply the tag:crowdsec tag to the key during creation.
  2. Replace the TS_AUTHKEY in your docker-compose.yml with this new tagged key. When the container boots, it identifies to the control plane as a tagged machine rather than inheriting the identity of the user who created the key.

Step 3: Defining the ACL Rules (HuJSON)

Navigate to your Tailscale Admin Console’s Access Controls tab. Below is the required HuJSON configuration to lock down the container:

{
  // 1. Define your administrative groups
  "groups": {
    "group:secops": [
      "admin.user@yourdomain.com",
      "auditor@yourdomain.com"
    ]
  },

  // 2. Define who is allowed to deploy infrastructure with specific tags
  "tagOwners": {
    "tag:crowdsec": ["group:secops"]
  },

  // 3. Define the routing rules (ACLs)
  "acls": [
    // Enforce explicit access: Only SecOps can hit the CrowdSec dashboard via port 8080
    {
      "action": "accept",
      "src":    ["group:secops"],
      "dst":    ["tag:crowdsec:8080"]
    },
    
    // (Optional) Permit the CrowdSec manager to initiate outbound connections to the internet 
    // via an exit node, or to other internal services for log ingestion over Tailscale.
    {
      "action": "accept",
      "src":    ["tag:crowdsec"],
      "dst":    ["autogroup:internet:*"]
    }
  ]
}

Technical Breakdown of the ACL Rule

  • "action": "accept": Tailscale operates on a default-deny paradigm once strict rules are applied. You only write accept rules.
  • "src": ["group:secops"]: Because this is bound to a group, Tailscale’s control plane will verify the cryptographic identity of the source node against the user’s current session state.
  • "dst": ["tag:crowdsec:8080"]: This explicitly binds the rule to the Layer 4 port (8080). Even if a user in the secops group attempts to hit port 22 (SSH) or 80, the control plane’s packet filter will silently drop the packets.

Step 4: Verification

Once applied, Tailscale pushes the updated packet filtering rules to all nodes almost instantly via the WireGuard tunnels.

  • If a user not in group:secops attempts to navigate to http://crowdsec-manager-ts:8080, the TCP connection will immediately time out.
  • Your local machine interactions (e.g., hitting 127.0.0.1:8080 from the host OS) remain entirely unaffected, as that traffic routes through the local Linux network namespace, bypassing the Tailscale WireGuard interface entirely.

Wrapping Up

By deploying Tailscale as a sidecar and enforcing strict ACLs, you get the absolute best of both worlds: robust local network compatibility and locked-down, zero-trust remote access. Spin it up, connect your devices, and enjoy highly secure access to your infrastructure from anywhere!

can I do 127.0.0.1:7080:8080 ? as I am running vps-bouncer and my original crowdsec is on 127.0.0.1:8080:8080 in pangolin docker-compose.yaml