--- title: "Bastion Host On DigitalOcean" date: 2021-09-14T21:17:12+06:00 image: "images/blog/blog-post-4.jpg" author: "Edwin Lyon" categories: ["cybersecurity","cloud"] tags: ["ubuntu","harden","security","linux","digital ocean","bastion-host","cloud"] description : "Hardening Your Ubuntu 20.0.4 LTS Cloud Server With A Bastion Host" draft: false type: "post" --- ## **What is a Bastion Host?** A bastion host is a special-purpose computer on a network specifically designed and configured to withstand attacks. There are two common network configurations that include bastion hosts and their placement. The first requires two firewalls, with bastion hosts sitting between the first "outside world" firewall, and an inside firewall, in a DMZ. Often, smaller networks do not have multiple firewalls, so if only one firewall exists in a network, bastion hosts are commonly placed outside the firewall. ### **Getting Started** You can use the referral badge below to get started with a $100 credit from Digital Ocean or use this link to [DigitalOcean](https://m.do.co/c/42cf2120197b). [![DigitalOcean Referral Badge](https://web-platforms.sfo2.cdn.digitaloceanspaces.com/WWW/Badge%201.svg)](https://www.digitalocean.com/?refcode=42cf2120197b&utm_campaign=Referral_Invite&utm_medium=Referral_Program&utm_source=badge) ### **DigitalOcean VPC** On 7 April, 2020, the VPC service replaced the Private Networking service on DigitalOcean. > A Virtual Private Cloud (VPC) is a private network interface for collections of DigitalOcean resources. VPC networks provide a more secure connection between resources because the network is inaccessible from the public internet and other VPC networks. Traffic within a VPC network doesn’t count against bandwidth usage. VPC are available at no additional cost and are enabled by default. They serve the same function as VLANs do. You have two options, you can either manual create a VPC network or if you don't have a VPC network DigitalOcean will create it for you when you build a new VPS. ### **DigitalOcean Cloud Firewalls** > Cloud Firewalls affect both public and VPC network traffic. Rules specific to either must specify the public or private IP range. We will be creating two cloud firewall rules, one named public-network and the other named private-network. These will be used as Access Control Lists to help protect our VPC network. Both the Public-Network and Private-Network cloud firewalls should be added to the bastion-host, while only the Private-Network cloud firewall should be added to all other members of your VPS. **PUBLIC-NETWORK** * INBOUND RULES : **Type** | **Protocol** | **Port Range** | **Sources** :--- | :--- | :--- | :--- ICMP | ICMP | None | All IPv4, All IPv6 SSH | TCP | 22 | All IPv4, All IPv6 HTTP | TCP | 80 | All IPv4, All IPv6 HTTPS | TCP | 443 | All IPv4, All IPv6 CUSTOM | UDP | 51820 | All IPv4, All IPv6 * OUTBOUND RULES : **Type** | **Protocol** | **Port Range** | **Sources** :--- | :--- | :--- | :--- ICMP | ICMP | None | All IPv4, All IPv6 All TCP | TCP | All Ports | All IPv4, All IPv6 All UDP | UDP | All Ports | All IPv4, All IPv6 **PRIVATE-NETWORK** * INBOUND RULES : **Type** | **Protocol** | **Port Range** | **Sources** :--- | :--- | :--- | :--- ICMP | ICMP | None | 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 All TCP | TCP | All Ports | 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 All UDP | UDP | All Ports | 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 * OUTBOUND RULES : **Type** | **Protocol** | **Port Range** | **Sources** :--- | :--- | :--- | :--- ICMP | ICMP | None | All IPv4 All TCP | TCP | All Ports | All IPv4 All UDP | UDP | All Ports | All IPv4 I also recommend creating new ssh keys to add to your bastion-host. ```bash ssh-keygen -b 4096 -a 1000 -t rsa -f ~/.ssh/id_rsa ``` Let's lock down your ssh service. ```bash $ sudo mv /etc/ssh/sshd_config /etc/ssh/sshd_config.bak # Harden SSH Settings $ sudo cat <<-EOF > /etc/ssh/sshd_config HostKey /etc/ssh/ssh_host_ed25519_key HostKey /etc/ssh/ssh_host_rsa_key HostKey /etc/ssh/ssh_host_ecdsa_key AcceptEnv LANG LC_* AllowGroups root sudo Banner /etc/issue.net ChallengeResponseAuthentication no Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr ClientAliveCountMax 0 ClientAliveInterval 300 Compression no HostbasedAuthentication no IgnoreUserKnownHosts yes KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256 LoginGraceTime 20 LogLevel VERBOSE Macs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256 MaxAuthTries 3 MaxSessions 3 MaxStartups 10:30:60 PermitEmptyPasswords no PermitRootLogin no PubkeyAuthentication yes PasswordAuthentication no PermitUserEnvironment no PrintLastLog yes PrintMotd no StrictModes yes Subsystem sftp internal-sftp UseDNS no UsePAM yes X11Forwarding no AllowTcpForwarding yes EOF ``` Create a new set of ssh host keys. ```bash ## Update ssh_host keys rm /etc/ssh/ssh_host_* ssh-keygen -t ecdsa -b 521 -f /etc/ssh/ssh_host_ecdsa_key -N "" ssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N "" ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N "" awk '$5 >= 3071' /etc/ssh/moduli > /etc/ssh/moduli.safe mv /etc/ssh/moduli.safe /etc/ssh/moduli ``` We need to edit the netplan for both the bastion-host and the webproxy so that the bastion-host handles all routing. ```bash sudo nano /etc/netplan/50-cloud-init.yaml ``` You can read more details on editing your netplan on DigitalOcean. ```nano network: version: 2 ethernets: eth0: addresses: - xxx.xxx.xxx.xxx/20 - 26xx:xxxx:x:xxx::xx:xxxx/64 gateway4: xxx.xxx.xxx.1 gateway6: 26xx:xxxx:x:xxx::1 match: macaddress: ab:ab:ab:ab:ab:ab nameservers: addresses: - 1.1.1.1 - 1.0.0.1 - 2606:4700:4700::1111 - 2606:4700:4700::1001 search: [technerdonline.com] eth1: addresses: - 10.128.0.2/20 match: macaddress: ba:ba:ba:ba:ba:ba nameservers: addresses: - 10.128.0.2 search: [local] routes: - to: 10.128.0.0/20 via: 10.128.0.2 ``` On the proxy server make the following netplan change. ```nano network: version: 2 ethernets: eth0: addresses: - xxx.xxx.xxx.xxx/20 - 26xx:xxxx:x:xxx::xx:xxxx/64 #gateway4: xxx.xxx.xxx.1 #gateway6: 26xx:xxxx:x:xxx::1 match: macaddress: ab:ab:ab:ab:ab:ab nameservers: addresses: - 1.1.1.1 - 1.0.0.1 - 2606:4700:4700::1111 - 2606:4700:4700::1001 search: [technerdonline.com] eth1: addresses: - 10.128.0.3/20 match: macaddress: ba:ba:ba:ba:ba:ba nameservers: addresses: - 10.128.0.2 search: [local] routes: - to: 0.0.0.0/0 via: 10.128.0.2 ``` Apply the netplan changes. ```bash sudo netplan apply ``` We will need to create a set of IPTABLES rules for both IPv4 and IPv6 but first we need to load some Kernel modules. ```bash sudo nano /etc/modules-load.d/iptables.conf ``` ```nano overlay br_netfilter ip_vs ip_vs_rr ip_vs_wrr ip_vs_sh nf_conntrack iptable_nat iptable_filter iptable_mangle ip_nf_target_redirect ip_set ip_vs_nfct ip_vs_proto_tcp ip_vs_proto_udp veth bridge bridge_netfilter ip_nf_filter ip_nf_target_masquerade netfilter_xt_match_addrtype netfilter_xt_match_conntrack netfilter_xt_match_ipvs nf_nat ``` Copy and paste the following content, replacing PUBLIC_IP with the public IP address of the bastion-host, WEBPROXY_PRIVATE_IP with the VPC IP address for the webproxy, and BASTION_PRIVATE_IP with the VPC IP address with the bastion host private IP. ```bash nano ipv4.conf ``` ```nano *mangle :PREROUTING ACCEPT [0:0] :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] COMMIT *nat :PREROUTING ACCEPT [0:0] :INPUT ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] -A PREROUTING -i eth0 -d {PUBLIC_IP} -p tcp -m tcp --dport 80 -j DNAT --to-destination {WEBPROXY_PRIVATE_IP}:80 -A PREROUTING -i eth0 -d {PUBLIC_IP} -p tcp -m tcp --dport 443 -j DNAT --to-destination {WEBPROXY_PRIVATE_IP}:443 -A POSTROUTING -d {WEBPROXY_PRIVATE_IP} -o eth1 -p tcp -m tcp --dport 80 -j SNAT --to-source {BASTION_PRIVATE_IP} -A POSTROUTING -d {WEBPROXY_PRIVATE_IP} -o eth1 -p tcp -m tcp --dport 443 -j SNAT --to-source {BASTION_PRIVATE_IP} -A POSTROUTING -s {BASTION_PRIVATE_IP} -o eth0 -j SNAT --to-source {PUBLIC_IP} -A POSTROUTING -s {PRIVATE_SUBNET} ! -d {PRIVATE_SUBNET} -j MASQUERADE COMMIT *filter :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT ACCEPT [0:0] :FILTERS - [0:0] -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A INPUT -i lo -j ACCEPT -A INPUT -m conntrack --ctstate INVALID -j DROP -A INPUT -p icmp -m icmp --icmp-type 8 -m limit --limit 5/sec -j ACCEPT -A INPUT -i eth1 -m conntrack --ctstate NEW -s {PRIVATE_SUBNET} -j ACCEPT -A INPUT -j FILTERS -A INPUT -j DROP -A FORWARD -o eth1 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A FORWARD -i eth1 -o eth1 -m conntrack --ctstate NEW -s {PRIVATE_SUBNET} -j ACCEPT -A FORWARD -o eth0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A FORWARD -i eth1 -o eth0 -m conntrack --ctstate NEW -s {PRIVATE_SUBNET} -j ACCEPT -A FORWARD -i eth0 -o eth1 -j FILTERS -A OUTPUT -o lo -j ACCEPT -A OUTPUT -o eth0 -j ACCEPT -A OUTPUT -o eth1 -j ACCEPT -A FILTERS -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A FILTERS -p tcp -m conntrack --ctstate NEW -m tcp --syn --dport 22 -j ACCEPT -A FILTERS -p tcp -m conntrack --ctstate NEW -m tcp --syn --dport 80 -j ACCEPT -A FILTERS -p tcp -m conntrack --ctstate NEW -m tcp --syn --dport 443 -j ACCEPT -A FILTERS -p udp -m conntrack --ctstate NEW -m udp --dport 51820 -j ACCEPT -A FILTERS -p udp -m conntrack --ctstate NEW -m udp --dport 51821 -j ACCEPT -A FILTERS -m conntrack --ctstate INVALID -j DROP -A FILTERS -j REJECT COMMIT ``` Now create IPTABLES Rules for IPv6. ```bash nano ipv6.conf ``` ```nano *nat :PREROUTING ACCEPT [0:0] :INPUT ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] COMMIT *filter :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT ACCEPT [0:0] :FILTERS - [0:0] -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A INPUT -i lo -j ACCEPT -A INPUT -m conntrack --ctstate INVALID -j DROP -A INPUT -i eth0 -p ipv6-icmp -m icmp6 --icmpv6-type 128 -m limit --limit 5/sec -j ACCEPT -A INPUT -i eth0 -p ipv6-icmp -m icmp6 --icmpv6-type 133 -m limit --limit 5/sec -j ACCEPT -A INPUT -i eth0 -p ipv6-icmp -m icmp6 --icmpv6-type 134 -m limit --limit 5/sec -j ACCEPT -A INPUT -i eth0 -p ipv6-icmp -m icmp6 --icmpv6-type 135 -m limit --limit 5/sec -j ACCEPT -A INPUT -j FILTERS -A INPUT -j DROP -A FILTERS -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A FILTERS -p tcp -m conntrack --ctstate NEW -m tcp --dport 80 --tcp-flags FIN,SYN,RST,ACK SYN -j ACCEPT -A FILTERS -p tcp -m conntrack --ctstate NEW -m tcp --dport 443 --tcp-flags FIN,SYN,RST,ACK SYN -j ACCEPT -A FILTERS -m conntrack --ctstate INVALID -j DROP -A FILTERS -j REJECT -A OUTPUT -o lo -j ACCEPT -A OUTPUT -o eth0 -j ACCEPT -A OUTPUT -o eth1 -j ACCEPT -A FORWARD -o eth1 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A FORWARD -i eth1 -o eth1 -j FILTERS -A FORWARD -o eth0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A FORWARD -i eth1 -o eth0 -m conntrack --ctstate NEW -j ACCEPT -A FORWARD -i eth0 -o eth1 -j FILTERS -A FORWARD -j REJECT COMMIT ``` Apply the iptables rules and install iptables-persistent. ```bash sudo iptables-restore -n ipv4.conf sudo ip6tables-restore -n ipv6.conf sudo iptables-save sudo ip6tables-save sudo apt install iptables-persistent ``` Simply install your favorite web server on the proxy droplet (i.e. nginx, caddy, haproxy etc). I would also suggest installing wireguard on the bastion host, it is also pretty easy to get a secure wireguard mesh network setup if you have multiple VPC.