Skip to content

Latest commit

 

History

History
547 lines (450 loc) · 16.4 KB

File metadata and controls

547 lines (450 loc) · 16.4 KB

OpenHands AWS Isolated Environment - Technical Implementation Guide

Architecture Overview

Network Architecture

┌─────────────────────────────────────────────────────────────────┐
│                        AWS VPC (10.0.0.0/16)                   │
│                                                                 │
│  ┌─────────────────────┐    ┌─────────────────────────────────┐ │
│  │   Public Subnet     │    │      Private Subnet             │ │
│  │   (10.0.0.0/24)     │    │      (10.0.1.0/24)             │ │
│  │                     │    │                                 │ │
│  │  ┌───────────────┐  │    │  ┌─────────────────────────────┐│ │
│  │  │  Web Proxy    │  │    │  │    OpenHands Server         ││ │
│  │  │  - Nginx      │  │    │  │    - OpenHands App          ││ │
│  │  │  - SSL Term   │◄─┼────┼──┤    - Docker                 ││ │
│  │  │  - Basic Auth │  │    │  │    - Python Environment     ││ │
│  │  └───────────────┘  │    │  └─────────────────────────────┘│ │
│  │         │            │    │              │                  │ │
│  └─────────┼────────────┘    └──────────────┼──────────────────┘ │
│            │                                │                    │
│  ┌─────────▼────────────┐    ┌──────────────▼──────────────────┐ │
│  │  Internet Gateway    │    │         NAT Gateway             │ │
│  └──────────────────────┘    └─────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
                │                                │
                ▼                                ▼
        ┌───────────────┐                ┌─────────────────┐
        │   Internet    │                │  LLM Endpoints  │
        │   (Users)     │                │  (OpenAI, etc.) │
        └───────────────┘                └─────────────────┘

Security Layers

┌─────────────────────────────────────────────────────────────────┐
│                     Security Architecture                       │
├─────────────────────────────────────────────────────────────────┤
│ Layer 1: AWS Security Groups (Application Firewall)            │
│ Layer 2: Network ACLs (Subnet-level Controls)                  │
│ Layer 3: Host-level iptables (Packet Filtering)                │
│ Layer 4: Application Authentication (Basic Auth + SSL)         │
│ Layer 5: System-level Access Controls (Linux Users)            │
└─────────────────────────────────────────────────────────────────┘

Technical Specifications

Infrastructure Components

Component Specification Purpose
VPC 10.0.0.0/16 Network isolation
Public Subnet 10.0.0.0/24 Web proxy hosting
Private Subnet 10.0.1.0/24 OpenHands server hosting
Internet Gateway Standard Public internet access
NAT Gateway Standard Controlled outbound access
Web Proxy t3.small, Ubuntu 22.04 Reverse proxy, SSL termination
OpenHands Server t3.large, Ubuntu 22.04 AI assistant hosting

Security Group Configurations

Web Proxy Security Group (openhands-web-proxy-sg)

Inbound Rules:

Port 22  (SSH)   ← Your IP only
Port 80  (HTTP)  ← Your IP (or 0.0.0.0/0 for broader access)
Port 443 (HTTPS) ← Your IP (or 0.0.0.0/0 for broader access)

Outbound Rules:

Port 22   → 10.0.1.0/24 (SSH to OpenHands server)
Port 3000 → 10.0.1.0/24 (OpenHands web interface)
Port 443  → 0.0.0.0/0   (SSL certificates, updates)

OpenHands Server Security Group (openhands-server-sg)

Inbound Rules:

Port 22   ← openhands-web-proxy-sg (SSH from proxy)
Port 3000 ← openhands-web-proxy-sg (Web interface)

Outbound Rules:

Port 443 → 0.0.0.0/0     (HTTPS - restricted by iptables)
Port 53  → 10.0.0.0/16   (DNS to VPC resolver)
Port 123 → 0.0.0.0/0     (NTP time sync)

Step-by-Step Implementation

Step 1: VPC and Network Setup

