Skip to content

Security Groups

CWIQ.IO uses centralized shared security groups (Tailscale, NAT) applied to all instances, supplemented by application-specific groups only when inter-service communication requires it.


Design Philosophy

Every EC2 instance receives two shared security groups created centrally in environments/<env>/security-groups/:

Shared SG Name Pattern Purpose
Tailscale <env>-tailscale-sg WireGuard mesh connectivity, developer SSH via Tailscale
NAT Gateway <env>-nat-gateway-sg Outbound internet access through NAT

Application-specific security groups are only created when an application must accept traffic from another specific service. For anything accessible only via Tailscale, the shared groups are sufficient.


Shared Security Groups

Tailscale SG (<env>-tailscale-sg)

Allows WireGuard UDP traffic and inbound connections from the Tailscale mesh. Applied to every EC2 instance — enables developer SSH and cross-server communication without public exposure.

NAT Gateway SG (<env>-nat-gateway-sg)

Allows outbound internet egress through the VPC NAT Gateway. Applied to all instances in private subnets needing package downloads, API calls to external services, or GitLab registry pushes.


Application-Specific Security Groups

Created inside each EC2 module (ec2-instances/<app>/security-groups.tf or security.tf) only when needed.

GitLab ALB SG (shared-gitlab-alb-sg)

Purpose: Internet-facing ALB in front of GitLab.

Direction Protocol Port Source Description
Ingress TCP 443 0.0.0.0/0 HTTPS from internet
Ingress TCP 80 0.0.0.0/0 HTTP redirect to HTTPS
Egress All All 0.0.0.0/0 Forward to GitLab instance

GitLab Application SG (shared-gitlab-sg)

Purpose: GitLab EC2 instance, sits behind the ALB.

Direction Protocol Port Source Description
Ingress TCP 80 shared-gitlab-alb-sg HTTP from ALB only
Ingress TCP 443 100.64.0.0/10 HTTPS from Tailscale clients
Ingress TCP 2222 100.64.0.0/10 SSH Git via Tailscale
Egress All All 0.0.0.0/0 All outbound

Authentik NLB SG (shared-authentik-nlb-sg)

Purpose: Network Load Balancer for Authentik HA pair. Accepts traffic from Tailscale subnet router CIDR (SNAT mode).

Direction Protocol Port Source Description
Ingress TCP 443 10.0.12.0/26 HTTPS from Tailscale subnet router
Ingress TCP 80 10.0.12.0/26 HTTP from Tailscale subnet router

Nexus Docker Registry SG (shared-nexus-registry-sg)

Purpose: Expose Docker registry ports (8443 push, 8444 pull) to EKS runner pods via VPC peering.

Direction Protocol Port Source Description
Ingress TCP 8443 10.1.0.0/16 Docker push from dev VPC (runners)
Ingress TCP 8444 10.1.0.0/16 Docker pull from dev VPC (runners)

SonarQube SG (shared-sonarqube-sg)

Purpose: Allow EKS runner pods to reach SonarQube over VPC peering without Tailscale.

Direction Protocol Port Source Description
Ingress TCP 9000 10.1.0.0/16 SonarQube API from dev VPC

Vault SG (shared-vault-sg)

Purpose: Vault API access for CI/CD JWT authentication (EKS pods reach Vault via VPC peering).

Direction Protocol Port Source Description
Ingress TCP 8200 10.1.0.0/16 Vault API from dev VPC
Ingress TCP 8200 100.64.0.0/10 Vault API from Tailscale clients

EKS Cluster Security Group

EKS runner pods get VPC CNI IPs in the 10.1.34.x/10.1.35.x subnets. The cluster security group must permit:

  • Outbound to 10.0.0.0/16 (shared-services VPC, for GitLab server, Vault, Nexus, SonarQube)
  • Outbound to 10.1.35.46 port 22 (SSH deploy-dev jobs reaching the orchestrator server)
  • Inbound from ALB health check IPs (if using internal ALB for runners)

When to Create an Application-Specific SG

Situation Action
App accessible only via Tailscale Use shared SGs only
App behind a public ALB Create ALB SG + app SG (ALB → app only)
App must accept traffic from EKS pods (no Tailscale) Create app SG with source CIDR 10.1.0.0/16
App must accept traffic from another specific service SG Create app SG referencing the source SG
Background worker, no inbound Use shared SGs only

Terraform Location

terraform-plan/organization/environments/
├── shared-services/
│   ├── security-groups/      ← shared SGs (tailscale, nat-gateway)
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   └── outputs.tf
│   └── ec2-instances/
│       ├── gitlab/
│       │   └── security-groups.tf  ← ALB SG + app SG
│       ├── nexus/
│       │   └── security-groups.tf  ← registry port SG
│       └── ...
└── dev/
    ├── security-groups/      ← shared SGs
    └── ec2-instances/
        └── ...