Skip to main content

Docker Deployment

AegisShield includes a production-ready Dockerfile for containerized deployment. This enables consistent environments across development, testing, and production.

Quick Start

# Clone repository
git clone https://github.com/mgrofsky/AegisShield.git
cd AegisShield

# Build Docker image
docker build -t aegisshield:latest .

# Run container
docker run -p 8501:8501 \
  -e OPENAI_API_KEY="your-openai-key" \
  -e NVD_API_KEY="your-nvd-key" \
  -e ALIENVAULT_API_KEY="your-alienvault-key" \
  aegisshield:latest
Access the application at http://localhost:8501

Dockerfile Breakdown

Let’s examine the AegisShield Dockerfile:
# Specify the base image
FROM python:3.13-slim
Base Image: Uses Python 3.13 slim variant for:
  • Minimal attack surface
  • Smaller image size (~150MB vs 1GB for full Python)
  • Faster build and deployment times

# Install system dependencies for PDF generation (Cairo/Pango for xhtml2pdf)
RUN apt-get update && apt-get install -y \
    build-essential \
    python3-dev \
    libcairo2-dev \
    libpango1.0-dev \
    libpangocairo-1.0-0 \
    libgdk-pixbuf2.0-dev \
    libffi-dev \
    pkg-config \
    shared-mime-info \
    curl \
    && rm -rf /var/lib/apt/lists/*
System Dependencies: Required for:
  • Cairo/Pango: PDF report generation with xhtml2pdf
  • libffi: Cryptographic operations
  • curl: Health check endpoint testing
  • build-essential: Compilation of Python packages with C extensions
The cleanup command rm -rf /var/lib/apt/lists/* reduces image size by removing package manager cache.

# Set the working directory in the container
WORKDIR /app

# Copy the current directory contents into the container at /app
COPY . /app
File Structure: Copies entire application directory including:
  • Python source files
  • MITRE ATT&CK data files
  • Requirements and configuration
  • Static assets (logo, etc.)

# Install any needed packages specified in requirements.txt
RUN pip install --no-cache-dir -r requirements.txt
Python Dependencies: Installs all required packages:
  • Streamlit (web framework)
  • OpenAI SDK (GPT-4o integration)
  • nvdlib (National Vulnerability Database)
  • OTXv2 (AlienVault threat intelligence)
  • markdown2, xhtml2pdf (report generation)
The --no-cache-dir flag prevents pip from caching packages, reducing final image size.

# Make port 8501 available to the world outside this container
EXPOSE 8501
Port Exposure: Streamlit’s default port 8501 is exposed for:
  • Web UI access
  • API endpoints (if implemented)
  • Health checks

# Test if the container is listening on port 8501
HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health
Health Monitoring:
  • Docker periodically checks the /_stcore/health endpoint
  • Marks container as unhealthy if checks fail
  • Enables orchestration tools (Kubernetes, ECS) to restart failed containers

# Configure the container to run as an executable
ENTRYPOINT ["streamlit", "run", "main.py", "--server.port=8501", "--server.address=0.0.0.0"]
Application Startup:
  • streamlit run main.py: Launches the main application
  • --server.port=8501: Binds to port 8501
  • --server.address=0.0.0.0: Listens on all network interfaces (required for container networking)

Environment Configuration

Using Environment Variables

AegisShield can be configured via environment variables for Docker deployments:
docker run -p 8501:8501 \
  -e OPENAI_API_KEY="sk-proj-xxx" \
  -e NVD_API_KEY="nvd-xxx" \
  -e ALIENVAULT_API_KEY="alienvault-xxx" \
  aegisshield:latest

Using Secrets File

For production, use Docker secrets or mounted configuration:
# Create secrets file
cat > local_config.py <<EOF
default_nvd_api_key="NVD-API-KEY"
default_openai_api_key="OPENAI-API-KEY"
default_alienvault_api_key="ALIENVAULT-API-KEY"
EOF

# Mount as volume
docker run -p 8501:8501 \
  -v $(pwd)/local_config.py:/app/local_config.py:ro \
  aegisshield:latest
Security Best Practice: Never commit local_config.py with real API keys to version control. Use .gitignore to exclude it.

Using .env File

Create a .env file for docker-compose:
# .env
OPENAI_API_KEY=sk-proj-xxx
NVD_API_KEY=nvd-xxx
ALIENVAULT_API_KEY=alienvault-xxx

Docker Compose Configuration

Create docker-compose.yml for easier management:
version: '3.8'

services:
  aegisshield:
    build: .
    image: aegisshield:latest
    container_name: aegisshield
    ports:
      - "8501:8501"
    environment:
      - OPENAI_API_KEY=${OPENAI_API_KEY}
      - NVD_API_KEY=${NVD_API_KEY}
      - ALIENVAULT_API_KEY=${ALIENVAULT_API_KEY}
    volumes:
      # Mount MITRE data directory (optional, if updating frequently)
      - ./MITRE_ATTACK_DATA:/app/MITRE_ATTACK_DATA:ro
      # Mount logs directory for persistence
      - ./logs:/app/logs
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8501/_stcore/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

Usage:

# Start service
docker-compose up -d

# View logs
docker-compose logs -f aegisshield

# Restart service
docker-compose restart

# Stop and remove
docker-compose down

Production Deployment

Kubernetes Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: aegisshield
  labels:
    app: aegisshield
spec:
  replicas: 2
  selector:
    matchLabels:
      app: aegisshield
  template:
    metadata:
      labels:
        app: aegisshield
    spec:
      containers:
      - name: aegisshield
        image: aegisshield:latest
        ports:
        - containerPort: 8501
        env:
        - name: OPENAI_API_KEY
          valueFrom:
            secretKeyRef:
              name: aegisshield-secrets
              key: openai-api-key
        - name: NVD_API_KEY
          valueFrom:
            secretKeyRef:
              name: aegisshield-secrets
              key: nvd-api-key
        - name: ALIENVAULT_API_KEY
          valueFrom:
            secretKeyRef:
              name: aegisshield-secrets
              key: alienvault-api-key
        resources:
          requests:
            memory: "512Mi"
            cpu: "500m"
          limits:
            memory: "2Gi"
            cpu: "2000m"
        livenessProbe:
          httpGet:
            path: /_stcore/health
            port: 8501
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /_stcore/health
            port: 8501
          initialDelaySeconds: 5
          periodSeconds: 5
Apply configuration:
# Create secrets
kubectl apply -f secrets.yaml

# Deploy application
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml

# Check status
kubectl get pods
kubectl logs -f deployment/aegisshield

AWS ECS Deployment

{
  "family": "aegisshield",
  "networkMode": "awsvpc",
  "containerDefinitions": [
    {
      "name": "aegisshield",
      "image": "<account-id>.dkr.ecr.<region>.amazonaws.com/aegisshield:latest",
      "portMappings": [
        {
          "containerPort": 8501,
          "protocol": "tcp"
        }
      ],
      "secrets": [
        {
          "name": "OPENAI_API_KEY",
          "valueFrom": "arn:aws:secretsmanager:region:account:secret:aegisshield/openai"
        },
        {
          "name": "NVD_API_KEY",
          "valueFrom": "arn:aws:secretsmanager:region:account:secret:aegisshield/nvd"
        },
        {
          "name": "ALIENVAULT_API_KEY",
          "valueFrom": "arn:aws:secretsmanager:region:account:secret:aegisshield/alienvault"
        }
      ],
      "memory": 2048,
      "cpu": 1024,
      "essential": true,
      "healthCheck": {
        "command": ["CMD-SHELL", "curl -f http://localhost:8501/_stcore/health || exit 1"],
        "interval": 30,
        "timeout": 5,
        "retries": 3
      }
    }
  ],
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "1024",
  "memory": "2048"
}

Customization Options

Custom Port

# Change port in Dockerfile
EXPOSE 9000
ENTRYPOINT ["streamlit", "run", "main.py", "--server.port=9000", "--server.address=0.0.0.0"]
# Run with custom port
docker run -p 9000:9000 aegisshield:latest

Additional Streamlit Configuration

Create .streamlit/config.toml:
[server]
port = 8501
address = "0.0.0.0"
maxUploadSize = 200
enableCORS = false
enableXsrfProtection = true

[browser]
gatherUsageStats = false

[theme]
primaryColor = "#1f77b4"
backgroundColor = "#ffffff"
secondaryBackgroundColor = "#f0f2f6"
textColor = "#262730"
Mount in Dockerfile:
COPY .streamlit /app/.streamlit

Persistent Data

Mount volumes for persistent storage:
docker run -p 8501:8501 \
  -v $(pwd)/logs:/app/logs \
  -v $(pwd)/outputs:/app/outputs \
  aegisshield:latest

Troubleshooting

Check logs:
docker logs aegisshield
Common causes:
  • Missing API keys in environment variables
  • Port 8501 already in use
  • Insufficient memory allocation
Solution:
# Check port usage
netstat -tulpn | grep 8501

# Use different port
docker run -p 8502:8501 aegisshield:latest
Symptom: Container marked as unhealthyCheck health:
docker inspect --format='{{json .State.Health}}' aegisshield | jq
Solution:
  • Increase start_period in health check (Streamlit needs ~30s to start)
  • Verify port 8501 is accessible inside container:
docker exec -it aegisshield curl http://localhost:8501/_stcore/health
Error: Missing Cairo/Pango librariesSolution: Ensure system dependencies are installed (they should be in the Dockerfile)Verify:
docker exec -it aegisshield dpkg -l | grep cairo
docker exec -it aegisshield dpkg -l | grep pango
Problem: Docker image is too largeSolutions:
  1. Use multi-stage builds to reduce size
  2. Remove unnecessary files with .dockerignore:
.git
.gitignore
__pycache__
*.pyc
tests/
docs/
.env
local_config.py
  1. Check image size:
docker images aegisshield
Problem: Application can’t access API keysDebug:
# Check environment variables
docker exec aegisshield env | grep API_KEY

# Check config file
docker exec aegisshield cat /app/local_config.py
Solution: Ensure environment variables or mounted config file is correct

Security Best Practices

Production Security Checklist:
  • ✅ Never include API keys in the Docker image
  • ✅ Use Docker secrets or environment variables
  • ✅ Run container as non-root user (add USER directive)
  • ✅ Use read-only file system where possible
  • ✅ Scan images for vulnerabilities regularly
  • ✅ Keep base image updated (Python 3.13-slim)
  • ✅ Enable TLS/HTTPS in production
  • ✅ Use private container registry
  • ✅ Implement network policies (firewall rules)
  • ✅ Monitor container logs and metrics

Non-Root User

Add to Dockerfile for improved security:
# Create non-root user
RUN useradd -m -u 1000 aegis && \
    chown -R aegis:aegis /app

USER aegis

ENTRYPOINT ["streamlit", "run", "main.py", "--server.port=8501", "--server.address=0.0.0.0"]

Performance Tuning

Resource Limits

# Set memory and CPU limits
docker run -p 8501:8501 \
  --memory="2g" \
  --cpus="1.5" \
  aegisshield:latest

Monitoring

# Real-time resource usage
docker stats aegisshield

# Export metrics (for Prometheus, etc.)
docker stats --no-stream --format "{{json .}}" aegisshield

Next Steps

Configuration

Configure API keys and settings

Troubleshooting

Resolve common issues

Build docs developers (and LLMs) love