# PentAGI Worker Node Setup
This guide configures a distributed PentAGI deployment where worker node operations are isolated on a separate server for enhanced security. The worker node runs both host Docker and Docker-in-Docker (dind) to provide secure container execution environments.
## Architecture Overview
```mermaid
graph TB
subgraph "Main Node"
PA[PentAGI Container]
end
subgraph "Worker Node"
HD[Host Docker
:2376 TLS]
DIND[Docker-in-Docker
:3376 TLS]
subgraph "Worker Containers"
WC1[pentagi-terminal-1]
WC2[pentagi-terminal-N]
end
end
PA -.->|"TLS Connection
Create Workers"| HD
HD --> WC1
HD --> WC2
WC1 -.->|"docker.sock
mapping"| DIND
WC2 -.->|"docker.sock
mapping"| DIND
PA -.->|"Alternative:
Direct TLS"| DIND
classDef main fill:#e1f5fe
classDef worker fill:#f3e5f5
classDef container fill:#e8f5e8
class PA main
class HD,DIND worker
class WC1,WC2 container
```
**Connection Modes:**
- **Standard**: PentAGI → Host Docker (creates workers) → Workers use dind via socket mapping
- **Direct**: PentAGI → dind (creates workers directly, socket mapping disabled)
## Prerequisites
Set the private IP address that will be used throughout this setup:
```bash
export PRIVATE_IP=192.168.10.10 # Replace with your worker node IP
```
## Install Docker on Both Nodes
> **Note:** Docker must be installed on both the **worker node** and the **main node**. Execute the following commands on each node separately.
Install Docker CE following the official Ubuntu installation guide:
```bash
# Add Docker's official GPG key
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Add Docker repository to APT sources
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
# Install Docker CE and plugins
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
```
## Configure Host Docker on Worker Node
### Generate TLS Certificates for Host Docker
Configure TLS authentication for secure remote Docker API access:
```bash
# Install easy-rsa for certificate management
sudo apt install easy-rsa
# Create PKI infrastructure for host docker
sudo mkdir -p /etc/easy-rsa/docker-host
cd /etc/easy-rsa/docker-host
sudo /usr/share/easy-rsa/easyrsa init-pki
sudo /usr/share/easy-rsa/easyrsa build-ca nopass
# Generate server certificate with SAN extensions
export EASYRSA_EXTRA_EXTS="subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost
DNS.2 = docker
DNS.3 = docker-host
IP.1 = 127.0.0.1
IP.2 = 0.0.0.0
IP.3 = ${PRIVATE_IP}"
sudo /usr/share/easy-rsa/easyrsa build-server-full server nopass # Confirm with 'yes'
unset EASYRSA_EXTRA_EXTS
# Generate client certificate
sudo /usr/share/easy-rsa/easyrsa build-client-full client nopass # Confirm with 'yes'
# Copy server certificates to Docker directory
sudo mkdir -p /etc/docker/certs/server
sudo cp pki/ca.crt /etc/docker/certs/server/ca.pem
sudo cp pki/issued/server.crt /etc/docker/certs/server/cert.pem
sudo cp pki/private/server.key /etc/docker/certs/server/key.pem
# Copy client certificates for remote access
sudo mkdir -p /etc/docker/certs/client
sudo cp pki/ca.crt /etc/docker/certs/client/ca.pem
sudo cp pki/issued/client.crt /etc/docker/certs/client/cert.pem
sudo cp pki/private/client.key /etc/docker/certs/client/key.pem
```
### Configure Docker Daemon with TLS
Enable TLS authentication and remote access for the Docker daemon:
```bash
# Configure Docker daemon with TLS settings
sudo cat > /etc/docker/daemon.json << EOF
{
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "2",
"compress": "true"
},
"dns-opts": [
"ndots:1"
],
"metrics-addr": "${PRIVATE_IP}:9323",
"tls": true,
"tlscacert": "/etc/docker/certs/server/ca.pem",
"tlscert": "/etc/docker/certs/server/cert.pem",
"tlskey": "/etc/docker/certs/server/key.pem",
"tlsverify": true
}
EOF
# Enable TCP listening on private IP (required for remote access)
sudo sed -i "s|ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock|ExecStart=/usr/bin/dockerd -H fd:// -H tcp://${PRIVATE_IP}:2376 --containerd=/run/containerd/containerd.sock|" /lib/systemd/system/docker.service
# Apply configuration changes
sudo systemctl daemon-reload
sudo systemctl restart docker
```
### Create TLS Access Test Script
Create a utility script to test secure Docker API access:
```bash
sudo cat > /usr/local/bin/docker-host-tls << EOF
#!/bin/bash
# Docker API client wrapper for TLS connections
# Usage: docker-host-tls [docker-commands]
export DOCKER_HOST=tcp://${PRIVATE_IP}:2376
export DOCKER_TLS_VERIFY=1
export DOCKER_CERT_PATH=/etc/docker/certs/client
# Show connection info if no arguments provided
if [ \$# -eq 0 ]; then
echo "Docker API connection configured:"
echo " Host: ${PRIVATE_IP}:2376"
echo " TLS: enabled"
echo " Certificates: /etc/docker/certs/client/"
echo ""
echo "Usage: docker-host-tls [docker-commands]"
echo "Examples:"
echo " docker-host-tls version"
echo " docker-host-tls ps"
echo " docker-host-tls images"
exit 0
fi
# Execute docker command with TLS environment
exec docker "\$@"
EOF
sudo chmod +x /usr/local/bin/docker-host-tls
# Test TLS connection
docker-host-tls ps && docker-host-tls info
```
## Configure Docker-in-Docker (dind) on Worker Node
Docker-in-Docker provides an isolated environment for worker containers to execute Docker commands securely.
### Generate TLS Certificates for dind
Create separate certificates for the dind daemon:
```bash
# Create PKI infrastructure for dind
sudo mkdir -p /etc/easy-rsa/docker-dind
cd /etc/easy-rsa/docker-dind
sudo /usr/share/easy-rsa/easyrsa init-pki
sudo /usr/share/easy-rsa/easyrsa build-ca nopass
# Generate server certificate with SAN extensions
export EASYRSA_EXTRA_EXTS="subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost
DNS.2 = docker
DNS.3 = docker-dind
IP.1 = 127.0.0.1
IP.2 = 0.0.0.0
IP.3 = ${PRIVATE_IP}"
sudo /usr/share/easy-rsa/easyrsa build-server-full server nopass # Confirm with 'yes'
unset EASYRSA_EXTRA_EXTS
# Generate client certificate
sudo /usr/share/easy-rsa/easyrsa build-client-full client nopass # Confirm with 'yes'
# Create certificate directories
sudo mkdir -p /etc/docker/certs/dind/{ca,client,server}
# Copy CA certificates
sudo cp pki/ca.crt /etc/docker/certs/dind/ca/cert.pem
sudo cp pki/private/ca.key /etc/docker/certs/dind/ca/key.pem
# Copy server certificates
sudo cp pki/ca.crt /etc/docker/certs/dind/server/ca.pem
sudo cp pki/issued/server.crt /etc/docker/certs/dind/server/cert.pem
sudo cp pki/private/server.key /etc/docker/certs/dind/server/key.pem
# Copy client certificates
sudo cp pki/ca.crt /etc/docker/certs/dind/client/ca.pem
sudo cp pki/issued/client.crt /etc/docker/certs/dind/client/cert.pem
sudo cp pki/private/client.key /etc/docker/certs/dind/client/key.pem
```
### Create dind Management Script
Create a script to manage the dind container lifecycle:
```bash
sudo cat > /usr/local/bin/run-dind << EOF
#!/bin/bash
# Check if dind container exists
if docker ps -a --format '{{.Names}}' | grep -q "^docker-dind$"; then
if ! docker ps --format '{{.Names}}' | grep -q "^docker-dind$"; then
echo "Starting existing docker-dind container..."
docker start docker-dind
else
echo "docker-dind container is already running."
fi
else
echo "Creating new docker-dind container..."
docker run -d \
--privileged \
-v /etc/docker/certs/dind/server:/certs/server:ro \
-v /var/lib/docker-dind:/var/lib/docker \
-v /var/run/docker-dind:/var/run/dind \
-p ${PRIVATE_IP}:3376:2376 \
-p ${PRIVATE_IP}:9324:9324 \
--cpus 2 --memory 2G \
--name docker-dind \
--restart always \
--log-opt max-size=50m \
--log-opt max-file=7 \
docker:dind \
--host=unix:///var/run/dind/docker.sock \
--host=tcp://0.0.0.0:2376 \
--tls=true \
--tlscert=/certs/server/cert.pem \
--tlskey=/certs/server/key.pem \
--tlscacert=/certs/server/ca.pem \
--tlsverify=true \
--metrics-addr=0.0.0.0:9324
echo "docker-dind container created and started."
fi
EOF
sudo chmod +x /usr/local/bin/run-dind
# Start dind container and verify
run-dind && docker ps
```
### Create dind Access Test Scripts
Create utilities to test dind access via TLS and Unix socket:
**TLS Access Script:**
```bash
sudo cat > /usr/local/bin/docker-dind-tls << EOF
#!/bin/bash
# Docker API client wrapper for dind TLS connections
# Usage: docker-dind-tls [docker-commands]
export DOCKER_HOST=tcp://${PRIVATE_IP}:3376
export DOCKER_TLS_VERIFY=1
export DOCKER_CERT_PATH=/etc/docker/certs/dind/client
# Show connection info if no arguments provided
if [ \$# -eq 0 ]; then
echo "Docker dind API connection configured:"
echo " Host: ${PRIVATE_IP}:3376"
echo " TLS: enabled"
echo " Certificates: /etc/docker/certs/dind/client/"
echo ""
echo "Usage: docker-dind-tls [docker-commands]"
echo "Examples:"
echo " docker-dind-tls version"
echo " docker-dind-tls ps"
echo " docker-dind-tls images"
exit 0
fi
# Execute docker command with TLS environment
exec docker "\$@"
EOF
sudo chmod +x /usr/local/bin/docker-dind-tls
# Test dind TLS connection
docker-dind-tls ps && docker-dind-tls info
```
**Unix Socket Access Script:**
```bash
sudo cat > /usr/local/bin/docker-dind-sock << EOF
#!/bin/bash
# Docker API client wrapper for dind socket connections
# Usage: docker-dind-sock [docker-commands]
export DOCKER_HOST=unix:///var/run/docker-dind/docker.sock
export DOCKER_TLS_VERIFY=
export DOCKER_CERT_PATH=
# Show connection info if no arguments provided
if [ \$# -eq 0 ]; then
echo "Docker dind socket connection configured:"
echo " Host: unix:///var/run/docker-dind/docker.sock"
echo ""
echo "Usage: docker-dind-sock [docker-commands]"
echo "Examples:"
echo " docker-dind-sock version"
echo " docker-dind-sock ps"
echo " docker-dind-sock images"
exit 0
fi
# Execute docker command with socket environment
exec docker "\$@"
EOF
sudo chmod +x /usr/local/bin/docker-dind-sock
# Test dind socket connection
docker-dind-sock ps && docker-dind-sock info
```
## Security & Firewall Configuration
### Required Port Access
The worker node exposes the following services on the private IP address:
| Port | Service | Description |
|------|---------|-------------|
| 2376 | Host Docker API | TLS-secured Docker daemon for worker container management |
| 3376 | dind API | TLS-secured Docker-in-Docker daemon |
| 9323 | Host Docker Metrics | Prometheus metrics endpoint for host Docker |
| 9324 | dind Metrics | Prometheus metrics endpoint for dind |
**Metrics Integration:** The metrics ports (9323, 9324) can be configured in PentAGI's `observability/otel/config.yml` under the `docker-engine-collector` job name for monitoring integration.
### OOB Attack Port Range
Each worker container (`pentagi-terminal-N`) dynamically allocates **2 ports** from the range `28000-30000` on all network interfaces to facilitate Out-of-Band (OOB) attack techniques during penetration testing.
**Firewall Requirements:**
- **Inbound**: Allow access to ports 2376, 3376, 9323, 9324 on `${PRIVATE_IP}` from the main PentAGI node
- **Inbound**: Allow access to port range 28000-30000 from target networks being tested
- Configure perimeter firewall to permit OOB traffic from target networks to worker node
## Transfer Certificates to Main Node
Copy the client certificates from the worker node to the main PentAGI node for secure Docker API access. The certificates need to be transferred to specific directories that the PentAGI installer will recognize.
### Copy Host Docker Client Certificates
Transfer the host Docker client certificates to the main node:
```bash
# On the worker node - create archive with host docker certificates
sudo tar czf docker-host-ssl.tar.gz -C /etc/docker/certs client/
# Transfer to main node (replace with actual IP)
scp docker-host-ssl.tar.gz root@:/opt/pentagi/
# On the main node - extract certificates
cd /opt/pentagi
tar xzf docker-host-ssl.tar.gz
mv client docker-host-ssl
rm docker-host-ssl.tar.gz
```
### Copy dind Client Certificates
Transfer the dind client certificates to the main node:
```bash
# On the worker node - create archive with dind certificates
sudo tar czf docker-dind-ssl.tar.gz -C /etc/docker/certs/dind client/
# Transfer to main node (replace with actual IP)
scp docker-dind-ssl.tar.gz root@:/opt/pentagi/
# On the main node - extract certificates
cd /opt/pentagi
tar xzf docker-dind-ssl.tar.gz
mv client docker-dind-ssl
rm docker-dind-ssl.tar.gz
```
### Verify Certificate Structure
After transfer, verify the certificate directory structure on the main node:
```bash
# Check certificate directories
ls -la /opt/pentagi/docker-host-ssl/
ls -la /opt/pentagi/docker-dind-ssl/
# Expected files in each directory:
# ca.pem (Certificate Authority)
# cert.pem (Client certificate)
# key.pem (Client private key)
```
These certificate directories will be used by the PentAGI installer to configure secure connections to the worker node Docker services.
## Install PentAGI on Main Node
After completing the worker node setup and transferring certificates, install PentAGI on the main node using the official installer.
### Download and Run Installer
Execute the following commands on the main node to download and run the PentAGI installer:
```bash
# Create installation directory and navigate to it
mkdir -p /opt/pentagi && cd /opt/pentagi
# Download the latest installer
wget -O installer.zip https://pentagi.com/downloads/linux/amd64/installer-latest.zip
# Extract the installer
unzip installer.zip
# Run the installer (interactive setup)
./installer
```
**Prerequisites & Permissions:**
The installer requires appropriate privileges to interact with the Docker API for proper operation. By default, it uses the Docker socket (`/var/run/docker.sock`) which requires either:
- **Option 1 (Recommended for production):** Run the installer as root:
```bash
sudo ./installer
```
- **Option 2 (Development environments):** Grant your user access to the Docker socket by adding them to the `docker` group:
```bash
# Add your user to the docker group
sudo usermod -aG docker $USER
# Log out and log back in, or activate the group immediately
newgrp docker
# Verify Docker access (should run without sudo)
docker ps
```
⚠️ **Security Note:** Adding a user to the `docker` group grants root-equivalent privileges. Only do this for trusted users in controlled environments. For production deployments, consider using rootless Docker mode or running the installer with sudo.
### Configure Docker Environment
After the installer completes and PentAGI is running, manually configure the Docker environment through the web interface:
1. **Access PentAGI Installer** via `./installer`
2. **Navigate to Tools → Docker Environment**
3. **Fill in the Docker Environment Configuration fields:**
**For Standard Mode (Host Docker):**
- **Docker Access**: `true` (enable Docker access for workers)
- **Network Admin**: `true` (enable network scanning capabilities)
- **Docker Socket**: `/var/run/docker-dind/docker.sock` (path inside worker containers)
- **Docker Network**: `pentagi-network` (custom network name)
- **Public IP Address**: `${PRIVATE_IP}` (worker node IP a front of tested network for OOB attacks)
- **Work Directory**: Leave empty (use default Docker volumes)
- **Default Image**: `debian:latest` (or leave empty)
- **Pentesting Image**: `vxcontrol/kali-linux` (or leave empty)
- **Docker Host**: `tcp://${PRIVATE_IP}:2376` (TLS connection to host Docker)
- **TLS Verification**: `1` (enable TLS verification)
- **TLS Certificates**: `/opt/pentagi/docker-host-ssl` (path to client certificates)
**For Direct Mode (dind only):**
- Use the same configuration but change:
- **Docker Host**: `tcp://${PRIVATE_IP}:3376` (TLS connection to dind)
- **TLS Certificates**: `/opt/pentagi/docker-dind-ssl` (path to dind client certificates)
- **Docker Socket**: Leave empty (no socket mapping needed)
The certificate directories `/opt/pentagi/docker-host-ssl/` and `/opt/pentagi/docker-dind-ssl/` will be automatically mounted into the PentAGI container for secure TLS authentication.