version: '3.8'

services:
  # PostgreSQL database for certctl
  postgres:
    image: postgres:16-alpine
    container_name: certctl-postgres-stepca-haproxy
    environment:
      POSTGRES_DB: certctl
      POSTGRES_USER: certctl
      POSTGRES_PASSWORD: ${DB_PASSWORD:-certctl-dev-password}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ['CMD-SHELL', 'pg_isready -U certctl -d certctl']
      interval: 5s
      timeout: 5s
      retries: 5
    networks:
      - certctl-network
    restart: unless-stopped

  # Smallstep step-ca (internal private CA)
  # Initialized with default admin token and provisioner configuration
  step-ca:
    image: smallstep/step-ca:latest
    container_name: step-ca-stepca-haproxy
    environment:
      # step-ca root password (for key encryption)
      STEPPATH: /home/step/step-ca
      # Provisioner password will be set up below
    volumes:
      # Persist step-ca configuration and keys
      - step_ca_data:/home/step/step-ca
      - ./step-ca-init.sh:/opt/step-ca-init.sh:ro
    entrypoint: /bin/sh
    command:
      - -c
      - |
        # Initialize step-ca if not already done
        if [ ! -f /home/step/step-ca/config/ca.json ]; then
          echo "Initializing step-ca..."
          step ca init \
            --name="certctl-demo-ca" \
            --dns=step-ca \
            --address=0.0.0.0:9000 \
            --provisioner=admin \
            --provisioner-password-file=<(echo "${STEP_CA_PASSWORD:-stepca-demo-password}") \
            --password-file=<(echo "${STEP_CA_PASSWORD:-stepca-demo-password}") \
            --deployment-type=standalone \
            --acme 2>&1 || true
        fi

        # Add a JWK provisioner for certctl if not present
        if ! step ca provisioner list 2>/dev/null | grep -q "certctl"; then
          echo "Adding certctl JWK provisioner..."
          step ca provisioner add certctl \
            --type=JWK \
            --password-file=<(echo "${STEP_CA_PROVISIONER_PASSWORD:-certctl-provisioner-demo}") \
            2>&1 || true
        fi

        # Start step-ca
        echo "Starting step-ca..."
        step-ca /home/step/step-ca/config/ca.json \
          --password-file=<(echo "${STEP_CA_PASSWORD:-stepca-demo-password}")
    ports:
      - '9000:9000'
    healthcheck:
      test: ['CMD-SHELL', 'step ca health --insecure || exit 1']
      interval: 10s
      timeout: 5s
      retries: 3
    networks:
      - certctl-network
    restart: unless-stopped

  # certctl server (control plane)
  certctl-server:
    image: ghcr.io/certctl-io/certctl-server:latest
    container_name: certctl-server-stepca-haproxy
    environment:
      # Database
      CERTCTL_DATABASE_URL: postgres://certctl:${DB_PASSWORD:-certctl-dev-password}@postgres:5432/certctl?sslmode=disable

      # Server settings
      CERTCTL_SERVER_PORT: 8443
      CERTCTL_SERVER_HOST: 0.0.0.0

      # Auth (disabled for demo; production should use API keys)
      CERTCTL_AUTH_TYPE: none

      # CORS (allow agent communication)
      CERTCTL_CORS_ORIGINS: '*'

      # Key generation mode (agent-side in production, server-side for demo)
      CERTCTL_KEYGEN_MODE: agent

      # step-ca issuer configuration
      # step-ca runs on step-ca:9000 in this compose network
      CERTCTL_STEPCA_URL: https://step-ca:9000
      CERTCTL_STEPCA_ROOT_CERT_PATH: /etc/certctl/step-ca-root.crt
      CERTCTL_STEPCA_PROVISIONER: certctl
      CERTCTL_STEPCA_KEY_PATH: /etc/certctl/step-ca-provisioner.json
      CERTCTL_STEPCA_PASSWORD: ${STEP_CA_PROVISIONER_PASSWORD:-certctl-provisioner-demo}

      # Logging
      CERTCTL_LOG_LEVEL: info
    volumes:
      # Mount step-ca certs for TLS verification (auto-generated by step-ca init)
      - step_ca_data:/home/step/step-ca/config:ro
    ports:
      - '${SERVER_PORT:-8443}:8443'
    depends_on:
      postgres:
        condition: service_healthy
      step-ca:
        condition: service_healthy
    networks:
      - certctl-network
    healthcheck:
      test: ['CMD-SHELL', 'curl -sfk https://localhost:8443/health || exit 1']
      interval: 10s
      timeout: 5s
      retries: 3
    restart: unless-stopped

  # certctl agent (runs on the target machine with HAProxy)
  certctl-agent:
    image: ghcr.io/certctl-io/certctl-agent:latest
    container_name: certctl-agent-stepca-haproxy
    environment:
      # Control plane connection
      CERTCTL_SERVER_URL: http://certctl-server:8443
      CERTCTL_API_KEY: ${AGENT_API_KEY:-agent-demo-key}

      # Key generation (agent-side keys, never sent to server)
      CERTCTL_KEYGEN_MODE: agent
      CERTCTL_KEY_DIR: /var/lib/certctl/keys

      # Discovery (scan existing certs so operator knows what's already deployed)
      CERTCTL_DISCOVERY_DIRS: /etc/haproxy/ssl

      # Heartbeat interval
      CERTCTL_HEARTBEAT_INTERVAL: 30s

      # Agent metadata (self-reported)
      CERTCTL_AGENT_NAME: haproxy-agent-01

      # Logging
      CERTCTL_LOG_LEVEL: info
    volumes:
      # Mount HAProxy config and cert directories
      # In production, these would be the actual HAProxy paths
      - haproxy_certs:/etc/haproxy/ssl
      - haproxy_conf:/etc/haproxy
      # Agent key storage (persisted across restarts)
      - agent_keys:/var/lib/certctl/keys
    depends_on:
      certctl-server:
        condition: service_healthy
    networks:
      - certctl-network
    restart: unless-stopped

  # HAProxy reverse proxy / load balancer
  # This is where certificates will be deployed
  haproxy:
    image: haproxy:2.9-alpine
    container_name: certctl-haproxy-stepca-haproxy
    ports:
      - '80:80'
      - '443:443'
    volumes:
      - haproxy_conf:/etc/haproxy
      - haproxy_certs:/etc/haproxy/ssl
      # Default HAProxy config
      - ./haproxy.cfg:/etc/haproxy/haproxy.cfg:ro
    depends_on:
      - certctl-agent
    networks:
      - certctl-network
    healthcheck:
      test: ['CMD-SHELL', 'wget --quiet --tries=1 --spider http://localhost:8080/stats || exit 1']
      interval: 10s
      timeout: 5s
      retries: 3
    restart: unless-stopped

networks:
  certctl-network:
    driver: bridge

volumes:
  postgres_data:
    driver: local
  step_ca_data:
    driver: local
  haproxy_certs:
    driver: local
  haproxy_conf:
    driver: local
  agent_keys:
    driver: local
