Skip to content

Commit

Permalink
fix: update bastion script logic
Browse files Browse the repository at this point in the history
  • Loading branch information
sean-freeman committed Nov 25, 2024
1 parent f2d0cef commit 5d97ffd
Show file tree
Hide file tree
Showing 5 changed files with 576 additions and 172 deletions.
189 changes: 147 additions & 42 deletions aws_ec2_instance/bastion_inject/bastion_provision.tf
Original file line number Diff line number Diff line change
Expand Up @@ -57,47 +57,6 @@ resource "null_resource" "bastion_ssh_configure" {
aws_route_table_association.vpc_bastion_rt_associate
]

# Host Private Key apply file permissions
provisioner "remote-exec" {
inline = [
"echo 'Create ${var.module_var_bastion_user} without sudoer'",
"sudo su - root -c 'useradd --create-home ${var.module_var_bastion_user}'",
"sudo su - root -c 'mkdir -p /home/${var.module_var_bastion_user}/.ssh'",
"sudo su - root -c 'touch /home/${var.module_var_bastion_user}/.ssh/authorized_keys'",
"sudo su - root -c 'echo \"${var.module_var_bastion_public_ssh_key}\" > /home/${var.module_var_bastion_user}/.ssh/authorized_keys'",
"if [ $(grep ^ID= /etc/os-release | cut -d '=' -f2 | tr -d '\"') = 'rhel' ] ; then sudo su - root -c 'chown -R ${var.module_var_bastion_user}:${var.module_var_bastion_user} /home/${var.module_var_bastion_user}/.ssh' ; fi",
"if [ $(grep ^ID= /etc/os-release | cut -d '=' -f2 | tr -d '\"') = 'sles' ] || [ $(grep ^ID= /etc/os-release | cut -d '=' -f2 | tr -d '\"') = 'sles_sap' ] ; then sudo su - root -c 'chown -R ${var.module_var_bastion_user}:users /home/${var.module_var_bastion_user}/.ssh' ; fi",
"sudo su - root -c 'chmod 700 /home/${var.module_var_bastion_user}/.ssh'",
"sudo su - root -c 'chmod 600 /home/${var.module_var_bastion_user}/.ssh/authorized_keys'",
"echo '${var.module_var_bastion_user} is created'",
"echo 'Installing firewalld'",
"if [ $(grep ^ID= /etc/os-release | cut -d '=' -f2 | tr -d '\"') = 'rhel' ] ; then echo 'RHEL detected, yum install firewalld' && yum --assumeyes --debuglevel=1 install firewalld ; fi",
"if [ $(grep ^ID= /etc/os-release | cut -d '=' -f2 | tr -d '\"') = 'sles' ] || [ $(grep ^ID= /etc/os-release | cut -d '=' -f2 | tr -d '\"') = 'sles_sap' ] ; then echo 'SLES detected, zypper install --no-confirm firewalld' && zypper install --no-confirm firewalld ; fi",
"echo 'Activate firewalld'",
"sudo su - root -c 'systemctl start firewalld'",
"sudo su - root -c 'systemctl enable firewalld'",
"echo 'Changing SSH Port to within IANA Dynamic Ports range'",
"sudo su - root -c 'sed -i \"s/#Port 22/Port ${var.module_var_bastion_ssh_port}/\" /etc/ssh/sshd_config'",
"if [ $(getenforce) = 'Enforcing' ]; then echo 'SELinux status as enforcing/enabled detected, inform SELinux about port change' && sudo su - root -c 'semanage port -a -t ssh_port_t -p tcp ${var.module_var_bastion_ssh_port}'; fi",
"if [ $(grep ^ID= /etc/os-release | cut -d '=' -f2 | tr -d '\"') = 'rhel' ] && [ $(grep ^VERSION_ID= /etc/os-release | grep '=\"8') ]; then echo 'RHEL 8.x detected, adding port to firewall-cmd' && sudo su - root -c 'firewall-cmd --add-port ${var.module_var_bastion_ssh_port}/tcp' && sudo su - root -c 'firewall-cmd --add-port ${var.module_var_bastion_ssh_port}/tcp --permanent' ; fi",
"if [ $(grep ^ID= /etc/os-release | cut -d '=' -f2 | tr -d '\"') = 'rhel' ] && [ $(grep ^VERSION_ID= /etc/os-release | grep '=\"8') ]; then echo 'RHEL 8.x detected, amending /etc/ssh/ssh_config to permit AllowTcpForwarding' && sudo su - root -c 'sed -i \"s/#AllowTcpForwarding yes/AllowTcpForwarding yes/\" /etc/ssh/sshd_config' ; fi",
"if [ $(grep ^ID= /etc/os-release | cut -d '=' -f2 | tr -d '\"') = 'sles' ] || [ $(grep ^ID= /etc/os-release | cut -d '=' -f2 | tr -d '\"') = 'sles_sap' ] && [ $(grep ^VERSION_ID= /etc/os-release | grep '=\"15') ]; then echo 'SLES 15.x detected, adding port to firewall-cmd' && sudo su - root -c 'firewall-cmd --add-port ${var.module_var_bastion_ssh_port}/tcp' && sudo su - root -c 'firewall-cmd --add-port ${var.module_var_bastion_ssh_port}/tcp --permanent' ; fi",
"if [ $(grep ^ID= /etc/os-release | cut -d '=' -f2 | tr -d '\"') = 'sles' ] || [ $(grep ^ID= /etc/os-release | cut -d '=' -f2 | tr -d '\"') = 'sles_sap' ] && [ $(grep ^VERSION_ID= /etc/os-release | grep '=\"15') ]; then echo 'SLES 15.x detected, amending /etc/ssh/ssh_config to permit AllowTcpForwarding' && sudo su - root -c 'sed -i \"s/#AllowTcpForwarding yes/AllowTcpForwarding yes/\" /etc/ssh/sshd_config' ; fi",
"echo 'Removing Root SSH Login for Bastion from Public IP'",
"sudo su - root -c 'sed -i \"s/PermitRootLogin yes/PermitRootLogin no/\" /etc/ssh/sshd_config'",
"echo 'Allowing only Root SSH Login for Bastion from Private IP range of the VPC Subnet (i.e. login to root on Bastion from Host/s only)'",
"sudo su - root -c 'echo \"Match Address ${data.aws_subnet.vpc_subnet.cidr_block}\" >> /etc/ssh/sshd_config'",
"sudo su - root -c 'echo \"PermitRootLogin yes\" >> /etc/ssh/sshd_config'",
"echo 'Reload sshd service after sshd_config changes'",
"sudo su - root -c 'systemctl restart sshd'",
"echo 'SSH Port now listening on...'",
"sudo su - root -c 'netstat -tlpn | grep ssh' || echo 'netstat not found, ignoring command'", // Use else command to avoid Terraform breaking error "executing "/tmp/terraform_xxxxxxxxxx.sh": Process exited with status 1". REPLACE WITH: ss -tunlp | grep ssh
"echo 'Disable ec2-user'",
"sudo mv /home/ec2-user/.ssh/authorized_keys /home/ec2-user/.ssh/disabled_keys",
"echo 'Disabled the ec2-user'"
]
}

