Skip to content

Commit 5d97ffd

Browse files
committed
fix: update bastion script logic
1 parent f2d0cef commit 5d97ffd

File tree

5 files changed

+576
-172
lines changed

5 files changed

+576
-172
lines changed

aws_ec2_instance/bastion_inject/bastion_provision.tf

Lines changed: 147 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -57,47 +57,6 @@ resource "null_resource" "bastion_ssh_configure" {
5757
aws_route_table_association.vpc_bastion_rt_associate
5858
]
5959

60-
# Host Private Key apply file permissions
61-
provisioner "remote-exec" {
62-
inline = [
63-
"echo 'Create ${var.module_var_bastion_user} without sudoer'",
64-
"sudo su - root -c 'useradd --create-home ${var.module_var_bastion_user}'",
65-
"sudo su - root -c 'mkdir -p /home/${var.module_var_bastion_user}/.ssh'",
66-
"sudo su - root -c 'touch /home/${var.module_var_bastion_user}/.ssh/authorized_keys'",
67-
"sudo su - root -c 'echo \"${var.module_var_bastion_public_ssh_key}\" > /home/${var.module_var_bastion_user}/.ssh/authorized_keys'",
68-
"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",
69-
"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",
70-
"sudo su - root -c 'chmod 700 /home/${var.module_var_bastion_user}/.ssh'",
71-
"sudo su - root -c 'chmod 600 /home/${var.module_var_bastion_user}/.ssh/authorized_keys'",
72-
"echo '${var.module_var_bastion_user} is created'",
73-
"echo 'Installing firewalld'",
74-
"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",
75-
"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",
76-
"echo 'Activate firewalld'",
77-
"sudo su - root -c 'systemctl start firewalld'",
78-
"sudo su - root -c 'systemctl enable firewalld'",
79-
"echo 'Changing SSH Port to within IANA Dynamic Ports range'",
80-
"sudo su - root -c 'sed -i \"s/#Port 22/Port ${var.module_var_bastion_ssh_port}/\" /etc/ssh/sshd_config'",
81-
"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",
82-
"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",
83-
"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",
84-
"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",
85-
"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",
86-
"echo 'Removing Root SSH Login for Bastion from Public IP'",
87-
"sudo su - root -c 'sed -i \"s/PermitRootLogin yes/PermitRootLogin no/\" /etc/ssh/sshd_config'",
88-
"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)'",
89-
"sudo su - root -c 'echo \"Match Address ${data.aws_subnet.vpc_subnet.cidr_block}\" >> /etc/ssh/sshd_config'",
90-
"sudo su - root -c 'echo \"PermitRootLogin yes\" >> /etc/ssh/sshd_config'",
91-
"echo 'Reload sshd service after sshd_config changes'",
92-
"sudo su - root -c 'systemctl restart sshd'",
93-
"echo 'SSH Port now listening on...'",
94-
"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
95-
"echo 'Disable ec2-user'",
96-
"sudo mv /home/ec2-user/.ssh/authorized_keys /home/ec2-user/.ssh/disabled_keys",
97-
"echo 'Disabled the ec2-user'"
98-
]
99-
}
100-
10160
connection {
10261
type = "ssh"
10362
user = "ec2-user"
@@ -107,7 +66,153 @@ resource "null_resource" "bastion_ssh_configure" {
10766
# Required when using RHEL 8.x because /tmp is set with noexec
10867
# Path must already exist and must not use Bash shell special variable, e.g. cannot use $HOME/terraform/tmp/
10968
# https://www.terraform.io/language/resources/provisioners/connection#executing-scripts-using-ssh-scp
110-
script_path = "/home/ec2-user/terraform_tmp_remote_exec_inline.sh"
69+
# script_path = "/home/ec2-user/terraform_tmp_remote_exec_inline.sh"
70+
}
71+
72+
# Path must already exist and must not use Bash shell special variable, e.g. cannot use $HOME/file.sh
73+
# "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"
74+
# https://www.terraform.io/language/resources/provisioners/file#destination-paths
75+
provisioner "file" {
76+
destination = "bastion_script.sh"
77+
content = <<EOT
78+
#!/bin/bash
79+
echo '---- Sleep 20s to ensure bastion host is ready -----' && sleep 20
80+
81+
echo 'Create ${var.module_var_bastion_user} without sudoer'
82+
useradd --create-home ${var.module_var_bastion_user}
83+
mkdir -p /home/${var.module_var_bastion_user}/.ssh
84+
85+
/bin/cp -f /home/ec2-user/.ssh/authorized_keys /home/${var.module_var_bastion_user}/.ssh/authorized_keys
86+
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
87+
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
88+
chmod 750 /home/${var.module_var_bastion_user}/.ssh
89+
chmod 600 /home/${var.module_var_bastion_user}/.ssh/authorized_keys
90+
echo '${var.module_var_bastion_user} is created'
91+
92+
echo 'Changing SSH Port to within IANA Dynamic Ports range'
93+
sed -i 's/#Port 22/Port ${var.module_var_bastion_ssh_port}/' /etc/ssh/sshd_config
94+
95+
echo 'Enable SSH AllowTcpForwarding'
96+
sed -i 's/#AllowTcpForwarding yes/AllowTcpForwarding yes/' /etc/ssh/sshd_config
97+
98+
echo 'Removing Root SSH Login for Bastion from Public IP'
99+
sed -i 's/PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
100+
sed -i 's/#PermitRootLogin/PermitRootLogin/' /etc/ssh/sshd_config
101+
echo 'Allow SSH Login to root user only from the Bastion's private Subnet range (i.e. no root login using Public IP)'
102+
echo 'Match Address ${data.aws_subnet.vpc_subnet.cidr_block}' >> /etc/ssh/sshd_config
103+
echo 'PermitRootLogin yes' >> /etc/ssh/sshd_config
104+
105+
echo 'Reload sshd service after sshd_config changes'
106+
systemctl restart sshd
107+
108+
echo 'SSH Port now listening on...'
109+
# Use else command to avoid Terraform breaking error "executing "/tmp/terraform_xxxxxxxxxx.sh": Process exited with status 1". REPLACE WITH: ss -tunlp | grep ssh
110+
if [ $(grep ^ID= /etc/os-release | cut -d '=' -f2 | tr -d '\"') = 'rhel' ]; then yum --assumeyes --debuglevel=1 install net-tools ; fi
111+
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
112+
netstat -tlpn | grep ssh || echo 'netstat not found, ignoring command'
113+
114+
echo 'Amending SELinux if present'
115+
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
116+
117+
if [ $(grep ^ID= /etc/os-release | cut -d '=' -f2 | tr -d '\"') = 'rhel' ] && [ $(grep ^VERSION_ID= /etc/os-release | grep '="7') ]; then
118+
echo 'RHEL 7.x detected, use firewalld and iptables'
119+
echo 'RHEL detected, yum install firewalld'
120+
yum --assumeyes --debuglevel=1 install firewalld
121+
echo 'Activate firewalld'
122+
systemctl start firewalld
123+
systemctl enable firewalld
124+
echo 'Allow new SSH Port'
125+
firewall-cmd --add-port ${var.module_var_bastion_ssh_port}/tcp
126+
firewall-cmd --add-port ${var.module_var_bastion_ssh_port}/tcp --permanent
127+
firewall-cmd --reload
128+
# Detection of Primary Network Interface
129+
# Find network adapter - identify the adapter, by showing which is used for the Default Gateway route
130+
# If statement to catch RHEL installations with route table multiple default entries
131+
# https://serverfault.com/questions/47915/how-do-i-get-the-default-gateway-in-linux-given-the-destination
132+
ACTIVE_NETWORK_ADAPTER=$(ip route show default 0.0.0.0/0 | awk '/default/ && !/metric/ {print $5}')
133+
CURRENT_IP=$(ip -oneline address show $ACTIVE_NETWORK_ADAPTER | sed -n 's/.*inet \(.*\)\/.*/\1/p')
134+
# Drop SSH Port 22 and ICMP Ping connection attempts
135+
# Append rule to iptables chain
136+
iptables --append INPUT --protocol tcp --dport 22 --in-interface $ACTIVE_NETWORK_ADAPTER --destination $CURRENT_IP --jump DROP
137+
iptables --append INPUT --protocol udp --dport 22 --in-interface $ACTIVE_NETWORK_ADAPTER --destination $CURRENT_IP --jump DROP
138+
iptables --append INPUT --protocol icmp --icmp-type echo-request --in-interface $ACTIVE_NETWORK_ADAPTER --destination $CURRENT_IP --jump DROP
139+
fi
140+
141+
if [ $(grep ^ID= /etc/os-release | cut -d '=' -f2 | tr -d '\"') = 'rhel' ] && [ $(grep ^VERSION_ID= /etc/os-release | grep '="8\|="9') ]; then
142+
echo 'RHEL 8.x/9.x detected, use nftables'
143+
echo 'Ensure firewalld is disabled (nftables (Netfilter service is auto disabled when firewalld enabled)'
144+
systemctl stop firewalld
145+
systemctl disable firewalld
146+
systemctl mask firewalld
147+
148+
echo 'Ensure nftables installed, and install'
149+
yum --assumeyes --debuglevel=1 install nftables
150+
systemctl start nftables
151+
systemctl enable nftables
152+
# Checking status will cause Terraform session to break, so grep active line to confirm running
153+
sudo systemctl status nftables | grep "Loaded:"
154+
sudo systemctl status nftables | grep "Active:"
155+
156+
echo 'Create Table with family as "inet" (for both ip and ip6 families)'
157+
nft add table inet ssh_drop_table
158+
159+
echo 'Create Table Chain with type as "filter" and hook as "prerouting" (for inet, hooks are prerouting,input,forward,output,postrouting,ingress)'
160+
nft add chain inet ssh_drop_table ssh_drop_filter_chain { type filter hook prerouting priority 0 \; }
161+
162+
# Use background (& suffix) to avoid lock-out of current script
163+
echo 'Create Rule inside Table Chain (add to end of chain, or insert to top of chain)'
164+
nft add rule inet ssh_drop_table ssh_drop_filter_chain icmp type { echo-request, echo-reply } log prefix \"[iptables_SSHDROP] \" drop
165+
nft add rule inet ssh_drop_table ssh_drop_filter_chain icmpv6 type { echo-request, echo-reply } log prefix \"[iptables_SSHDROP] \" drop
166+
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
167+
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
168+
169+
# Show tables
170+
# nft list ruleset
171+
fi
172+
173+
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
174+
echo 'SLES 15.x detected, use nftables'
175+
echo 'Ensure firewalld is disabled (nftables (Netfilter service is auto disabled when firewalld enabled)'
176+
systemctl stop firewalld
177+
systemctl disable firewalld
178+
systemctl mask firewalld
179+
180+
echo 'Ensure nftables installed, and install'
181+
zypper install --no-confirm nftables
182+
systemctl start nftables
183+
systemctl enable nftables
184+
# Checking status will cause Terraform session to break, so grep active line to confirm running
185+
sudo systemctl status nftables | grep "Loaded:"
186+
sudo systemctl status nftables | grep "Active:"
187+
188+
echo 'Create Table with family as "inet" (for both ip and ip6 families)'
189+
nft add table inet ssh_drop_table
190+
191+
echo 'Create Table Chain with type as "filter" and hook as "prerouting" (for inet, hooks are prerouting,input,forward,output,postrouting,ingress)'
192+
nft add chain inet ssh_drop_table ssh_drop_filter_chain { type filter hook prerouting priority 0 \; }
193+
194+
# Use background (& suffix) to avoid lock-out of current script
195+
echo 'Create Rule inside Table Chain (add to end of chain, or insert to top of chain)'
196+
nft add rule inet ssh_drop_table ssh_drop_filter_chain icmp type { echo-request, echo-reply } log prefix \"[iptables_SSHDROP] \" drop
197+
nft add rule inet ssh_drop_table ssh_drop_filter_chain icmpv6 type { echo-request, echo-reply } log prefix \"[iptables_SSHDROP] \" drop
198+
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
199+
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
200+
201+
# Show tables
202+
# nft list ruleset
203+
fi
204+
205+
echo 'Disable ec2-user'
206+
sudo mv /home/ec2-user/.ssh/authorized_keys /home/ec2-user/.ssh/disabled_keys
207+
echo 'Disabled the ec2-user'
208+
209+
EOT
210+
}
211+
212+
provisioner "remote-exec" {
213+
inline = [
214+
"chmod +x /home/ec2-user/bastion_script.sh ; sudo su - root -c 'bash /home/ec2-user/bastion_script.sh'"
215+
]
111216
}
112217

113218
}

0 commit comments

Comments
 (0)