# Homelab Secure Production Dockerfile FROM golang:1.25-alpine AS builder # Install dependencies RUN apk add --no-cache git make # Set working directory WORKDIR /app # Copy go mod files COPY go.mod go.sum ./ # Download dependencies RUN go mod download # Copy source code COPY . . # Build Go binaries RUN go build -o bin/api-server cmd/api-server/main.go && \ go build -o bin/worker cmd/worker/worker_server.go cmd/worker/worker_config.go # Final stage with security hardening FROM alpine:3.19 # Install security packages and runtime dependencies RUN apk add --no-cache \ ca-certificates \ redis \ openssl \ curl \ podman \ openssh \ sudo \ fail2ban \ logrotate \ && rm -rf /var/cache/apk/* # Create app user and worker user with no shell by default RUN addgroup -g 1001 -S appgroup && \ adduser -u 1001 -S appuser -G appgroup -s /sbin/nologin && \ addgroup -g 1002 -S workergroup && \ adduser -u 1002 -S worker -G workergroup -s /bin/sh && \ echo "worker:HomelabWorker2024!" | chpasswd && \ mkdir -p /home/worker/.ssh && \ chown -R worker:workergroup /home/worker # Set working directory WORKDIR /app # Copy binaries from builder COPY --from=builder /app/bin/ /usr/local/bin/ # Copy configs COPY --from=builder /app/configs/ /app/configs/ # Create necessary directories with proper permissions RUN mkdir -p /app/data/experiments /app/data/datasets /app/data/snapshots /app/logs /app/ssl /tmp/fetchml-jobs && \ mkdir -p /data/active/datasets /data/active/snapshots && \ mkdir -p /logs && \ chown -R appuser:appgroup /app /data /logs && \ chmod 750 /app/data/experiments /app/logs # Generate SSL certificates with stronger crypto RUN openssl req -x509 -newkey rsa:4096 -keyout /app/ssl/key.pem -out /app/ssl/cert.pem -days 365 -nodes \ -subj "/C=US/ST=Homelab/L=Local/O=ML/OU=Experiments/CN=localhost" && \ chmod 600 /app/ssl/key.pem && \ chmod 644 /app/ssl/cert.pem # Generate SSH keys with stronger crypto RUN ssh-keygen -t rsa -b 4096 -f /home/worker/.ssh/id_rsa -N "" && \ cp /home/worker/.ssh/id_rsa.pub /home/worker/.ssh/authorized_keys && \ chmod 700 /home/worker/.ssh && \ chmod 600 /home/worker/.ssh/id_rsa && \ chmod 644 /home/worker/.ssh/id_rsa.pub /home/worker/.ssh/authorized_keys && \ chown -R worker:workergroup /home/worker/.ssh # Configure SSH with security hardening RUN echo "Port 2222" >> /etc/ssh/sshd_config && \ echo "PermitRootLogin no" >> /etc/ssh/sshd_config && \ echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config && \ echo "PubkeyAuthentication yes" >> /etc/ssh/sshd_config && \ echo "AuthorizedKeysFile %h/.ssh/authorized_keys" >> /etc/ssh/sshd_config && \ echo "AllowUsers worker" >> /etc/ssh/sshd_config && \ echo "MaxAuthTries 3" >> /etc/ssh/sshd_config && \ echo "ClientAliveInterval 300" >> /etc/ssh/sshd_config && \ echo "ClientAliveCountMax 2" >> /etc/ssh/sshd_config && \ echo "X11Forwarding no" >> /etc/ssh/sshd_config && \ echo "AllowTcpForwarding no" >> /etc/ssh/sshd_config && \ echo "Banner /etc/ssh/banner" >> /etc/ssh/sshd_config && \ echo "Protocol 2" >> /etc/ssh/sshd_config && \ echo "Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com" >> /etc/ssh/sshd_config && \ echo "MACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha2-256,hmac-sha2-512" >> /etc/ssh/sshd_config && \ echo "KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group16-sha512" >> /etc/ssh/sshd_config # Create SSH banner RUN echo "=================================================" > /etc/ssh/banner && \ echo " ML Experiments Homelab Server" >> /etc/ssh/banner && \ echo " Unauthorized access is prohibited" >> /etc/ssh/banner && \ echo " All connections are monitored and logged" >> /etc/ssh/banner && \ echo "=================================================" >> /etc/ssh/banner # Generate SSH host keys RUN ssh-keygen -A # Configure fail2ban for SSH protection RUN echo "[DEFAULT]" > /etc/fail2ban/jail.local && \ echo "bantime = 3600" >> /etc/fail2ban/jail.local && \ echo "findtime = 600" >> /etc/fail2ban/jail.local && \ echo "maxretry = 3" >> /etc/fail2ban/jail.local && \ echo "" >> /etc/fail2ban/jail.local && \ echo "[sshd]" >> /etc/fail2ban/jail.local && \ echo "enabled = true" >> /etc/fail2ban/jail.local && \ echo "port = 2222" >> /etc/fail2ban/jail.local && \ echo "filter = sshd" >> /etc/fail2ban/jail.local && \ echo "logpath = /var/log/messages" >> /etc/fail2ban/jail.local # Configure sudo with restricted access RUN echo "appuser ALL=(ALL) NOPASSWD: /app/start-security.sh" >> /etc/sudoers && \ echo "appuser ALL=(ALL) NOPASSWD: /usr/sbin/sshd" >> /etc/sudoers && \ echo "appuser ALL=(ALL) NOPASSWD: /usr/bin/ssh-keygen" >> /etc/sudoers && \ echo "worker ALL=(ALL) NOPASSWD: /usr/bin/podman" >> /etc/sudoers && \ echo "Defaults:appuser !requiretty" >> /etc/sudoers && \ echo "Defaults:worker !requiretty" >> /etc/sudoers && \ echo "Defaults:appuser !lecture" >> /etc/sudoers && \ echo "Defaults:worker !lecture" >> /etc/sudoers # Security hardening - remove setuid binaries except sudo RUN find / -perm /4000 -type f -not -path "/usr/bin/sudo" -exec chmod 755 {} \; 2>/dev/null || true # Create startup script for security services RUN echo "#!/bin/sh" > /app/start-security.sh && \ echo "ssh-keygen -A" >> /app/start-security.sh && \ echo "/usr/sbin/sshd -D -p 2222" >> /app/start-security.sh && \ echo "# End of security services" >> /app/start-security.sh && \ chmod 755 /app/start-security.sh # Switch to app user for application USER appuser # Expose ports EXPOSE 9101 2222 # Health check HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \ CMD curl -k -f https://localhost:9101/health || exit 1 # Default command for API server CMD ["/usr/local/bin/api-server", "-config", "/app/configs/api/prod.yaml"]