1.1 Create VPC

# AWS Console: VPC → Create VPC
Name: openhands-isolated-vpc
IPv4 CIDR: 10.0.0.0/16
IPv6 CIDR: No IPv6 CIDR block
Tenancy: Default

1.2 Create Subnets

# Public Subnet
Name: openhands-public-subnet
VPC: openhands-isolated-vpc
Availability Zone: us-west-2a (or your preferred AZ)
IPv4 CIDR: 10.0.0.0/24

# Private Subnet
Name: openhands-private-subnet
VPC: openhands-isolated-vpc
Availability Zone: us-west-2a
IPv4 CIDR: 10.0.1.0/24

1.3 Create and Attach Internet Gateway

# AWS Console: VPC → Internet Gateways
Name: openhands-igw
Attach to VPC: openhands-isolated-vpc

1.4 Create NAT Gateway

# AWS Console: VPC → NAT Gateways
Name: openhands-nat-gw
Subnet: openhands-public-subnet
Connectivity type: Public
Elastic IP allocation: Create new EIP

1.5 Configure Route Tables

# Public Route Table
Name: openhands-public-rt
Routes:
  - 10.0.0.0/16 → Local
  - 0.0.0.0/0 → openhands-igw
Associate with: openhands-public-subnet

# Private Route Table
Name: openhands-private-rt
Routes:
  - 10.0.0.0/16 → Local
  - 0.0.0.0/0 → openhands-nat-gw
Associate with: openhands-private-subnet

Step 2: Security Groups Configuration

2.1 Web Proxy Security Group

# AWS Console: EC2 → Security Groups → Create
Name: openhands-web-proxy-sg
Description: Security group for OpenHands web proxy
VPC: openhands-isolated-vpc

# Inbound Rules
Type: SSH, Protocol: TCP, Port: 22, Source: My IP
Type: HTTP, Protocol: TCP, Port: 80, Source: My IP
Type: HTTPS, Protocol: TCP, Port: 443, Source: My IP

# Outbound Rules (remove default, add these)
Type: SSH, Protocol: TCP, Port: 22, Destination: 10.0.1.0/24
Type: Custom TCP, Protocol: TCP, Port: 3000, Destination: 10.0.1.0/24
Type: HTTPS, Protocol: TCP, Port: 443, Destination: 0.0.0.0/0

2.2 OpenHands Server Security Group

# AWS Console: EC2 → Security Groups → Create
Name: openhands-server-sg
Description: Security group for isolated OpenHands server
VPC: openhands-isolated-vpc

# Inbound Rules
Type: SSH, Protocol: TCP, Port: 22, Source: openhands-web-proxy-sg
Type: Custom TCP, Protocol: TCP, Port: 3000, Source: openhands-web-proxy-sg

# Outbound Rules (remove default, add these)
Type: HTTPS, Protocol: TCP, Port: 443, Destination: 0.0.0.0/0
Type: DNS (UDP), Protocol: UDP, Port: 53, Destination: 10.0.0.0/16
Type: NTP, Protocol: UDP, Port: 123, Destination: 0.0.0.0/0

Step 3: EC2 Instance Deployment

3.1 Create Key Pair

# AWS Console: EC2 → Key Pairs → Create
Name: openhands-keypair
Key pair type: RSA
Private key file format: .pem
# Download and secure the .pem file

3.2 Launch Web Proxy Instance

Instance Configuration:

Name: openhands-web-proxy
AMI: Ubuntu Server 22.04 LTS (ami-0c2d3e23b7e8a4b8d)
Instance type: t3.small
Key pair: openhands-keypair
VPC: openhands-isolated-vpc
Subnet: openhands-public-subnet
Auto-assign public IP: Enable
Security groups: openhands-web-proxy-sg

User Data Script:

#!/bin/bash
apt-get update && apt-get upgrade -y

# Install packages
apt-get install -y nginx certbot python3-certbot-nginx fail2ban apache2-utils ufw

# Configure firewall
ufw allow 22 && ufw allow 80 && ufw allow 443 && ufw --force enable

