Welcome, this will be the first part of a series i’m doing on setting up a production-ready container cluster with Raspberry Pi’s, my rig are 3 x Raspberry Pi Zero W.
I’ll pretty much do a summary on Raspberry’s own Security tutorial and implement the following:
First access: to remotely access Raspberry (exclusive to wireless capable Pi versions)* and update OS packages.
Authentication: to ensure only authenticated users are able to connect.
Firewall: for us to have explicit access control and basic DDoS protection for exposed ports, including SSH’s.
*if one is able to access by Ethernet cable, this is optional.
First access
Custom boot
For Pi to connect to Wi-Fi and be accessible to the local network and also enable SSH for us to access it we have to customize the OS image to be loaded to Pi’s SD card.
First thing we need to do is to mount the source .img we want to customize to a folder:
# MacOS
# double-click the .img
# Linux
$ mount -o loop ~/Downloads/my-source.img /mount/my-folder
# Windows
https://midnightprogrammer.net/post/create-mount-and-unmount-img-files-in-ubuntu/
After that, all we need to do is to create two simple files:
wpa_supplicant.conf, that will configure Wi-Fi with your local network access credentials.
country=<country code here> # eg.: BR
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
ssid="MyWiFiNetwork"
psk=bd9cf0f1asd902jd0sk5c6b307a7622sdoasd2jd69238f # NTLM password hash*
key_mgmt=WPA-PSK
}
*what i did to get to this values was to first customize the image with the plaintext password, which is basically achieved by setting the same psk property but wrapped with quotes, for example:
psk="mySuperSecretPass"
and from this setup generate the hashed password with (inside Pi’s OS):
$ wpa_passphrase "SSID" "mySuperSecretPass"
and finally an empty file called ssh, that only will enable ssh by default.
That done, just burn source .img to SD card, power Pi up and wait a minute or so to be up and connected to local network.
To find out Pi’s local network IP, one can rely on nmap tool to do so:
$ sudo nmap -sn 192.168.1.0/24
Password:
Starting Nmap 7.91 ( https://nmap.org ) at 2021-04-11 16:27 -03
...
MAC Address: <ommited mac address> (Raspberry Pi Foundation)
Nmap scan report for 192.168.1.123
...
and finally, login to Pi via ssh:
$ ssh pi@192.168.1.123
Update OS
After login into Pi, let’s update things so we can get the latest security patches available:
# update packages information
$ sudo apt-get update
# upgrade packages
$ sudo apt-get full-upgrade
Authentication
Next step is to create a custom user and remove the standard pi user:
# create new user, remember to securely store the password set here, it will be needed for privileged operations
$ sudo adduser vniche
# list pi's associated groups so we can add to our new user
$ sudo groups pi
pi adm dialout cdrom sudo audio video plugdev games users input netdev gpio i2c spi
# adds new user to these groups, except pi
$ sudo usermod -a -G adm,dialout,cdrom,sudo,audio,video,plugdev,games,users,input,netdev,gpio,i2c,spi vniche
Enforce access control by allowing only selected users:
# adds config line to ssh daemon config file
$ echo -n "AllowUsers vniche" | sudo tee -a /etc/ssh/sshd_config
# restarts ssh daemon
$ sudo systemctl restart ssh
Update sudoer config to ask for password when sudo is used:
# starts to edit the sudoer config file
$ sudo nano /etc/sudoers.d/010_pi-nopasswd
Change the content from:
pi ALL=(ALL) NOPASSWD: ALL
to
vniche ALL=(ALL) PASSWD: ALL
ps.: notice that i’ve changed NOPASSWD to PASSWD to ensure privilege escalation is protected by password.
# logout and login again with the new user to ensure pi's data is not in-use by any process
$ exit
Extra security can be achieved by enforcing key-based ssh authentication with these 2-step:
Generate a new SSH Key (if you don’t already have one)
# copy the public key to the server
$ ssh-copy-id -i ~/.ssh/id_ed25519.pub vniche@192.168.1.123
Also, lets disable password authentication to ensure ssh authentication are only done with keys, we can do that by setting the following property on /etc/ssh/sshd_config
:
PasswordAuthentication no
and be sure to restart ssh to apply the configured property:
$ sudo systemctl restart ssh
As a last step for users and access control management, we can remove pi user to ensure it can’t be used by all means:
# deletes and cleans pi user & its data
$ sudo deluser -remove-home pi
Firewall
Now let’s ensure we expose ports explicitly by installing and setting up a firewall:
# installs firewall software
$ sudo apt-get install ufw
# ufw by default allows all outgoing and denies all incoming connections
# allows SSH connections
$ sudo ufw allow ssh
# limits SSH connections to avoid vulnerabilities such as force-brute or DDoS
$ sudo ufw limit ssh/tcp
# enable ufw, caution not to do this before allowing ssh when doing this setup remotely
$ sudo ufw enable
Customization
We want to customize it’s server to a unique hostname, specially when working with multiple hosts. All we have to do is to change raspberrypi
to one of our own on both:
/etc/hosts
/etc/hostname
You can reduce the memory split between the GPU and the rest of the system down to 16mb
by editing /boot/config.txt
and add:
gpu_mem=16
We can now reboot and enjoy our fresh secure Raspberry server.
Conclusion
By following these steps one will have a first-layer security on it’s Pi and be able to start to configure services and workloads to attend needs. On the next post we will install Docker, run an example application on it and expose it through the internet, so stay tuned and see you then!
Extra:
Resources: