-
Notifications
You must be signed in to change notification settings - Fork 0
/
nodestrap.sh
387 lines (328 loc) · 11.8 KB
/
nodestrap.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
#!/bin/bash
# TODO: Login with SSH Keys
# TODO: Should specific versions of packages be installed?
# TODO: Try making while loops into a function
# TODO: Try making if statements into a function
# TODO: How to route all network traffic over tor?
check_sudo() {
# TODO: Exit script if incorrect password is entered three times in a row currently it takes 9 times (3 times if using ctrl+c)
# TODO: Issues with certain sudo commands
attempts=0
until $1
do
if [ $attempts -ne 2 ]; then
((attempts++))
else
echo "Exiting nodestrap: 3 incorrect password attempts"
exit 1
fi
sleep 1
done
}
set_up_sudo_session() {
printf "sudo permissions needed to set up bitcoin node\n"
check_sudo 'sudo -v'
}
system_update() {
sudo apt update
sudo apt full-upgrade
sudo apt install -y wget curl gpg git --install-recommends
}
cpu_architecture=
detect_cpu_architecture() {
cpu_architecture=$(dpkg --print-architecture)
}
# TODO: Check if ssh is already enabled and started by default, apt should already check if a package is installed, if it is will it update it
# when installing again?
# TODO: Command requires user to input q when initially ran
enable_and_start_ssh() {
sudo apt install -y openssh-server
systemctl status sshd
sudo systemctl enable --now sshd
}
check_usb3_drive_performance() {
# TODO: Make measuring the speed of drive optional?
sudo apt install -y hdparm
# TODO: Instead of prompting for user input make an informed guess on which drive they're using and ask them for confirmation, if they're using a different drive then allow them to input it?
# TODO: Allow someone to use a slow external drive
partition_name=
partition_name_confirmation=
speed_confirmation=
# TODO: Improve prompts
printf "\nMeasuring the speed of your drive... \n\n"
printf "If the measured speed is more than 50MB/s, then no further action is needed \n\n"
# TODO: Configure the USB driver to ignore UAS interface
# TODO: Make this optional?
printf "If the measured speed is not ideal, then we can configure the USB driver to ignore the UAS interface if using an external drive\n\n"
lsblk -pli
while true
do
# TODO: Improve example
printf "\n"
read -p "Enter the partition name being used to store the data for the node, for example, /dev/sda: " partition_name
printf "\n"
read -r -p "Re-enter the partition name: " partition_name_confirmation
if [ $partition_name == $partition_name_confirmation ]; then
printf "\n"
sudo hdparm -t --direct $partition_name
if [ $? -eq 0 ]; then
printf "\n\n"
# TODO: If the speed is not ideal, then ask if they want to configure the USB driver to ignore UAS interface
# Only ask if using an external drive since internal drive should be faster and be handled differently
# TODO: Could get the speed value from the command and evaluate it ourselves
read -p "Is measured speed more than 50MB/s? [Y/n] " speed_confirmation
printf "\n"
break
fi
else
# TODO: Allow them to cancel the measurement and continue with script?
printf "\n"
printf "The partition names do not match\n"
fi
done
}
detect_usb_drives() {
external_usb_drive=
# TODO: Improve prompts
while true
do
printf "\n"
read -r -p "Are you using an external USB drive to store the data for the node? [Y/n] " external_usb_drive
case $external_usb_drive in
[yY][eE][sS]|[yY]|"")
printf "\n"
ls -l /dev/disk/by-id/usb*
if [ $? -eq 0 ]; then
printf "\nUSB drive(s) detected\n\n"
check_usb3_drive_performance
break
else
printf "\nNo USB drives detected\n\n"
printf "If you are using an internal drive, then input n\n\n"
#TODO: Check mounting: done automatically & should be checked and done before this?
printf "If you are using an external USB drive, then check the connection and that it has been properly mounted\n"
printf "You may need to reboot the device\n"
fi
;;
[nN][oO]|[nN])
printf "\nSince you are using an internal drive to store the node data, we will not be measurinng the speed of the drive\n"
break
;;
*)
printf "\nInvalid input...\n"
;;
esac
done
}
create_data_dir() {
sudo mkdir /data
sudo chown "$USER":"$USER" /data
}
dynamic_swap() {
sudo apt install -y dphys-swapfile
sudo update-rc.d dphys-swapfile enable
# TODO: Check restricting to config limit value of 2048MB, the config limit can be updated in dphys-swapfile
sudo sed -i '/CONF_SWAPSIZE/s//#&/' /etc/dphys-swapfile
sudo dphys-swapfile install
sudo systemctl restart dphys-swapfile.service
}
enable_firewall() {
sudo apt install -y ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw logging off
sudo ufw enable
sudo systemctl enable ufw
}
install_fail2ban() {
sudo apt install -y fail2ban
}
increase_open_files_limit() {
sudo mkdir -p /etc/security/limits.d
cat <<EOF | sudo tee /etc/security/limits.d/90-limits.conf
* soft nofile 128000
* hard nofile 128000
root soft nofile 128000
root hard nofile 128000
EOF
# TODO: Use \t instead of spaces, i.e., session required\tpam_limits.so
# instead of session required pam_limits.so
# TODO: Want to be able to detect the pattern session optional\tpam_systemd.so for common-session
if ! grep -Fxq "session required pam_limits.so" /etc/pam.d/common-session
then
sudo sed -i '/pam_systemd.so/a session required\tpam_limits.so' /etc/pam.d/common-session
else
printf "\n/etc/pam.d/common-session already updated...\n"
fi
# TODO: Want to be able to detect the pattern session required\tpam_unix.so for common-session-noninteractive
if ! grep -Fxq "session required pam_limits.so" /etc/pam.d/common-session-noninteractive
then
sudo sed -i '/pam_unix.so/a session required\tpam_limits.so' /etc/pam.d/common-session-noninteractive
else
printf "\n/etc/pam.d/common-session-noninteractive already updated...\n\n"
fi
}
prepare_nginx_reverse_proxy() {
sudo apt install -y nginx
sudo openssl req -x509 -nodes -newkey rsa:4096 -keyout /etc/ssl/private/nginx-selfsigned.key -out /etc/ssl/certs/nginx-selfsigned.crt -subj "/CN=localhost" -days 3650
sudo mkdir /etc/nginx/streams-enabled
sudo mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
cat <<EOF | sudo tee /etc/nginx/nginx.conf
user www-data;
worker_processes 1;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
}
stream {
ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 4h;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
include /etc/nginx/streams-enabled/*.conf;
}
EOF
}
disable_wireless_interfaces() {
printf "\nIn a security-focused device like a bitcoin node, it's recommended to turn off all radios which includes Bluetooth and WiFi\n\n"
printf "If you're not using either of them, then both should be disabled\n"
disable_bluetooth
disable_wifi
}
disable_bluetooth() {
# TODO: Improve prompts
disable_bluetooth=
while true
do
printf "\n"
read -r -p "Do you want to disable bluetooth [Y/n] " disable_bluetooth
case $disable_bluetooth in
[yY][eE][sS]|[yY]|"")
printf "\n"
sudo systemctl disable bluetooth.service
break
;;
[nN][oO]|[nN])
printf "\n"
sudo systemctl enable bluetooth.service
break
;;
*)
printf "\nInvalid input...\n"
;;
esac
done
}
disable_wifi() {
# TODO: Improve prompts
printf "\n"
# TODO: Installing another package to handle disabling WiFi, see if we can do it without this package
# TODO: Allow user to set a static IP Address, can use nmcli
# TODO: RPi 3 with Raspian crashed here on initial execution?
sudo apt install -y network-manager
sudo systemctl start NetworkManager.service
sudo systemctl enable NetworkManager.service
disable_wifi=
while true
do
printf "\n"
read -r -p "Do you want to disable WiFi [Y/n] " disable_wifi
case $disable_wifi in
[yY][eE][sS]|[yY]|"")
printf "\n"
nmcli radio wifi off
break
;;
[nN][oO]|[nN])
printf "\n"
nmcli radio wifi on
break
;;
*)
printf "\nInvalid input...\n"
;;
esac
done
}
install_tor() {
sudo apt install -y apt-transport-https
cat <<EOF | sudo tee /etc/apt/sources.list.d/tor.list
deb [arch=$cpu_architecture signed-by=/usr/share/keyrings/tor-archive-keyring.gpg] https://deb.torproject.org/torproject.org bullseye main
deb-src [arch=$cpu_architecture signed-by=/usr/share/keyrings/tor-archive-keyring.gpg] https://deb.torproject.org/torproject.org bullseye main
EOF
# TODO: Check if the script hangs here, i.e., at the wget and why?
sudo wget -qO- https://deb.torproject.org/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc | gpg --dearmor | tee /usr/share/keyrings/tor-archive-keyring.gpg >/dev/null
sudo apt update
sudo apt install -y tor deb.torproject.org-keyring
sudo sed -i '/ControlPort 9051/s/^#//g' /etc/tor/torrc
sudo sed -i '/CookieAuthentication 1/s/^#//g' /etc/tor/torrc
if ! grep -Fxq "CookieAuthFileGroupReadable 1" /etc/tor/torrc
then
sudo sed -i '/CookieAuthentication 1/a CookieAuthFileGroupReadable 1' /etc/tor/torrc
else
printf "\n/etc/tor/torrc already updated...\n"
fi
sudo systemctl reload tor
}
ssh_remote_access_through_tor() {
# TODO: display onion address, tell them to copy it, store it in a safe location, e.g., in a password manager, and tell them how to use it
enable_ssh_remote_access_through_tor=
tor_connection_address_confirmation=
# TODO: If already added to the file don't display the connection
# address, ask them if they want to display the connection address, if
# yes display the connection address and ask them if they stored it in
# a secure location,
# make a separate function for displaying the connection address if
# already added to the file
while true
do
printf "\n"
read -r -p "Do you want to enable SSH remote access through Tor? [Y/n] " enable_ssh_remote_access_through_tor
case $enable_ssh_remote_access_through_tor in
[yY][eE][sS]|[yY]|"")
if ! grep -Fxq "HiddenServiceDir /var/lib/tor/hidden_service_sshd/" /etc/tor/torrc
then
sudo sed -i '/HiddenServicePort 22 127.0.0.1:22/a \\nHiddenServiceDir /var/lib/tor/hidden_service_sshd/' /etc/tor/torrc
sudo sed -i '/HiddenServiceDir \/var\/lib\/tor\/hidden_service_sshd\//a HiddenServiceVersion 3' /etc/tor/torrc
# TODO: Check this IP Address, should local address be used?
sudo sed -i '/HiddenServiceVersion 3/a HiddenServicePort 22 127.0.0.1:22' /etc/tor/torrc
else
printf "\n/etc/tor/torrc already updated...\n"
fi
sudo systemctl reload tor
printf "\nDo not share your Tor connection address with anyone!\n\n"
printf "Be sure to store your Tor connection address in a secure location, e.g., your password manager\n\n"
printf "Tor connection address: %s\n" "$(sudo cat /var/lib/tor/hidden_service_sshd/hostname)"
# TODO: If it isn't and they want it to be securely stored then show them how to securely store it
printf "\n"
read -p "Is your Tor connection address stored in a secure location? [Y/n] " tor_connection_address_confirmation
break
;;
[nN][oO]|[nN])
printf "\nSSH remote access through Tor not enabled\n"
break
;;
*)
printf "\nInvalid input...\n"
;;
esac
done
}
set_up_sudo_session
system_update
detect_cpu_architecture
enable_and_start_ssh
detect_usb_drives
create_data_dir
dynamic_swap
enable_firewall
install_fail2ban
increase_open_files_limit
prepare_nginx_reverse_proxy
disable_wireless_interfaces
install_tor
ssh_remote_access_through_tor