# Create user
useradd -m -s /bin/bash openhands
echo "openhands:$(openssl rand -base64 32)" | chpasswd
echo "openhands:$(openssl rand -base64 32)" | tee -a /var/log/setup.log

# Create htpasswd
htpasswd -cb /etc/nginx/.htpasswd openhands $(openssl rand -base64 32)

# Nginx configuration
cat > /etc/nginx/sites-available/openhands << 'EOF'
server {
    listen 80;
    server_name _;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name _;
    
    ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
    ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    
    auth_basic "OpenHands Access";
    auth_basic_user_file /etc/nginx/.htpasswd;
    
    location / {
        proxy_pass http://OPENHANDS_PRIVATE_IP:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
        
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }
}
EOF

# Create SSL certificate
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
    -keyout /etc/ssl/private/nginx-selfsigned.key \
    -out /etc/ssl/certs/nginx-selfsigned.crt \
    -subj "/C=US/ST=State/L=City/O=Organization/CN=localhost"

# Update script
cat > /root/update_openhands_ip.sh << 'EOF'
#!/bin/bash
if [ "$1" ]; then
    sed -i "s/OPENHANDS_PRIVATE_IP/$1/g" /etc/nginx/sites-available/openhands
    ln -sf /etc/nginx/sites-available/openhands /etc/nginx/sites-enabled/
    rm -f /etc/nginx/sites-enabled/default
    nginx -t && systemctl reload nginx
    echo "Updated OpenHands IP to $1"
fi
EOF
chmod +x /root/update_openhands_ip.sh

# Configure fail2ban
systemctl enable fail2ban nginx
systemctl start fail2ban nginx

3.3 Launch OpenHands Server Instance

Instance Configuration:

Name: openhands-server
AMI: Ubuntu Server 22.04 LTS
Instance type: t3.large
Key pair: openhands-keypair
VPC: openhands-isolated-vpc
Subnet: openhands-private-subnet
Auto-assign public IP: Disable
Security groups: openhands-server-sg

User Data Script:

#!/bin/bash
set -e

# Update system
apt-get update && apt-get upgrade -y

# Install packages
apt-get install -y python3 python3-pip python3-venv nodejs npm docker.io \
    docker-compose git curl wget ufw iptables-persistent dnsutils fail2ban

# Create user
useradd -m -s /bin/bash openhands
echo "openhands:$(openssl rand -base64 32)" | chpasswd
usermod -aG docker,sudo openhands

# Configure firewall
ufw --force reset
ufw default deny incoming && ufw default deny outgoing
ufw allow from 10.0.0.0/24 to any port 22
ufw allow from 10.0.0.0/24 to any port 3000
ufw allow out 443 && ufw allow out 80
ufw allow out to 10.0.0.2 port 53
ufw allow out 123
ufw enable

# Start Docker
systemctl enable docker && systemctl start docker

# Install OpenHands
cd /home/openhands
git clone https://github.com/All-Hands-AI/OpenHands.git
chown -R openhands:openhands OpenHands

# Setup as openhands user
sudo -u openhands bash << 'EOSU'
cd /home/openhands/OpenHands
python3 -m venv venv
source venv/bin/activate
pip install -e .

mkdir -p /home/openhands/.openhands
cat > /home/openhands/.openhands/config.toml << 'EOF'
[core]
workspace_base = "/home/openhands/workspace"
persist_sandbox = false

[llm]
model = "gpt-4"
api_key = "your-api-key-here"
base_url = "https://api.openai.com/v1"

[agent]
memory_enabled = true

[security]
security_analyzer = "default"
allow_file_uploads = false
restrict_file_types = true

[server]
host = "0.0.0.0"
port = 3000
EOF

mkdir -p /home/openhands/workspace
EOSU

# Create startup script
cat > /home/openhands/start_openhands.sh << 'EOF'
#!/bin/bash
cd /home/openhands/OpenHands
source venv/bin/activate

