Skip to content

[User Story] Proxy Access Control (Lockdown) #171

@noahwhite

Description

@noahwhite

Story Summary

As a Security Engineer, I want to restrict proxy access to specific Linux users and time windows, so that a compromised application container cannot query the proxy for administrative secrets.

Phase: 3 - Hardened Ongoing Maintenance


✅ Acceptance Criteria

  • iptables/nftables rules restrict which users can reach Aembit proxy (port 8080)
  • Only root and backup users can query the proxy
  • Docker containers cannot directly query proxy (network namespace isolation)
  • Aembit policy denies R2 secret requests outside 2:00 AM - 3:00 AM window
  • Application secrets (MySQL, mail) available 24/7 to bootstrap service only
  • Audit log shows denied requests from unauthorized sources

📝 Additional Context

Threat Model

Threat Mitigation
Compromised Ghost container queries proxy Network namespace isolation - containers can't reach host localhost
Attacker gets non-root shell iptables owner match - only root/backup can reach port 8080
Attacker queries backup creds at wrong time Aembit time-based policy - R2 creds only available 2-3 AM
Attacker queries app secrets Secrets only fetched at boot by root bootstrap service

iptables Rules

# /opt/bin/setup-proxy-firewall.sh

# Allow root to access proxy
iptables -A OUTPUT -p tcp --dport 8080 -m owner --uid-owner 0 -j ACCEPT

# Allow backup user to access proxy
iptables -A OUTPUT -p tcp --dport 8080 -m owner --uid-owner backup -j ACCEPT

# Deny all other local access to proxy
iptables -A OUTPUT -p tcp --dport 8080 -d 127.0.0.1 -j DROP

Butane Configuration

systemd:
  units:
    - name: proxy-firewall.service
      enabled: true
      contents: |
        [Unit]
        Description=Configure Aembit proxy access firewall
        After=network.target
        Before=aembit-proxy.service
        
        [Service]
        Type=oneshot
        RemainAfterExit=yes
        ExecStart=/opt/bin/setup-proxy-firewall.sh
        
        [Install]
        WantedBy=multi-user.target

Aembit Time-Based Policy

resource "aembit_access_policy" "backup_r2" {
  client_workload_id     = aembit_client_workload.ghost_dev.id
  credential_provider_id = aembit_credential_provider.r2_backup.id
  
  # Time-based condition
  conditions {
    time_window {
      start_time = "02:00"
      end_time   = "03:00"
      timezone   = "UTC"
      days       = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]
    }
  }
}

resource "aembit_access_policy" "app_secrets" {
  client_workload_id     = aembit_client_workload.ghost_dev.id
  credential_provider_id = aembit_credential_provider.app_secrets.id
  
  # No time restriction - available for boot-time bootstrap
  # But only root can reach proxy (enforced by iptables)
}

Docker Network Isolation

Docker containers use their own network namespace. By default, localhost inside a container refers to the container's loopback, not the host's. This provides natural isolation.

To verify:

# From host - should work (as root)
curl http://localhost:8080/health

# From container - should fail (different network namespace)
docker exec ghost curl http://localhost:8080/health
# curl: (7) Failed to connect to localhost port 8080: Connection refused

Defense in Depth Layers

Layer 1: Network Namespace
    └─► Containers can't reach host localhost

Layer 2: iptables Owner Match
    └─► Only root/backup users can reach port 8080

Layer 3: Aembit Time-Based Policy
    └─► R2 creds only available 2-3 AM

Layer 4: Aembit Audit Logging
    └─► All access attempts logged

Dependencies

  • GHO-70: JIT backup credentials (defines what needs time restriction)

📦 Definition of Ready

  • Acceptance criteria defined
  • Blocked by GHO-70 (JIT backup credentials)
  • Story is estimated
  • Team has necessary skills and access
  • Priority is clear
  • Business value understood

✅ Definition of Done

  • All acceptance criteria met
  • iptables rules deployed and verified
  • Non-root user cannot reach proxy (tested)
  • Container cannot reach proxy (tested)
  • R2 creds denied outside time window (tested)
  • Aembit audit logs show denied attempts
  • Security documentation updated

Metadata

Metadata

Assignees

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions