#cloud-config # ============================================================================= # Jump Host (Bastion) Cloud-Init Configuration # Minimal attack surface - SSH only, no Docker # ============================================================================= # NOTE: We install packages via runcmd instead of packages: section # because DigitalOcean's base image cloud-init can interfere with the packages module # SSH hardening configuration write_files: # SSH daemon configuration - path: /etc/ssh/sshd_config.d/99-hardening.conf content: | # Non-standard port Port ${ssh_port} # Authentication hardening PermitRootLogin prohibit-password PasswordAuthentication no PubkeyAuthentication yes AuthenticationMethods publickey # Security settings MaxAuthTries 3 LoginGraceTime 30 PermitEmptyPasswords no X11Forwarding no AllowTcpForwarding no AllowAgentForwarding no PermitUserEnvironment no MaxSessions 3 # Session settings ClientAliveInterval 300 ClientAliveCountMax 2 # Logging LogLevel VERBOSE permissions: '0644' # Fail2ban SSH jail configuration - path: /etc/fail2ban/jail.d/sshd.local content: | [sshd] enabled = true port = ${ssh_port} filter = sshd logpath = /var/log/auth.log backend = systemd bantime = 1h findtime = 10m maxretry = 3 permissions: '0644' # UFW configuration script - path: /usr/local/bin/configure-firewall.sh content: | #!/bin/bash set -e # Reset UFW ufw --force reset # Default policies ufw default deny incoming ufw default deny outgoing # Inbound: SSH on non-standard port ufw allow in ${ssh_port}/tcp comment 'SSH' # Inbound: VPC traffic ufw allow in from ${vpc_ip_range} comment 'VPC internal' # Outbound: Only necessary traffic (matching DO firewall) ufw allow out 53/tcp comment 'DNS' ufw allow out 53/udp comment 'DNS' ufw allow out 80/tcp comment 'HTTP' ufw allow out 443/tcp comment 'HTTPS' ufw allow out 123/udp comment 'NTP' ufw allow out to ${vpc_ip_range} comment 'VPC' # Enable logging for security audit ufw logging high # Enable UFW ufw --force enable echo "Firewall configured successfully" permissions: '0755' # Unattended upgrades configuration - path: /etc/apt/apt.conf.d/50unattended-upgrades content: | Unattended-Upgrade::Allowed-Origins { "$${distro_id}:$${distro_codename}"; "$${distro_id}:$${distro_codename}-security"; "$${distro_id}:$${distro_codename}-updates"; }; Unattended-Upgrade::AutoFixInterruptedDpkg "true"; Unattended-Upgrade::MinimalSteps "true"; Unattended-Upgrade::Remove-Unused-Dependencies "true"; Unattended-Upgrade::Automatic-Reboot "false"; permissions: '0644' # Auto-upgrades configuration - path: /etc/apt/apt.conf.d/20auto-upgrades content: | APT::Periodic::Update-Package-Lists "1"; APT::Periodic::Unattended-Upgrade "1"; APT::Periodic::AutocleanInterval "7"; permissions: '0644' # Message of the day - path: /etc/motd content: | ╔═══════════════════════════════════════════════════════════════╗ ║ JUMP HOST / BASTION ║ ║ ║ ║ This is a restricted access server. ║ ║ All connections are logged and monitored. ║ ║ ║ ║ Use this host to access internal infrastructure: ║ ║ ssh -p 52913 root@10.10.0.x ║ ║ ║ ╚═══════════════════════════════════════════════════════════════╝ permissions: '0644' # Internal SSH private key (for accessing Forgejo and other internal servers) - path: /root/.ssh/id_ed25519 content: | ${indent(6, internal_private_key)} permissions: '0600' # SSH config for internal servers - path: /root/.ssh/config content: | Host 10.10.0.* StrictHostKeyChecking accept-new IdentityFile ~/.ssh/id_ed25519 User root permissions: '0600' runcmd: # Ensure sshd_config includes the .d directory (Debian 12 fix) - grep -q 'Include /etc/ssh/sshd_config.d' /etc/ssh/sshd_config || sed -i '1i Include /etc/ssh/sshd_config.d/*.conf' /etc/ssh/sshd_config # Comment out Port in main sshd_config so sshd_config.d takes precedence (Debian 12 fix) - sed -i 's/^Port /#Port /' /etc/ssh/sshd_config # Restart SSH with new configuration - systemctl restart sshd # Wait for any background apt processes to finish (DO images run apt on boot) - while fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1; do echo "Waiting for dpkg lock..."; sleep 5; done # Install all required packages (more reliable than packages: section on DO images) - apt-get update - DEBIAN_FRONTEND=noninteractive apt-get -o DPkg::Lock::Timeout=60 install -y fail2ban ufw unattended-upgrades apt-listchanges curl vim # Enable and start fail2ban - systemctl enable fail2ban - systemctl restart fail2ban # Configure firewall - /usr/local/bin/configure-firewall.sh # Enable unattended upgrades - systemctl enable unattended-upgrades - systemctl start unattended-upgrades final_message: "Jump host initialization complete after $UPTIME seconds"