connection {
type = "ssh"
user = "ec2-user"
Expand All @@ -107,7 +66,153 @@ resource "null_resource" "bastion_ssh_configure" {
# Required when using RHEL 8.x because /tmp is set with noexec
# Path must already exist and must not use Bash shell special variable, e.g. cannot use $HOME/terraform/tmp/
# https://www.terraform.io/language/resources/provisioners/connection#executing-scripts-using-ssh-scp
script_path = "/home/ec2-user/terraform_tmp_remote_exec_inline.sh"
# script_path = "/home/ec2-user/terraform_tmp_remote_exec_inline.sh"
}

# Path must already exist and must not use Bash shell special variable, e.g. cannot use $HOME/file.sh
# "By default, OpenSSH's scp implementation runs in the remote user's home directory and so you can specify a relative path to upload into that home directory"
# https://www.terraform.io/language/resources/provisioners/file#destination-paths
provisioner "file" {
destination = "bastion_script.sh"
content = <<EOT
#!/bin/bash
echo '---- Sleep 20s to ensure bastion host is ready -----' && sleep 20
echo 'Create ${var.module_var_bastion_user} without sudoer'
useradd --create-home ${var.module_var_bastion_user}
mkdir -p /home/${var.module_var_bastion_user}/.ssh
/bin/cp -f /home/ec2-user/.ssh/authorized_keys /home/${var.module_var_bastion_user}/.ssh/authorized_keys
if [ $(grep ^ID= /etc/os-release | cut -d '=' -f2 | tr -d '\"') = 'rhel' ]; then chown -R ${var.module_var_bastion_user}:${var.module_var_bastion_user} /home/${var.module_var_bastion_user}/.ssh ; fi
if [ $(grep ^ID= /etc/os-release | cut -d '=' -f2 | tr -d '\"') = 'sles' ] || [ $(grep ^ID= /etc/os-release | cut -d '=' -f2 | tr -d '\"') = 'sles_sap' ]; then chown -R ${var.module_var_bastion_user}:users /home/${var.module_var_bastion_user}/.ssh ; fi
chmod 750 /home/${var.module_var_bastion_user}/.ssh
chmod 600 /home/${var.module_var_bastion_user}/.ssh/authorized_keys
echo '${var.module_var_bastion_user} is created'
echo 'Changing SSH Port to within IANA Dynamic Ports range'
sed -i 's/#Port 22/Port ${var.module_var_bastion_ssh_port}/' /etc/ssh/sshd_config
echo 'Enable SSH AllowTcpForwarding'
sed -i 's/#AllowTcpForwarding yes/AllowTcpForwarding yes/' /etc/ssh/sshd_config
echo 'Removing Root SSH Login for Bastion from Public IP'
sed -i 's/PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
sed -i 's/#PermitRootLogin/PermitRootLogin/' /etc/ssh/sshd_config
echo 'Allow SSH Login to root user only from the Bastion's private Subnet range (i.e. no root login using Public IP)'
echo 'Match Address ${data.aws_subnet.vpc_subnet.cidr_block}' >> /etc/ssh/sshd_config
echo 'PermitRootLogin yes' >> /etc/ssh/sshd_config
echo 'Reload sshd service after sshd_config changes'
systemctl restart sshd
echo 'SSH Port now listening on...'
# Use else command to avoid Terraform breaking error "executing "/tmp/terraform_xxxxxxxxxx.sh": Process exited with status 1". REPLACE WITH: ss -tunlp | grep ssh
if [ $(grep ^ID= /etc/os-release | cut -d '=' -f2 | tr -d '\"') = 'rhel' ]; then yum --assumeyes --debuglevel=1 install net-tools ; fi
if [ $(grep ^ID= /etc/os-release | cut -d '=' -f2 | tr -d '\"') = 'sles' ] || [ $(grep ^ID= /etc/os-release | cut -d '=' -f2 | tr -d '\"') = 'sles_sap' ]; then zypper install --no-confirm net-tools ; fi
netstat -tlpn | grep ssh || echo 'netstat not found, ignoring command'
echo 'Amending SELinux if present'
if [ $(getenforce) = 'Enforcing' ]; then echo 'SELinux status as enforcing/enabled detected, inform SELinux about port change' && semanage port -a -t ssh_port_t -p tcp ${var.module_var_bastion_ssh_port}; fi
if [ $(grep ^ID= /etc/os-release | cut -d '=' -f2 | tr -d '\"') = 'rhel' ] && [ $(grep ^VERSION_ID= /etc/os-release | grep '="7') ]; then
echo 'RHEL 7.x detected, use firewalld and iptables'
echo 'RHEL detected, yum install firewalld'
yum --assumeyes --debuglevel=1 install firewalld
echo 'Activate firewalld'
systemctl start firewalld
systemctl enable firewalld
echo 'Allow new SSH Port'
firewall-cmd --add-port ${var.module_var_bastion_ssh_port}/tcp
firewall-cmd --add-port ${var.module_var_bastion_ssh_port}/tcp --permanent
firewall-cmd --reload
# Detection of Primary Network Interface
# Find network adapter - identify the adapter, by showing which is used for the Default Gateway route
# If statement to catch RHEL installations with route table multiple default entries
# https://serverfault.com/questions/47915/how-do-i-get-the-default-gateway-in-linux-given-the-destination
ACTIVE_NETWORK_ADAPTER=$(ip route show default 0.0.0.0/0 | awk '/default/ && !/metric/ {print $5}')
CURRENT_IP=$(ip -oneline address show $ACTIVE_NETWORK_ADAPTER | sed -n 's/.*inet \(.*\)\/.*/\1/p')
# Drop SSH Port 22 and ICMP Ping connection attempts
# Append rule to iptables chain
iptables --append INPUT --protocol tcp --dport 22 --in-interface $ACTIVE_NETWORK_ADAPTER --destination $CURRENT_IP --jump DROP
iptables --append INPUT --protocol udp --dport 22 --in-interface $ACTIVE_NETWORK_ADAPTER --destination $CURRENT_IP --jump DROP
iptables --append INPUT --protocol icmp --icmp-type echo-request --in-interface $ACTIVE_NETWORK_ADAPTER --destination $CURRENT_IP --jump DROP
fi
if [ $(grep ^ID= /etc/os-release | cut -d '=' -f2 | tr -d '\"') = 'rhel' ] && [ $(grep ^VERSION_ID= /etc/os-release | grep '="8\|="9') ]; then
echo 'RHEL 8.x/9.x detected, use nftables'
echo 'Ensure firewalld is disabled (nftables (Netfilter service is auto disabled when firewalld enabled)'
systemctl stop firewalld
systemctl disable firewalld
systemctl mask firewalld
echo 'Ensure nftables installed, and install'
yum --assumeyes --debuglevel=1 install nftables
systemctl start nftables
systemctl enable nftables
# Checking status will cause Terraform session to break, so grep active line to confirm running
sudo systemctl status nftables | grep "Loaded:"
sudo systemctl status nftables | grep "Active:"
echo 'Create Table with family as "inet" (for both ip and ip6 families)'
nft add table inet ssh_drop_table
echo 'Create Table Chain with type as "filter" and hook as "prerouting" (for inet, hooks are prerouting,input,forward,output,postrouting,ingress)'
nft add chain inet ssh_drop_table ssh_drop_filter_chain { type filter hook prerouting priority 0 \; }
# Use background (& suffix) to avoid lock-out of current script
echo 'Create Rule inside Table Chain (add to end of chain, or insert to top of chain)'
nft add rule inet ssh_drop_table ssh_drop_filter_chain icmp type { echo-request, echo-reply } log prefix \"[iptables_SSHDROP] \" drop
nft add rule inet ssh_drop_table ssh_drop_filter_chain icmpv6 type { echo-request, echo-reply } log prefix \"[iptables_SSHDROP] \" drop
nohup bash -c 'sleep 5; nft add rule inet ssh_drop_table ssh_drop_filter_chain tcp dport 22 log prefix \"[iptables_SSHDROP] \" drop' &>/dev/null & disown
nohup bash -c 'sleep 5; nft add rule inet ssh_drop_table ssh_drop_filter_chain udp dport 22 log prefix \"[iptables_SSHDROP] \" drop' &>/dev/null & disown
# Show tables
# nft list ruleset
fi
if [ $(grep ^ID= /etc/os-release | cut -d '=' -f2 | tr -d '\"') = 'sles' ] || [ $(grep ^ID= /etc/os-release | cut -d '=' -f2 | tr -d '\"') = 'sles_sap' ] && [ $(grep ^VERSION_ID= /etc/os-release | grep '="15') ]; then
echo 'SLES 15.x detected, use nftables'
echo 'Ensure firewalld is disabled (nftables (Netfilter service is auto disabled when firewalld enabled)'
systemctl stop firewalld
systemctl disable firewalld
systemctl mask firewalld
echo 'Ensure nftables installed, and install'
zypper install --no-confirm nftables
systemctl start nftables
systemctl enable nftables
# Checking status will cause Terraform session to break, so grep active line to confirm running
sudo systemctl status nftables | grep "Loaded:"
sudo systemctl status nftables | grep "Active:"
echo 'Create Table with family as "inet" (for both ip and ip6 families)'
nft add table inet ssh_drop_table
echo 'Create Table Chain with type as "filter" and hook as "prerouting" (for inet, hooks are prerouting,input,forward,output,postrouting,ingress)'
nft add chain inet ssh_drop_table ssh_drop_filter_chain { type filter hook prerouting priority 0 \; }
# Use background (& suffix) to avoid lock-out of current script
echo 'Create Rule inside Table Chain (add to end of chain, or insert to top of chain)'
nft add rule inet ssh_drop_table ssh_drop_filter_chain icmp type { echo-request, echo-reply } log prefix \"[iptables_SSHDROP] \" drop
nft add rule inet ssh_drop_table ssh_drop_filter_chain icmpv6 type { echo-request, echo-reply } log prefix \"[iptables_SSHDROP] \" drop
nohup bash -c 'sleep 5; nft add rule inet ssh_drop_table ssh_drop_filter_chain tcp dport 22 log prefix \"[iptables_SSHDROP] \" drop' &>/dev/null & disown
nohup bash -c 'sleep 5; nft add rule inet ssh_drop_table ssh_drop_filter_chain udp dport 22 log prefix \"[iptables_SSHDROP] \" drop' &>/dev/null & disown
# Show tables
# nft list ruleset
fi
echo 'Disable ec2-user'
sudo mv /home/ec2-user/.ssh/authorized_keys /home/ec2-user/.ssh/disabled_keys
echo 'Disabled the ec2-user'
EOT
}

provisioner "remote-exec" {
inline = [
"chmod +x /home/ec2-user/bastion_script.sh ; sudo su - root -c 'bash /home/ec2-user/bastion_script.sh'"
]
}

}
Loading

0 comments on commit 5d97ffd

Please sign in to comment.