if [ -z "$OPENAI_API_KEY" ]; then
    echo "Error: OPENAI_API_KEY not set"
    exit 1
fi

python -m openhands.server.listen --host 0.0.0.0 --port 3000
EOF
chmod +x /home/openhands/start_openhands.sh
chown openhands:openhands /home/openhands/start_openhands.sh

# Create systemd service
cat > /etc/systemd/system/openhands.service << 'EOF'
[Unit]
Description=OpenHands AI Assistant
After=network.target docker.service
Requires=docker.service

[Service]
Type=simple
User=openhands
Group=openhands
WorkingDirectory=/home/openhands/OpenHands
Environment=OPENAI_API_KEY=your-api-key-here
ExecStart=/home/openhands/start_openhands.sh
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload

# Network restriction script
cat > /home/openhands/restrict_network.sh << 'EOF'
#!/bin/bash
# Restrict to LLM endpoints only
OPENAI_IPS=$(dig +short api.openai.com | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$')

sudo iptables -F OUTPUT
sudo iptables -P OUTPUT DROP
sudo iptables -A OUTPUT -o lo -j ACCEPT
sudo iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A OUTPUT -d 10.0.0.2 -p udp --dport 53 -j ACCEPT
sudo iptables -A OUTPUT -p udp --dport 123 -j ACCEPT

for ip in $OPENAI_IPS; do
    sudo iptables -A OUTPUT -d $ip -p tcp --dport 443 -j ACCEPT
done

sudo iptables-save > /etc/iptables/rules.v4
echo "Network restrictions applied"
EOF
chmod +x /home/openhands/restrict_network.sh
chown openhands:openhands /home/openhands/restrict_network.sh

echo "Setup complete - configure API key and start service"

Step 4: Configuration and Testing

4.1 Configure Web Proxy

# SSH to web proxy
ssh -i openhands-keypair.pem ubuntu@<WEB_PROXY_PUBLIC_IP>

# Update with OpenHands server private IP
sudo /root/update_openhands_ip.sh <OPENHANDS_PRIVATE_IP>

4.2 Configure OpenHands Server

# SSH to OpenHands server via web proxy
ssh openhands@<OPENHANDS_PRIVATE_IP>

# Set API key
export OPENAI_API_KEY="your-actual-api-key"
sudo sed -i "s/your-api-key-here/$OPENAI_API_KEY/" /etc/systemd/system/openhands.service
sudo systemctl daemon-reload

# Start service
sudo systemctl start openhands
sudo systemctl enable openhands

# Apply network restrictions
./restrict_network.sh

4.3 Test Access

# Test web interface
# Browser: https://<WEB_PROXY_PUBLIC_IP>
# Credentials: openhands / <password from setup log>

# Test network isolation
curl -m 10 https://google.com  # Should FAIL
curl -m 10 https://api.openai.com  # Should WORK

Network Isolation Verification

Allowed Connections

# From OpenHands Server - These should WORK:
curl -m 10 https://api.openai.com
dig api.openai.com
ntpdate -q pool.ntp.org

Blocked Connections

# From OpenHands Server - These should FAIL:
curl -m 10 https://google.com
curl -m 10 https://github.com
ping 8.8.8.8
wget http://example.com

Monitoring and Maintenance

Log Locations

# System logs
/var/log/syslog
/var/log/auth.log
/var/log/nginx/access.log
/var/log/nginx/error.log

# Application logs
/var/log/openhands-audit.log
/home/openhands/.openhands/logs/

# Setup logs
/var/log/setup.log

Health Checks

# Service status
systemctl status openhands
systemctl status nginx

# Network connectivity
netstat -tlnp | grep :3000
netstat -tlnp | grep :443

# Firewall status
ufw status verbose
iptables -L OUTPUT -v

Security Validation

# Verify isolation
ss -tuln  # Check listening ports
netstat -rn  # Check routing table
iptables -L -v  # Check firewall rules

This technical implementation provides complete network isolation while maintaining secure web access to the OpenHands interface through a properly configured reverse proxy with authentication.