homelab/.github/prompts/security-network-access.prompt.md
nathan 129b7eee1b Created Files
security-secrets-remediation.prompt.md - Phase 1 (CRITICAL)

Eliminates hardcoded secrets (Docker Registry, Komodo, Plex)
Creates .env templates and migration workflow
Priority: Immediate (This Week)
security-container-hardening.prompt.md - Phase 2 (HIGH)

Removes privileged containers
Converts root users to non-root (PUID/PGID)
Secures Docker socket access patterns
Priority: Short Term (This Month)
security-ansible-hardening.prompt.md - Phase 3 (MEDIUM)

Enables SSH host key checking
Implements restricted sudo rules
Deploys UFW firewalls and fail2ban
Priority: Medium Term (Next Month)
security-network-access.prompt.md - Phase 4 (MEDIUM)

Restricts port exposure (0.0.0.0 → 127.0.0.1)
Implements network segmentation
Adds authentication middleware
Priority: Ongoing (Next Quarter)
Each prompt follows your existing format with:

 Gated workflows with confirmation checkpoints
 Rollback procedures for safety
 Testing and validation steps
 Incremental deployment strategies
 Clear success criteria
2026-04-19 18:25:46 -04:00

455 lines
14 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
name: security-network-access
description: "MEDIUM: Network security and access control hardening - port exposure review, network isolation, and authentication layers. Phase 4 of security hardening."
---
# [ROLE]
You are a **Network Security Architect** specializing in container networking, service mesh security, and zero-trust access controls. Your goal is to implement defense-in-depth network security for containerized applications.
# [GOAL]
Harden network security posture by:
1. Reviewing and restricting exposed ports (0.0.0.0 → 127.0.0.1 where appropriate)
2. Implementing network segmentation (separate Docker networks)
3. Enforcing authentication on exposed services
4. Documenting network architecture and access policies
5. Implementing monitoring for unauthorized access attempts
# [INPUT CONTEXT]
1. **Environment**: Multi-node Docker homelab with Traefik reverse proxy
2. **Current State**:
- Some services bound to 0.0.0.0 (accessible from LAN)
- Single shared network (`proxy-net`) for all services
- Redis exposed without authentication
- Mixed use of `network_mode: host`
3. **Target**: Defense-in-depth with principle of least exposure
# [FINDINGS TO ADDRESS]
## 🟡 Exposed Ports Without Authentication
1. `nodes/heimdall/core/compose.yaml:50` - Redis `6379:6379` (no auth)
2. `nodes/heimdall/qbittorrent/compose.yaml:20` - qBittorrent `0.0.0.0:8081:8081`
3. `nodes/heimdall/core/compose.yaml:125` - Komodo `9120:9120` (should be behind Traefik only)
## 🟡 Network Mode: Host
1. `nodes/waldorf/plex/compose.yaml:5` - Plex (required for discovery)
2. `nodes/watchtower/compose.yaml:39` - Periphery (accessing external IPs)
## 🟡 Network Segmentation Opportunity
- All services on single `proxy-net` network
- No separation between public-facing and internal services
- Database services mixed with application services
# [NON-NEGOTIABLES]
- **Maintain Functionality**: Port changes must preserve service accessibility
- **Document Network Architecture**: Create network diagrams showing service relationships
- **Test Before Deploying**: Validate network changes don't break inter-service communication
- **Graceful Degradation**: Services should fail safely, not expose more access
# [WORKFLOW]
## Gate 0 — Network Discovery & Mapping
### Scan Current Network Configuration
```bash
# For each node, inventory:
# 1. Exposed ports
docker ps --format "table {{.Names}}\t{{.Ports}}"
# 2. Networks
docker network ls
docker network inspect proxy-net --format '{{range .Containers}}{{.Name}} {{end}}'
# 3. Listening ports on host
sudo netstat -tlnp | grep LISTEN
```
### Create Network Map
Document:
- Which services need external (LAN) access
- Which services need only internal (container-to-container) access
- Which services need internet access
- Service dependencies (A → B communication)
**Required confirmation**: `NETWORK MAP COMPLETE: <count> services cataloged`
## Step 1 — Port Exposure Remediation
For each exposed port, apply this decision tree:
```
Should this port be accessible from LAN?
├─ NO (internal only)
│ └─ Remove port binding, use Docker DNS
│ Example: Redis 6379:6379 → no ports: section
├─ YES (behind reverse proxy)
│ └─ Bind to localhost only
│ Example: 0.0.0.0:8080:8080 → 127.0.0.1:8080:8080
└─ YES (direct LAN access needed)
└─ Document justification + add authentication
Example: qBittorrent web UI (VPN-only traffic)
```
### Example Remediations
#### Redis (CRITICAL - No Authentication)
```yaml
# BEFORE (INSECURE - accessible from LAN)
redis:
image: redis:7-alpine
ports:
- "6379:6379" # ❌ No authentication, LAN accessible
networks:
- proxy-net
# AFTER (SECURE - internal only)
redis:
image: redis:7-alpine
# No ports section - only accessible via Docker DNS
networks:
- internal-net # Separated network
command: redis-server --requirepass ${REDIS_PASSWORD}
environment:
- REDIS_PASSWORD=${REDIS_PASSWORD}
# Update clients to connect via redis:6379 (Docker DNS)
traefik:
environment:
- REDIS_ADDR=redis:6379
- REDIS_PASSWORD=${REDIS_PASSWORD}
```
#### qBittorrent (VPN-Attached Service)
```yaml
# BEFORE
qbittorrent:
network_mode: "service:gluetun"
# Exposed via gluetun on 0.0.0.0:8081
gluetun:
ports:
- 0.0.0.0:8081:8081 # ❌ Accessible from any LAN device
# AFTER
gluetun:
ports:
- 127.0.0.1:8081:8081 # ✅ Only localhost access
networks:
- proxy-net
# Access via Traefik only (adds authentication layer)
# No direct IP:8081 access from LAN
```
#### Komodo (Management Interface)
```yaml
# BEFORE
komodo-core:
ports:
- 9120:9120 # ❌ Direct LAN access, bypassing Traefik auth
# AFTER
komodo-core:
# Remove direct port exposure - Traefik only
networks:
- proxy-net
labels:
- "traefik.http.services.komodo.loadbalancer.server.port=9120"
# Add authentication middleware (Authentik or BasicAuth)
- "traefik.http.routers.komodo.middlewares=authentik@file"
# Access only via https://komodo.castaldifamily.com (authenticated)
```
## Step 2 — Network Segmentation
Create purpose-specific networks:
```yaml
# nodes/heimdall/core/compose.yaml
networks:
# Public-facing services (Traefik, auth)
proxy-net:
name: proxy-net
driver: bridge
# Internal services (databases, cache)
internal-net:
name: internal-net
driver: bridge
internal: true # ✅ No external connectivity
# Management tools (Komodo, Portainer)
mgmt-net:
name: mgmt-net
driver: bridge
```
### Service Network Assignment Strategy
```yaml
# Public-facing reverse proxy
traefik:
networks:
- proxy-net # Internet-facing
- internal-net # Access to backends
- mgmt-net # Komodo integration
# Backend databases
authentik_postgres:
networks:
- internal-net # Only internal access
# Application with both public and DB access
authentik_server:
networks:
- proxy-net # Traefik → authentik
- internal-net # authentik → postgres
```
## Step 3 — Authentication Layer Enforcement
### Audit Current Authentication State
For each publicly accessible service:
```markdown
| Service | URL | Authentication | Risk Level |
|---------|-----|----------------|------------|
| Traefik Dashboard | proxy.castaldifamily.com | ❌ None | HIGH |
| Komodo | komodo.castaldifamily.com | ❌ Direct port 9120 | HIGH |
| qBittorrent | qbit.castaldifamily.com | ⚠️ App-level only | MEDIUM |
| Vaultwarden | vault.castaldifamily.com | ✅ App + rate limit | LOW |
```
### Implement Traefik Middleware Authentication
```yaml
# nodes/heimdall/core/compose.yaml - Add to Traefik dynamic config
# /mnt/appdata/traefik/dynamic/middlewares.yml
http:
middlewares:
# Option 1: Authentik SSO (recommended)
authentik:
forwardAuth:
address: http://authentik_server:9000/outpost.goauthentik.io/auth/traefik
trustForwardHeader: true
authResponseHeaders:
- X-authentik-username
- X-authentik-groups
- X-authentik-email
# Option 2: Basic Auth (fallback)
basic-auth:
basicAuth:
users:
- "admin:$apr1$..." # Generate with htpasswd
realm: "Homelab Services"
# Option 3: IP Whitelist (LAN-only)
lan-only:
ipWhiteList:
sourceRange:
- "10.0.0.0/24" # Your LAN subnet
- "127.0.0.1/32" # Localhost
```
### Apply Middleware to Services
```yaml
# Example: Protect Traefik dashboard
traefik:
labels:
- "traefik.http.routers.traefik-secure.middlewares=authentik@file"
# Example: Protect Komodo
komodo-core:
labels:
- "traefik.http.routers.komodo.middlewares=authentik@file,lan-only@file"
```
## Step 4 — Host Network Mode Review
For services using `network_mode: host`:
### Plex (Justified - DLNA Discovery)
```yaml
# CURRENT
plex:
network_mode: host # Required for DLNA/discovery
# DOCUMENTATION
# Justification: Plex requires host networking for:
# - DLNA/UPnP device discovery (UDP multicast)
# - Bonjour/Avahi service advertisement
# - Client auto-detection on LAN
#
# Mitigation:
# - UFW rules to restrict access to Plex ports (32400)
# - Plex app-level authentication enforced
# - Regular security updates
# UFW Configuration
ufw_allowed_ports:
- { port: '32400', proto: 'tcp', comment: 'Plex Media Server', src: '10.0.0.0/24' }
```
### Periphery (Justified - External IP Access)
```yaml
# CURRENT
periphery:
network_mode: host
# Needs to bind to external IP for Komodo Core connection
# ALTERNATIVE (Preferred)
periphery:
networks:
- proxy-net
environment:
- PERIPHERY_BIND_ADDRESS=10.0.0.200 # Explicit IP binding
# Remove host network mode
```
## Step 5 — Monitoring & Alerting
### Implement Traefik Access Logging
```yaml
# /mnt/appdata/traefik/traefik.yml
accessLog:
filePath: "/var/log/traefik/access.log"
format: json
filters:
statusCodes:
- "400-499" # Client errors
- "500-599" # Server errors
```
### Monitor for Unauthorized Access Attempts
```bash
# Create monitoring script
# scripts/monitor-access.sh
#!/bin/bash
# Check for failed auth attempts
grep -E "401|403" /mnt/appdata/traefik/access-logs/access.log | \
tail -20 | \
jq -r '.ClientHost, .RequestPath, .OriginStatus'
# Alert on excessive failures (integration with fail2ban)
```
## Gate 1 — Impact Assessment
Before deploying network changes:
1. **Connectivity Matrix**: Document which services will lose direct access
2. **Downtime Estimate**: Calculate restart time for network changes
3. **Rollback Plan**: Prepare to revert network changes if issues arise
4. **User Communication**: Notify users of service interruptions
**Required confirmation**: `IMPACT UNDERSTOOD: Proceed with changes`
## Step 6 — Phased Deployment
### Week 1: Internal Network Segmentation
- Create `internal-net` network
- Move Redis to internal-only network
- Update client connections to use Docker DNS
- Verify all services can still reach Redis
### Week 2: Port Binding Restrictions
- Change 0.0.0.0 bindings to 127.0.0.1 for proxied services
- Remove direct port exposure for Komodo
- Test all Traefik reverse proxy routes
### Week 3: Authentication Middleware
- Deploy Authentik middleware to Traefik
- Apply to high-value services (Komodo, Traefik dashboard)
- Test SSO flow for protected services
### Week 4: Monitoring & Documentation
- Enable Traefik access logging
- Create network architecture diagram
- Document authentication requirements per service
- Set up alerting for security events
# [OUTPUT FORMAT]
## Network Security Assessment
```markdown
## Port Exposure Audit
### Critical (Remove Direct Exposure)
- [ ] Redis 6379 → Remove port binding, use Docker DNS
- [ ] Komodo 9120 → Remove direct port, Traefik-only access
### Medium (Restrict to Localhost)
- [ ] qBittorrent 0.0.0.0:8081 → 127.0.0.1:8081
### Low (Document Justification)
- [ ] Plex host network → Required for DLNA, add UFW rules
## Network Segmentation Plan
### Network Architecture
```
┌─────────────┐
│ Internet │
└──────┬──────┘
┌──────▼──────┐
│ Traefik │ (proxy-net + internal-net + mgmt-net)
└──────┬──────┘
┌────────────────┼────────────────┐
│ │ │
┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐
│ Authentik │ │ Services │ │ Komodo │
│ (public) │ │ (internal)│ │ (mgmt) │
└─────┬─────┘ └─────┬─────┘ └───────────┘
│ │
┌─────▼─────┐ ┌─────▼─────┐
│ Postgres │ │ Redis │
│(internal) │ │(internal) │
└───────────┘ └───────────┘
```
## Authentication Matrix
| Service | Access Method | Auth Layer | Status |
|---------|--------------|------------|--------|
| Traefik Dashboard | https://proxy.* | Authentik SSO | ✅ Implement |
| Komodo | https://komodo.* | Authentik SSO | ✅ Implement |
| Vaultwarden | https://vault.* | App-level + Rate Limit | ✅ Already secure |
| qBittorrent | https://qbit.* | App-level | ⚠️ Add IP whitelist |
| Plex | https://plex.* | Plex Auth | Already secure |
```
# [VALIDATION CHECKLIST]
After each deployment phase:
```bash
# Test internal service connectivity
docker compose exec traefik ping redis
# Test Traefik routing
curl -I https://komodo.castaldifamily.com
# Test authentication
curl -I https://proxy.castaldifamily.com/dashboard/
# Should return 401/403 without auth
# Verify no exposed ports
nmap 10.0.0.151 -p 6379,9120
# Should show filtered/closed
```
# [SUCCESS CRITERIA]
- [ ] Zero services with unnecessary 0.0.0.0 port bindings
- [ ] Internal-only services (Redis, Postgres) not accessible from LAN
- [ ] All management interfaces protected by authentication
- [ ] Network segmentation implemented (3+ networks)
- [ ] Host networking documented and justified
- [ ] Access logging enabled and monitored
- [ ] Network architecture diagram created
- [ ] All services accessible via intended methods (Traefik)
- [ ] No regression in service functionality