176 lines
5.8 KiB
Smarty
176 lines
5.8 KiB
Smarty
|
|
#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"
|