Skip to content

Tailscale Networking Overview

Tailscale provides the primary access layer for CWIQ.IO infrastructure — replacing VPN concentrators, bastion hosts, and per-instance SSH key management with identity-based WireGuard mesh networking.


What Tailscale Provides

Tailscale is a zero-configuration mesh VPN built on WireGuard. For CWIQ.IO it delivers:

Capability How Used
Developer SSH access Engineers connect to any server by Tailscale hostname without public IPs or bastion hosts
Cross-VPC service connectivity Services in the dev VPC reach shared-services (Authentik, Vault) via Tailscale mesh
Cross-account access Shared-services servers reach dev servers and vice versa
Managed service access Subnet routers make RDS, ALB, and other AWS managed services reachable from Tailscale clients
Identity-based ACLs Access controlled by user/tag identity, not IP whitelists

Architecture

                     TAILSCALE CONTROL PLANE
                    (Auth, Key Exchange, ACLs)
         ┌────────────────────┼─────────────────────┐
         │                    │                     │
         ▼                    ▼                     ▼
┌──────────────────┐  ┌──────────────────┐  ┌─────────────────┐
│ Shared-Services  │  │   Dev VPC        │  │  Developer      │
│ VPC (10.0.0.0/16)│  │ (10.1.0.0/16)   │  │  Laptops        │
│                  │  │                  │  │  (100.64.x.x)   │
│ Subnet Router    │◄─┼►Subnet Router    │  │                 │
│ 10.0.12.x        │  │ 10.1.40.x        │  │  Tailscale      │
│ (advertises      │  │ (advertises      │  │  client         │
│  10.0.0.0/16)    │  │  10.1.0.0/16)    │  │                 │
└──────────────────┘  └──────────────────┘  └─────────────────┘

Subnet Routers

Each VPC has one EC2 instance running the Tailscale client with subnet routing enabled:

VPC Subnet Router Advertises Subnet
Shared-Services tailscale-shared 10.0.0.0/16 10.0.12.0/26 (vpn-access-1a)
Dev tailscale-dev 10.1.0.0/16 10.1.40.0/26 (vpn-access-1a)

Subnet routers use SNAT mode by default. Traffic from Tailscale clients (100.64.x.x) appears to VPC resources as originating from the router's VPC IP (10.0.12.x or 10.1.40.x). This means VPC security groups only need to allow the router subnet CIDR, not the full Tailscale CGNAT range.


Tailscale vs AWS Native Networking

Is traffic going to/from the public internet?
├── YES → AWS (NAT Gateway, ALB, Internet Gateway)
└── NO → Is source an EKS runner pod?
          ├── YES → VPC peering (pods have no Tailscale)
          └── NO → Tailscale mesh
Scenario Use Why
Developer SSH to any server Tailscale No public IPs, no bastion
Dev server → Authentik SSO Tailscale Cross-VPC, subnet router handles routing
EKS pod → Nexus VPC peering + private Route53 Pods cannot run Tailscale
CI job → dev server (deploy) VPC private IP (10.1.35.46) EKS pods have no Tailscale
Alloy agent → Loki/Prometheus Tailscale hostname Cross-VPC log/metric push
GitLab runner (host) → CI/CD targets Tailscale Host-level Tailscale available

Key Benefits for CWIQ.IO

  1. No bastion hosts — Direct developer access to any server by Tailscale hostname
  2. No per-instance public IPs — All application servers are in private subnets
  3. Cross-VPC without Transit Gateway — Saves ~$88/month vs AWS Transit Gateway
  4. Managed service access — Subnet routers make RDS, ALBs, ElastiCache reachable from Tailscale
  5. ACL-based access controltag:devops gets access to everything; tag:dev-apps gets access to shared-services only

Terraform Management

Tailscale ACLs are managed by the Terraform Tailscale provider in terraform-plan/. Changes to ACLs require: - TAILSCALE_AUTH_KEY from .claude-env - CREATED_BY variable

cd terraform-plan/organization/tailscale
terraform plan -var="tailscale_auth_key=$TAILSCALE_AUTH_KEY" -var="created_by=$CREATED_BY"