|
Disclaimer
This page is part of the MydriaTech Knowledge Base.
There is no guarantee of correctness or value of the provided content.
Send any feedback and/or corrections to kb at mydriatech dot se.Copyright © 2017 MydriaTech AB. All rights reserved, but feel free to get inspired by the content. |
Background and scope
Raspberry Pi (RPi) is a cheap and easy way to do quick product prototyping.
This article will show you how to install a fairly minimalistic headless RPi3 base system using the Linux distribution Raspbian Stretch Lite and configure it with some basic security to be used as base for prototyping over SSH.
The intended audience of this article is assumed to be fairly familiar with Debian systems, OpenSSH and the Linux console.
|
This is by no means secure enough for a production system, but is rather intended to at least prevent some unfocused drive-by hacking of a test environment. |
|
Rasbian currently runs armhf even though the ARM Cortex-A53 CPU of the RPi3 would support arm64. Since Rasbian is based on Debian this page might contain useful updates. |
If you prefer a scripted setup, see the appendix for how to automate this.
Raspbian operating system installation
Download the latest Raspbian Stretch Lite from the Raspberry Pi Foundation and follow their instructions for flashing the image to an SD card.
Summary: Download the image, unzip it, locate the inserted SD card device (/dev/sdX
in the example),
flash the OS image to the card, flush all writes to the SD card.
wget https://downloads.raspberrypi.org/raspbian_lite_latest unzip 2017-11-29-raspbian-stretch-lite.zip lsblk export SDCARD_DEVICE="/dev/sdX" sudo dd bs=32M if=2017-11-29-raspbian-stretch-lite.img of=${SDCARD_DEVICE} sync
Once flashing has completed, mount the /boot
partition of the SD card
sudo mkdir /mnt/rpi-boot sudo mount ${SDCARD_DEVICE}1 /mnt/rpi-boot/
Create the empty file named ssh
so the RPi comes up with SSH enabled once booted and connected to the network.
sudo touch /mnt/rpi-boot/ssh
and unmount the partition.
sudo umount /mnt/rpi-boot/ sudo rmdir /mnt/rpi-boot sync
(Optional) Enable 2.4 GHz WPA2 WiFi
The BCM43438 chip include 2.4 GHz WLAN IEEE 802.11 b/g/n MAC/baseband/radio support. Ensure that the WiFi settings reflect connection to such network. Also, use CCMP security whenever possible since TKIP is based on the RC4 stream cipher.
While you have your SD card’s /boot
partition mounted, add the following file:
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
scan_ssid=1
ssid="SSID"
psk="PASSWORD"
proto=RSN
key_mgmt=WPA-PSK
pairwise=CCMP
group=CCMP
}
# Secondary location network
#network={
# scan_ssid=1
# ssid="SSID2"
# psk="PASSWORD2"
# proto=RSN
# key_mgmt=WPA-PSK
# pairwise=CCMP
# group=CCMP
#}
At the next (and first) boot of the system /boot/wpa_supplicant.conf
will be moved to /etc/wpa_supplicant/wpa_supplicant.conf
.
Find the RPi on the network
Assuming your Local Area Network (LAN) is using DHCP, the new RPi will be assigned a new IP address that is unknown to you once it is booted.
If multicast Domain Name System (mDNS) is enabled on your Local Area Network, just connect (using password raspberry
) with
ssh -o "UserKnownHostsFile /dev/null" -o "StrictHostKeyChecking no" pi@raspberrypi.local
The additional settings for the options UserKnownHostsFile
and StrictHostKeyChecking
will prevent checking and saving of the host key
that we will replace later in this guide.
If you are unable to use mDNS, please refer to the troubleshooting section for alternative ways of finding your RPi.
Update system and stay up to date
Enable HTTPS instead of plain HTTP transport for communication to update servers to make it harder for a Man In The Middle (MITM) to replay an older repository and prevent security updates from happening. Confidentiality will still be very limited by the fact that package sizes are fairly unique and a MITM will be able to reasonable determine by package sizes which packages are installed or updated. Unfortunately, the main mirroring system does not support HTTPS yet.
#sudo sed -i 's/ http:\/\// https:\/\//g' /etc/apt/sources.list sudo sed -i 's/ http:\/\// https:\/\//g' /etc/apt/sources.list.d/raspi.list
Get and apply all updates since the operating system image was released.
sudo rpi-update sudo apt-get update sudo apt-get -y upgrade sudo reboot
Ensure that the box stays up to date by enabling unattended upgrades.
sudo apt-get install unattended-upgrades
Remove unused dependencies after the upgrade and reboot nightly if needed to apply security fixes.
...
Unattended-Upgrade::Remove-Unused-Dependencies "true";
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "02:00";
Unattended-Upgrade::SyslogEnable "true";
Unattended-Upgrade::SyslogFacility "daemon";
Configure the system for headless use
Perform basic settings on the host like
-
Set a non-default temporary password for the
pi
user (sudo passwd pi
) -
Set hostname to your liking (modify
/etc/hostname
and the entry for127.0.1.1
in/etc/hosts
) -
Change the amount of RAM allocated to the GPU to 16MiB (set
gpu_mem=16
in/boot/config.txt
)
or simply use the tool provided by Raspbian
sudo raspi-config
Disable unused hardware
In /boot/config.txt
you can additionally disable functionality that you wont use to save power and/or limit the attack surface.
Disable audio
dtparam=audio=off
Disable BCM43438 chip’s 2.4 GHz WLAN IEEE 802.11 b/g/n WIFI support (unless you are using it).
dtoverlay=pi3-disable-wifi
Disable BCM43438 chip’s Bluetooth 4.1 support.
dtoverlay=pi3-disable-bt
Saves ~25 mA by turning off the HDMI connector during boot from /etc/rc.local
.
echo "@reboot root /usr/bin/tvservice --off" | sudo tee /etc/cron.d/tvserviceoff
Reboot automatically if the systems enters a bad state
Enabling the hardware watch dog is a double edged sword. When configured correctly, you will reboot the system when an unexpected event happens that would otherwise force you to gain physical access to the SD card to debug. When configured incorrectly, you will reboot the system seemingly randomly when it is actually doing hard work that you might have asked it for. Also, repeatedly doing things is not great for power consumption on a system that would idle otherwise.
Add the following to /boot/config.txt
.
dtparam=watchdog=on
Install the service that keeps pooking the hardware watchdog when the system is still alive.
sudo apt-get install -y watchdog
Be fairly conservative and only reboot if average system load is very high, we have run out of memory or the CPU temperature reaches 75°C.
echo " max-load-1 = 48 max-load-5 = 36 max-load-15 = 24 min-memory = 1 watchdog-device = /dev/watchdog #realtime = yes #priority = 1 watchdog-timeout=15 interval=5 temperature-sensor = /sys/class/thermal/thermal_zone0/temp max-temperature = 75 " | sudo tee -a /etc/watchdog.conf
Prevent any kind of login except for SSH access
Since we are running the system headless, we don’t expect any kind of local login.
|
Note that this will effectively prevent any kind of recovery by connecting a keyboard, monitor and/or serial cable. It is also not a replacement for physical security, since directly plugging in to the circuit board would allow a different level of system tampering. |
Remove both serial line and regular console and prevent panic root shell.
sudo sed -i 's/ console=serial0,115200 console=tty1/ panic=0/g' /boot/cmdline.txt
No tty is considered secure for root login.
sudo mv /etc/securetty /etc/securetty.bak sudo touch /etc/securetty
Disable local tty1
sudo systemctl disable getty@tty1.service
Disable serial line tty
sudo systemctl disable serial-getty@ttyAMA0.service
Disable automatic spawning of new ttys
sudo sed -i '#NAutoVTs=6 a NAutoVTs=0' /etc/systemd/logind.conf
Random security (pun intended)
Cryptography based security and confidentiality requires a proper entropy source to prevent an attacker from guessing keys. It will be used for transport (SSH), disk encryption and also operating system functions like Address space layout randomization ASLR.
In Linux there are two random devices - a blocking (/dev/random
and a non-blocking /dev/urandom
).
Internally they both deliver a stream of random bits originating from the same hidden state using
Psuedo Random Number Generator (PRNG) based on a hash functions.
The big difference between the two is that the blocking device will only return the requested number of bit
once enough bits of entropy has been added to the internal state.
If the hash function is broken in the future, the random bits provided by the blocking device might still be
hard to predict if the internal state is compromised.
Not having a sufficient entropy will however prevent applications using the blocking device from functioning at full speed, since they have to wait for the pool to fill up before continuing their operation.
Enable the RPi3 hardware random generator
Install entropy gathering daemon to make the internal /dev/random
state harder to predict compared to a
when the original host keys were generated and will provide entropy at a much higher rate than without.
sudo apt-get install rng-tools
Verify status.
echo $(cat /proc/sys/kernel/random/entropy_avail)/$(cat /proc/sys/kernel/random/poolsize) sudo pkill -USR1 rngd; tail -15 /var/log/syslog
|
This article is in no way trying to suggest that the quality of the HW RNG on the RPi3 is sufficient for security applications. Entropy quality is hard measure and beyond the scope of this article. |
Regenerate SSH hosts keys
Once a harder to predict entropy source is active, we should regenerate the host keys that were created on first boot.
sudo ssh-keygen -t rsa -b 4096 -N "" -f /etc/ssh/ssh_host_rsa_key sudo ssh-keygen -t ecdsa -b 521 -N "" -f /etc/ssh/ssh_host_ecdsa_key sudo ssh-keygen -t ed25519 -N "" -f /etc/ssh/ssh_host_ed25519_key
List the new host key fingerprints so you know that you connect back to the right host.
sudo ssh-keygen -l -f /etc/ssh/ssh_host_rsa_key sudo ssh-keygen -l -f /etc/ssh/ssh_host_ecdsa_key sudo ssh-keygen -l -f /etc/ssh/ssh_host_ed25519_key
Restart SSH and logout.
sudo service ssh restart logout
Log back in again and verify that the host key fingerprint matches one of the outputs from ssh-keygen -l
above.
ssh pi@new-rpi-hostname.local
Only allow public key authentication over SSH
A good way to prevent unauthorized access to your box is to only allow public key authentication over SSH since it currently is much harder to attack than passwords.
Before you continue, generate client SSH keys if you don’t already have done so.
ssh-keygen -b 4096 -t rsa -C "Lab environment key" -f ~/.ssh/id_rsa_env_lab
Copy your public key to the box using for example
ssh-copy-id -i ~/.ssh/id_rsa_env_lab pi@new-rpi-hostname.local
Login to the box again and edit the SSH configuration (sudo nano /etc/ssh/sshd_config
).
...
SyslogFacility AUTH
LogLevel INFO
...
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM yes
...
X11Forwarding no
...
#Subsystem sftp /usr/lib/openssh/sftp-server
...
UseDNS no
TcpKeepAlive yes
...
ClientAliveInterval 30
ClientAliveCountMax 1
...
Restart SSHd.
sudo service ssh restart
Logout and login again to verify that it works.
logout ssh -i ~/.ssh/id_rsa_env_lab pi@new-rpi-hostname.local
Optionally simplify your life by adding a new entry in ~/.ssh/config
on the client side.
...
Host new-rpi-hostname
Hostname new-rpi-hostname.local
User pi
IdentityFile ~/.ssh/id_rsa_env_lab
ServerAliveInterval 30
Try the new short version of the previous command.
ssh new-rpi-hostname
Disable password login for the pi
user
Assuming that you will allow sudo
without password, you can simply disable the password authentication
for the pi
user to prevent its use through any unintended login path accidently left open.
sudo passwd -l pi
Please refer to the appendix for how to instead use a password for sudo
.
Encrypt swap
Given the RPi’s limited I/O capabilities it is wise to avoid swapping in the first place, but when it can’t be avoided encrypting the swap will prevent unintentionally persisting sensitive data from RAM.
Remove the on demand swap allocation used by Rasbian.
sudo apt-get -y purge dphys-swapfile sudo apt-get -y autoremove
Pre-allocate a 1 GiB file /opt/swap-device.bin
to use as encrypted swap device.
(This is the the same size as the available RAM on the RPi3.)
sudo dd if=/dev/urandom of=/opt/swap-device.bin bs=1M count=1024 iflag=fullblock
The allocated file should be mapped as a dm-crypt swap device on boot. (sudo nano /etc/crypttab
)
swap /opt/swap-device.bin /dev/urandom swap,cipher=aes-xts-plain64:sha256,size=256
Instruct system to use the mapped encrypted device as swap on boot. (sudo nano /etc/fstab
)
...
/dev/mapper/swap swap swap defaults 0 0
Reboot and verify that change.
sudo reboot grep SwapTotal /proc/meminfo
Enable firewall
Enable a basic iptables
firewall that only allows the basic services enabled for the scope of this article.
The default policy will be to drop everything unless permitted (even internal localhost traffic).
Outgoing connections for a service will only by allowed per owner (system user) to potentially prevent
successfully injected malware from phoning home.
sudo apt-get install iptables-persistent
Reconfigure IP and ARP settings to avoid leaking information.
# Always use strict mode Source Address Verification
net/ipv4/conf/default/rp_filter=1
net/ipv4/conf/all/rp_filter=1
# Don't allow IP source route packets
net/ipv4/conf/default/accept_source_route=0
net/ipv4/conf/all/accept_source_route=0
net/ipv6/conf/default/accept_source_route=0
net/ipv6/conf/all/accept_source_route=0
# Don't allow ICMP redirects
net/ipv4/conf/default/accept_redirects=0
net/ipv4/conf/all/accept_redirects=0
net/ipv6/conf/default/accept_redirects=0
net/ipv6/conf/all/accept_redirects=0
# Don't allow bogus ICMP errors
net/ipv4/icmp_echo_ignore_broadcasts=1
net/ipv4/icmp_ignore_bogus_error_responses=1
net/ipv4/icmp_echo_ignore_all=0
# Don't log Martian Packets
net/ipv4/conf/default/log_martians=0
net/ipv4/conf/all/log_martians=0
# Clean up failing connections more quickly
net/ipv4/tcp_fin_timeout=30
# Keep various sane defaults
net/ipv4/tcp_syncookies=1
net/ipv4/tcp_keepalive_intvl=75
net/ipv4/tcp_sack=1
# Don't allow IPv6 auto-configuration
net/ipv6/conf/default/autoconf=0
net/ipv6/conf/all/autoconf=0
# Always use the best local address for this target.
net/ipv4/conf/default/arp_announce = 0
net/ipv4/conf/all/arp_announce = 2
# Only respond to ARPs if kernel would route packets through this iface for this IP
# (If two NICs are connected to the same network, policy/source routing must be used,
# so the setting here is intended to prevent leaks through a VPN or similar.)
net/ipv4/conf/default/arp_filter = 1
net/ipv4/conf/all/arp_filter = 0
net/ipv4/conf/eth0/arp_filter = 0
net/ipv4/conf/wlan0/arp_filter = 0
# Reply only if the target IP address is local address configured on the incoming interface
net/ipv4/conf/default/arp_ignore = 0
net/ipv4/conf/all/arp_ignore = 1
Configure IPv4 firewall rules. The following services will be made available:
-
Allow outgoing HTTP and HTTPS from the package manager for download of updates.
-
Allow outgoing Network Time Protocol (NTP) requests.
-
Allow outgoing Domain Name System (DNS) queries from package manager and NTP service.
-
Allow outgoing Dynamic Host Configuration Protocol (DHCP) requests.
-
Allow incoming and outgoing Multicast DNS (mDNS).
-
Allow incoming Secure Shell (SSH) connections.
-
Allow outgoing Internet Control Message Protocol (ICMP) ping by the default
pi
user. -
Allow incoming ICMP ping
-
Log all other packets that will be dropped at a maximum rate of 20 log entries per minute.
Note that this implies that by default:
-
Prevent the 'pi' user to make DNS queries or HTTP/HTTPS requests.
-
Prevent internal traffic over localhost unless it is one of the allowed services.
-
Prevent ICMP destination-unreachable responses in reply to a ping request.
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
# Drop invalid packets right away
-A INPUT -m conntrack --ctstate INVALID -j DROP
# Drop fragmented ICMP packets
-A INPUT --fragment -p icmp -j DROP
# Respond to ICMP ping
-A INPUT -i eth0 -p icmp --icmp-type echo-request -m state --state NEW,ESTABLISHED -j ACCEPT
-A INPUT -i wlan0 -p icmp --icmp-type echo-request -m state --state NEW,ESTABLISHED -j ACCEPT
-A OUTPUT -o eth0 -p icmp --icmp-type echo-reply -m state --state ESTABLISHED -j ACCEPT
-A OUTPUT -o wlan0 -p icmp --icmp-type echo-reply -m state --state ESTABLISHED -j ACCEPT
# Allow outgoing ICMP ping from the user ('pi', UID=1000)
-A OUTPUT -o eth0 -p icmp --icmp-type echo-request -m state --state NEW,ESTABLISHED -m owner --uid-owner 1000 -j ACCEPT
-A OUTPUT -o wlan0 -p icmp --icmp-type echo-request -m state --state NEW,ESTABLISHED -m owner --uid-owner 1000 -j ACCEPT
# And successful ICMP pong responses
-A INPUT -i eth0 -p icmp --icmp-type echo-reply -m state --state ESTABLISHED -j ACCEPT
-A INPUT -i wlan0 -p icmp --icmp-type echo-reply -m state --state ESTABLISHED -j ACCEPT
# Allow DHCP
-A OUTPUT -o eth0 -p udp --sport 68 --dport 67 -m state --state NEW,ESTABLISHED -j ACCEPT
-A OUTPUT -o wlan0 -p udp --sport 68 --dport 67 -m state --state NEW,ESTABLISHED -j ACCEPT
# Allow result of DHCP requests to be returned
-A INPUT -i eth0 -p udp --sport 67 --dport 68 -m state --state ESTABLISHED -j ACCEPT
-A INPUT -i wlan0 -p udp --sport 67 --dport 68 -m state --state ESTABLISHED -j ACCEPT
# Allow mDNS from the avahi daemon ('avahi', UID=108)
-A OUTPUT -o eth0 -p udp -m owner --uid-owner 108 --dport 5353 -j ACCEPT
-A OUTPUT -o wlan0 -p udp -m owner --uid-owner 108 --dport 5353 -j ACCEPT
-A INPUT -i eth0 -p udp -d 224.0.0.251 --dport 5353 -j ACCEPT
-A INPUT -i wlan0 -p udp -d 224.0.0.251 --dport 5353 -j ACCEPT
# Allow DNS queries by required apps daemon ('systemd-timesync', UID=100; '_apt', UID=104)
-A OUTPUT -o eth0 -p udp --dport 53 --sport 1024:65535 -m state --state NEW,ESTABLISHED -m owner --uid-owner 100 -j ACCEPT
-A OUTPUT -o wlan0 -p udp --dport 53 --sport 1024:65535 -m state --state NEW,ESTABLISHED -m owner --uid-owner 100 -j ACCEPT
-A OUTPUT -o eth0 -p udp --dport 53 --sport 1024:65535 -m state --state NEW,ESTABLISHED -m owner --uid-owner 104 -j ACCEPT
-A OUTPUT -o wlan0 -p udp --dport 53 --sport 1024:65535 -m state --state NEW,ESTABLISHED -m owner --uid-owner 104 -j ACCEPT
# Allow result of DNS queries to be returned
-A INPUT -i eth0 -p udp --sport 53 --dport 1024:65535 -m state --state ESTABLISHED -j ACCEPT
-A INPUT -i wlan0 -p udp --sport 53 --dport 1024:65535 -m state --state ESTABLISHED -j ACCEPT
# Allow NTP queries by NTP daemon ('systemd-timesync', UID=100)
-A OUTPUT -o eth0 -p udp --dport 123 -m state --state NEW,ESTABLISHED -m owner --uid-owner 100 -j ACCEPT
-A OUTPUT -o wlan0 -p udp --dport 123 -m state --state NEW,ESTABLISHED -m owner --uid-owner 100 -j ACCEPT
# Allow result of NTP queries to be returned
-A INPUT -i eth0 -p udp --sport 123 -m state --state ESTABLISHED -j ACCEPT
-A INPUT -i wlan0 -p udp --sport 123 -m state --state ESTABLISHED -j ACCEPT
# Allow incoming SSH connections
-A INPUT -i eth0 -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
-A INPUT -i wlan0 -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
-A OUTPUT -o eth0 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
-A OUTPUT -o wlan0 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
# Allow APT to fetch updates over HTTP and HTTPS. ('_apt', UID=104)
-A OUTPUT -o eth0 -p tcp --dport 80 -m state --state NEW,ESTABLISHED -m owner --uid-owner 104 -j ACCEPT
-A OUTPUT -o wlan0 -p tcp --dport 80 -m state --state NEW,ESTABLISHED -m owner --uid-owner 104 -j ACCEPT
-A OUTPUT -o eth0 -p tcp --dport 443 -m state --state NEW,ESTABLISHED -m owner --uid-owner 104 -j ACCEPT
-A OUTPUT -o wlan0 -p tcp --dport 443 -m state --state NEW,ESTABLISHED -m owner --uid-owner 104 -j ACCEPT
# Allow result of HTTP/HTTPS to be returned
-A INPUT -i eth0 -p tcp --sport 80 -m state --state ESTABLISHED -j ACCEPT
-A INPUT -i wlan0 -p tcp --sport 80 -m state --state ESTABLISHED -j ACCEPT
-A INPUT -i eth0 -p tcp --sport 443 -m state --state ESTABLISHED -j ACCEPT
-A INPUT -i wlan0 -p tcp --sport 443 -m state --state ESTABLISHED -j ACCEPT
# Log anything that will hit the default DROP-policy
-A INPUT -m limit --limit 20/min -j LOG --log-prefix \"iptables dropped: \" --log-level 7
-A OUTPUT -m limit --limit 20/min -j LOG --log-prefix \"iptables dropped: \" --log-level 7 --log-uid
-A FORWARD -m limit --limit 20/min -j LOG --log-prefix \"iptables dropped: \" --log-level 7 --log-uid
COMMIT
Configure IPv6 (DROP all) firewall rules.
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
COMMIT
Test and enable firewall rules.
sudo iptables-restore --test /etc/iptables/rules.v4 sudo iptables-restore --test /etc/iptables/rules.v6 sudo systemctl enable netfilter-persistent
Appendix A: Troubleshooting
Alternative ways of finding the IP of your device
Alternative A: Further debug multicast Domain Name System
If your system is running avahi-daemon
and your LAN allows multicast Domain Name System (mDNS), you can list all enabled hosts with
avahi-browse -a -t -k
If you find raspberrypi.local
device, you could find the IP address of the new RPi using
avahi-resolve --name raspberrypi.local
Alternative B: Find IP by checking your router
Checking your router for new network devices where the MAC address starts with b8:27:eb:xx:xx:xx
.
It is likely that this is your new RPi.
Since you probably wont be using mDNS Take the opportunity to configure a static IP for the new device.
Alternative C: Ping scan your LAN for a new device
Use namp
to ping-scan the LAN for a host named raspberrypi
:
sudo apt-get install -y nmap export LAN_NETWORK=$(ip route | grep kernel | grep $(ip route | grep default | cut -d' ' -f5) | cut -d' ' -f1) echo "${LAN_NETWORK}" nmap -sn "${LAN_NETWORK}" | grep raspberry
Later when ping is disabled by the firewall, you can scan for open SSH ports instead.
nmap -sT -p 22 "${LAN_NETWORK}"
Appendix B: Common tasks
Use ACT LED to indicate WLAN carrier
Add a DHCP hook that will use the ACT LED to indicate a carrier on the wlan0
interface.
This is extremely useful if you plan to deploy your headless RPi3 at the edge of WiFi coverage.
# Turn on ACT LED when WLAN carrier has been detected
if [ "$interface" = "wlan0" ] ; then
if [ "$reason" = "CARRIER" ] ; then
echo none > /sys/class/leds/led0/trigger
echo 1 > /sys/class/leds/led0/brightness
fi
if [ "$reason" = "NOCARRIER" ] ; then
echo none > /sys/class/leds/led0/trigger
echo 0 > /sys/class/leds/led0/brightness
fi
fi
Install your new favorite editor vim
sudo apt-get -y install vim
Optionally you can also revert some of the new default behaviors to make it easier to work with the mouse (vim ~/.vimrc
).
" Avoid automatic indention during paste
set paste
" Allow crtl+shift+c for copying mouse selects instead of visual mode
set mouse-=a
To apply the same for the root
user, copy the file.
sudo cp /home/pi/.vimrc /root/.vimrc
If you just blindly followed this guide and are currently panicking over how to get out of vim
, just type
:q!
and hit enter.
Prevent password-less sudo
Even if you don’t use a password for the pi
user for SSH authentication, you can choose to use it
for sudo
authentication.
Set a sufficient strong password for the pi
user
sudo passwd pi
Edit and comment out the special rule for the pi
user. (sudo nano /etc/sudoers.d/010_pi-nopasswd
)
#pi ALL=(ALL) NOPASSWD: ALL
Even if you really use a proper password (which you should), increasing the delay between failed attempts will significantly make the password harder to brute force.
Delay each failed attempt by 10 (000 000 micro-) seconds.
sudo sed -i '/pam_unix.so/ i auth optional pam_faildelay.so delay=10000000' /etc/pam.d/common-auth
Lock account for 5.5 minutes after 3 failed attempts.
sudo sed -i '$ a auth required pam_tally2.so deny=3 onerr=fail even_deny_root unlock_time=630' /etc/pam.d/common-auth sudo sed -i '$ a account required pam_tally2.so' /etc/pam.d/common-account
The result will be that 3 attempts is allowed every 6 minutes. As an example (which you should not use), a simple 4 digit PIN would could be expected to be broken on average after 10^4/2=5000 attempts and would on average resist brute force with these settings for 7 days.
Choose a sufficiently strong randomly generated password and adapt these values to ensure that the system will never be broken this way during its life-time so you have one less thing to worry about.
Inform authorized users to avoid human errors
Informing authorized users about what this particular system is for, to avoid "human errors". This wont hurt if you are multiple people working on a project or if your future self easily forgets what it did a while back.
echo " ************************************************************************************* * Test System X created under project Y yyyy-MM-dd by John Doe. * * See https://wiki.organisation.intranet/ProjectY/TestSystemX for more information. * *************************************************************************************" \ | sudo tee -a /etc/motd
Pull more up to date packages from Debian
Import Debian Stretch release keys (since we are running Raspbian Stretch).
export DEFAULT_DEV="`ip route show | grep default | cut -d' ' -f5`" sudo iptables -A OUTPUT -o ${DEFAULT_DEV} -p tcp --dport 11371 -j ACCEPT
sudo apt-get install -y dirmngr sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 7638D0442B90D010
sudo iptables -D OUTPUT -o ${DEFAULT_DEV} -p tcp --dport 11371 -j ACCEPT
Add repository.
echo 'deb http://httpredir.debian.org/debian stretch main contrib non-free' | sudo tee -a /etc/apt/sources.list.d/stretch.list
Configure priorities so that the Raspbian repository has precedences over the Debian ones except for the packages we want.
(sudo nano /etc/apt/preferences.d/stretch.pref
)
Package: *
Pin: origin httpredir.debian.org
Pin-Priority: 10
Package: openvswitch-switch openvswitch-common
Pin: origin httpredir.debian.org
Pin-Priority: 1000
Update package list and show the policy we just configured.
sudo apt-get update sudo apt-cache policy
Go ahead and install the packages from Debian, e.g.
sudo apt-get install openvswitch-switch
Making the device accessible from the big bad Internet
Making the device accessible from the big bad Internet is usually a large part of why a system is setup. In the examples below, TCP port 22 of the RPi will be made available via port 12345 on the public IP.
Leverage another Internet accessible device as incoming SSH proxy
The idea is to use OpenSSH to make an outgoing connection to another host that has a static public IP address and forward all traffic from one of the public IP’s ports back to an localhost port of the RPi. This will work even if you are connected over for example a mobile carrier that wont allow your LAN to have a public IP. Since the public IP is (by the definition above) static, it makes it easy to find your way back to the RPi even if it is moved to a different LAN.
Install autossh
to keep the OpenSSH tunnel alive.
sudo apt-get install -y autossh
Prepare the remote proxy by editing /etc/ssh/sshd_config
and adding
GatewayPorts yes
Setup SSH tunnel at server boot by adding the following to /etc/rc.local
just before exit 0
.
autossh -fNT -i /root/.ssh/id_rsa_tunnel -R PUBLIC_IP:12345:127.0.0.1:22 user@public-host.hostingservice.com &
Test by connecting back via the proxy
ssh pi@public-host.hostingservice.com -p 12345 ~/.ssh/id_rsa_env_lab
Setup port forwarding in your router
This works best if you assign a static IP to your device. Either configure a static IP directly on the RPi or configure the DHCP server to always assign the same IP to your device’s MAC address. Please consider you router’s and/or DHCP server’s documentation on advice how to do this.
Poking a hole with the UPnP protocol
A UPnP enabled router can be requested to dynamically add port forwarding for a specified number of seconds.
Adding a script invoked by crond
every 5 minutes to request renewal of the port forwarding for 5.5 more minutes
will keep the port forwarding alive for as long as the RPi is up.
|
Enabling UPnP in your router will allow rough code running in your network to open up additional attack vectors to your network. Don’t enable it unless you have to. |
Install the minimalistic UPnP client miniupnpc
.
sudo apt-get install -y miniupnpc
Create client script. (sudo nano /opt/setup-port-forward.sh
)
#!/bin/bash
####
#### Setup port forwarding of SSH to local host in UPnP supporting router.
####
####
externalPort="12345"
## Require root access
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root." 1>&2
exit 1
fi
# Temporarily allow UPnP discovery traffic
ipDefaultRoute="`ip route show | grep default | cut -d' ' -f3`"
ipDefaultDevice="`ip route show | grep default | cut -d' ' -f5`"
# Allow UPnP discovery
iptables -A INPUT -i "${ipDefaultDevice}" -p udp -d 239.255.255.250 --dport 1900 -j ACCEPT
iptables -A OUTPUT -o "${ipDefaultDevice}" -p udp -d 239.255.255.250 --dport 1900 -j ACCEPT
iptables -A OUTPUT -o "${ipDefaultDevice}" -p tcp -d "${ipDefaultRoute}" -j ACCEPT
# Attempt UPnP discovery
eater="`upnpc -l`"
upnpcError="$?"
if [ "$upnpcError" == "0" ] ; then
xmlRootDescriptorUrl=$(echo "${eater}" | \
grep -B 1 "schemas-upnp-org:device:InternetGatewayDevice" | grep desc | \
sed 's/ desc: //g')
lanIp=$(echo "${eater}" | grep "Local LAN ip address" | \
sed 's/Local LAN ip address : //g')
wanIp=$(echo "${eater}" | grep "ExternalIPAddress" | \
sed 's/ExternalIPAddress = //g')
nodeName="`hostname`"
# Setup port forward in gateway back to port 22 of this host that last
# for 5 minutes and 30 seconds (and we run this every 5 minutes)
upnpc -u ${xmlRootDescriptorUrl} -a ${lanIp} 22 ${externalPort} TCP 330
# Save our current external IP address (so can push it to peers later
# that want to connect back here)
echo "${wanIp}" > /opt/ip-wan-${nodeName}
else
echo "Unable to setup port forwarding in UPNP Internet Gateway Device."
fi
# Disallow UPnP discovery
iptables -D INPUT -i "${ipDefaultDevice}" -p udp -d 239.255.255.250 --dport 1900 -j ACCEPT
iptables -D OUTPUT -o "${ipDefaultDevice}" -p udp -d 239.255.255.250 --dport 1900 -j ACCEPT
iptables -D OUTPUT -o "${ipDefaultDevice}" -p tcp -d "${ipDefaultRoute}" -j ACCEPT
Make script runnable by root.
sudo chmod 700 /opt/setup-port-forward.sh
Keep forward alive as long as host is up. (sudo nano /etc/cron.d/setup-port-forward
)
*/5 * * * * root /opt/setup-port-forward.sh >/dev/null 2>&1
$ sudo service cron reload
Find external IP address
Unless you use the reverse SSH tunnel + external proxy method, you need to find the devices public IP address.
Find external IP address using OpenDNS and publish
A real duct tape fix would be to find the public IP address of your device and publish it for example in an IRC channel.
Install dig
.
sudo apt-get install -y dnsutils
Do lookup to a special resolver from opendns.com.
sudo iptables -A OUTPUT -o eth0 -p udp --dport 53 --sport 1024:65535 -m state --state NEW,ESTABLISHED -m owner --uid-owner 1000 -j ACCEPT sudo iptables -A OUTPUT -o wlan0 -p udp --dport 53 --sport 1024:65535 -m state --state NEW,ESTABLISHED -m owner --uid-owner 1000 -j ACCEPT
dig @208.67.222.220 myip.opendns.com +short 2> /dev/null
sudo iptables -D OUTPUT -o eth0 -p udp --dport 53 --sport 1024:65535 -m state --state NEW,ESTABLISHED -m owner --uid-owner 1000 -j ACCEPT sudo iptables -D OUTPUT -o wlan0 -p udp --dport 53 --sport 1024:65535 -m state --state NEW,ESTABLISHED -m owner --uid-owner 1000 -j ACCEPT
Publish…
Find external IP address using dynamic DNS service
See xdd.se for an anonymous dynamic DNS service provider to easily find your device’s IP.
Network performance testing with iperf
Install the iperf
network performance testing tool.
sudo apt-get install -y iperf
To run an iperf server accepting traffic on the default network interface during the test.
export DEFAULT_DEV="`ip route show | grep default | cut -d' ' -f5`" sudo iptables -A INPUT -i ${DEFAULT_DEV} -p tcp --dport 5001 -m state --state NEW,ESTABLISHED -j ACCEPT sudo iptables -A OUTPUT -o ${DEFAULT_DEV} -p tcp --sport 5001 -m state --state ESTABLISHED -j ACCEPT
iperf -e -f M -s
sudo iptables -D INPUT -i ${DEFAULT_DEV} -p tcp --dport 5001 -m state --state NEW,ESTABLISHED -j ACCEPT sudo iptables -D OUTPUT -o ${DEFAULT_DEV} -p tcp --sport 5001 -m state --state ESTABLISHED -j ACCEPT
To run an iperf client (also allowing the outgoing traffic through the firewall during the test).
export DEFAULT_DEV="`ip route show | grep default | cut -d' ' -f5`" sudo iptables -A OUTPUT -o ${DEFAULT_DEV} -p tcp --dport 5001 -j ACCEPT sudo iptables -A INPUT -i ${DEFAULT_DEV} -p tcp --sport 5001 -m state --state ESTABLISHED -j ACCEPT
iperf -f M -d -n 1024M -F /dev/urandom -c ranet-s2n1-int
sudo iptables -D OUTPUT -o ${DEFAULT_DEV} -p tcp --dport 5001 -j ACCEPT sudo iptables -D INPUT -i ${DEFAULT_DEV} -p tcp --sport 5001 -m state --state ESTABLISHED -j ACCEPT
Appendix C: Scripted setup
Run the following one-liner to detect the new /dev/sdX device that will be assumed to be your SD card.
a=""; b=""; while [ "${b}" = "" ] || [[ "${a#"$b"}" = "" || ${#a} -lt ${#b} ]] ; do b=${a}; a=$(echo "$(ls /dev/sd?)"); done ; \ c="${a#"$b"}"; c=${c/$'\n'}; echo "Detected ${c}." ; lsblk ${c} ; export SDCARD_DEVICE=${c}
Download Raspbian and flash the ${SDCARD_DEVICE}
(e.g. /dev/sdc
). Make sure this is really is the SD card and that is not mounted.
wget https://downloads.raspberrypi.org/raspbian_lite_latest -O raspbian_lite_latest.zip udisksctl unmount -b ${SDCARD_DEVICE}1 udisksctl unmount -b ${SDCARD_DEVICE}2 unzip -p raspbian_lite_latest.zip | sudo dd bs=32M of=${SDCARD_DEVICE} && sync
After flashing the image, mount the root file system partition
sudo mkdir /mnt/rpi-rootfs sudo mount ${SDCARD_DEVICE}2 /mnt/rpi-rootfs/
and add
-
a trigger for script that runs on initial boot and syslogs its operations
echo "@reboot root /root/rpisetup.sh 2>&1 | /usr/bin/logger -t rpisetup" | sudo tee /mnt/rpi-rootfs/etc/cron.d/rpisetup
-
a configuration file for the device
hostname="raspberrypi"
ssh_pubkey="ssh-rsa AAA... ..."
local_access_enable="false"
watchdog_enable="true"
wifi_enable="true"
wifi_wpa_supplicant_conf="
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
scan_ssid=1
ssid=\"SSID\"
psk=\"PASSWORD\"
proto=RSN
key_mgmt=WPA-PSK
pairwise=CCMP
group=CCMP
}
#network={
# ...
#}
"
also_apt_get_packages="vim screen dnsutils wget"
additional_iptables_rules="
# Allow default user to make HTTP and HTTPS requests. ('pi', UID=1000)
-A OUTPUT -o eth0 -p tcp --dport 80 -m state --state NEW,ESTABLISHED -m owner --uid-owner 1000 -j ACCEPT
-A OUTPUT -o wlan0 -p tcp --dport 80 -m state --state NEW,ESTABLISHED -m owner --uid-owner 1000 -j ACCEPT
-A OUTPUT -o eth0 -p tcp --dport 443 -m state --state NEW,ESTABLISHED -m owner --uid-owner 1000 -j ACCEPT
-A OUTPUT -o wlan0 -p tcp --dport 443 -m state --state NEW,ESTABLISHED -m owner --uid-owner 1000 -j ACCEPT
# Allow default user to make DNS queries. ('pi', UID=1000)
-A OUTPUT -o eth0 -p udp --dport 53 --sport 1024:65535 -m state --state NEW,ESTABLISHED -m owner --uid-owner 1000 -j ACCEPT
-A OUTPUT -o wlan0 -p udp --dport 53 --sport 1024:65535 -m state --state NEW,ESTABLISHED -m owner --uid-owner 1000 -j ACCEPT
"
-
a script that performs the initial configuration
#!/bin/bash -x
echo "Waiting 10 seconds for most of the system to boot..."
sleep 10
###
### Load configuration
###
source ./rpisetup.conf
export DEBIAN_FRONTEND=noninteractive
export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
###
### Configure hardware and networking
###
if [ ! -f ./rpisetup-flag-part1 ] ; then
touch ./rpisetup-flag-part1
echo "*** Reconfiguring WiFi... [wifi_enable=${wifi_enable}]"
if [ "${wifi_enable}" = "true" ] ; then
echo "${wifi_wpa_supplicant_conf}" > /boot/wpa_supplicant.conf
echo "# Turn on ACT LED when WLAN carrier has been detected
if [ \"\$interface\" = \"wlan0\" ] ; then
if [ \"\$reason\" = \"CARRIER\" ] ; then
echo none > /sys/class/leds/led0/trigger
echo 1 > /sys/class/leds/led0/brightness
fi
if [ \"\$reason\" = \"NOCARRIER\" ] ; then
echo none > /sys/class/leds/led0/trigger
echo 0 > /sys/class/leds/led0/brightness
fi
fi
" > /lib/dhcpcd/dhcpcd-hooks/99-carrier-act-led
else
echo "dtoverlay=pi3-disable-wifi" >> /boot/config.txt
fi
echo "*** Disabling audio, bluetooth and setting minimum GPU memory usage..."
sed -i 's/dtparam=audio=on/dtparam=audio=off/g' /boot/config.txt
echo "dtoverlay=pi3-disable-bt" >> /boot/config.txt
echo "gpu_mem=16" >> /boot/config.txt
if [ "${watchdog_enable}" = "true" ] ; then
echo "*** Enabling HW watchdog..."
echo "dtparam=watchdog=on" >> /boot/config.txt
fi
echo "*** Changing hostname..."
sed -i "s/$(cat /etc/hostname)/${hostname}/g" /etc/hosts
echo ${hostname} > /etc/hostname
echo "*** Reconfiguring SSH to only use public key authentication..."
sed -i 's/#SyslogFacility AUTH/SyslogFacility AUTH/g' /etc/ssh/sshd_config
sed -i 's/#LogLevel INFO/LogLevel INFO/g' /etc/ssh/sshd_config
sed -i 's/#PasswordAuthentication no/PasswordAuthentication no/g' /etc/ssh/sshd_config
sed -i 's/X11Forwarding yes/X11Forwarding no/g' /etc/ssh/sshd_config
sed -i 's/Subsystem/#Subsystem/g' /etc/ssh/sshd_config
sed -i 's/#UseDNS no/UseDNS no/g' /etc/ssh/sshd_config
sed -i 's/#ClientAliveInterval 0/ClientAliveInterval 30/g' /etc/ssh/sshd_config
sed -i 's/#ClientAliveCountMax 3/ClientAliveCountMax 1/g' /etc/ssh/sshd_config
mkdir /home/pi/.ssh
echo "${ssh_pubkey}" > /home/pi/.ssh/authorized_keys
chown -R pi:pi /home/pi/.ssh/
chmod 700 /home/pi/.ssh/
chmod 500 /home/pi/.ssh/authorized_keys
systemctl enable ssh
if [ "${local_access_enable}" != "true" ] ; then
echo "*** Disabling local access and turning off HDMI on startup... [local_access_enable=${local_access_enable}]"
echo "@reboot root /usr/bin/tvservice --off" > /etc/cron.d/tvserviceoff
sed -i 's/ console=serial0,115200 console=tty1/ panic=0/g' /boot/cmdline.txt
mv /etc/securetty /etc/securetty.bak && touch /etc/securetty
systemctl disable getty@tty1.service
systemctl disable serial-getty@ttyAMA0.service
sed -i '#NAutoVTs=6 a NAutoVTs=0' /etc/systemd/logind.conf
passwd -l pi
fi
sync
echo "System will now reboot..."
reboot
exit 0
fi
if [ ! -f ./rpisetup-flag-part2 ] ; then
touch ./rpisetup-flag-part2
echo "Waiting 20 more seconds for network..."
sleep 20
###
### Install software
###
echo "*** Upgrading system and setting up unattended upgrades..."
## Upgrade first
sed -i 's/ http:\/\// https:\/\//g' /etc/apt/sources.list.d/raspi.list
rpi-update
apt-get update
apt-get -y upgrade
apt-get -y install unattended-upgrades
echo "
Unattended-Upgrade::Remove-Unused-Dependencies "true";
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "02:00";
Unattended-Upgrade::SyslogEnable "true";
Unattended-Upgrade::SyslogFacility "daemon";
" >> /etc/apt/apt.conf.d/50unattended-upgrades
echo "*** Enable HW RNG..."
apt-get -y install rng-tools
echo "*** Regenerating SSH host keys..."
ssh-keygen -t rsa -b 4096 -N "" -f /etc/ssh/ssh_host_rsa_key-new
ssh-keygen -t ecdsa -b 521 -N "" -f /etc/ssh/ssh_host_ecdsa_key-new
ssh-keygen -t ed25519 -N "" -f /etc/ssh/ssh_host_ed25519_key-new
mv /etc/ssh/ssh_host_rsa_key-new /etc/ssh/ssh_host_rsa_key
mv /etc/ssh/ssh_host_ecdsa_key-new /etc/ssh/ssh_host_ecdsa_key
mv /etc/ssh/ssh_host_ed25519_key-new /etc/ssh/ssh_host_ed25519_key
echo "*** Encrypting swap..."
apt-get -y purge dphys-swapfile dc
dd if=/dev/urandom of=/opt/swap-device.bin bs=1M count=1024 iflag=fullblock
echo "swap /opt/swap-device.bin /dev/urandom swap,cipher=aes-xts-plain64:sha256,size=256" > /etc/crypttab
echo "/dev/mapper/swap swap swap defaults 0 0" >> /etc/fstab
echo "*** Enabling firewall..."
export DEBIAN_FRONTEND="noninteractive"
apt-get install -y iptables-persistent
if [ "${wifi_enable}" = "true" ] ; then
skipDevice="nonexistingpattern"
else
skipDevice="wlan0"
fi
echo "
# Default to block anything IPv6
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
COMMIT
" | grep -v ${skipDevice} > /etc/iptables/rules.v6
echo "# DROP everything that isn't explicitly permitted
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
# Drop invalid packets right away
-A INPUT -m conntrack --ctstate INVALID -j DROP
# Drop fragmented ICMP packets
-A INPUT --fragment -p icmp -j DROP
# Respond to ICMP ping
-A INPUT -i eth0 -p icmp --icmp-type echo-request -m state --state NEW,ESTABLISHED -j ACCEPT
-A INPUT -i wlan0 -p icmp --icmp-type echo-request -m state --state NEW,ESTABLISHED -j ACCEPT
-A OUTPUT -o eth0 -p icmp --icmp-type echo-reply -m state --state ESTABLISHED -j ACCEPT
-A OUTPUT -o wlan0 -p icmp --icmp-type echo-reply -m state --state ESTABLISHED -j ACCEPT
# Allow outgoing ICMP ping from the user ('pi', UID=1000)
-A OUTPUT -o eth0 -p icmp --icmp-type echo-request -m state --state NEW,ESTABLISHED -m owner --uid-owner 1000 -j ACCEPT
-A OUTPUT -o wlan0 -p icmp --icmp-type echo-request -m state --state NEW,ESTABLISHED -m owner --uid-owner 1000 -j ACCEPT
# And successful ICMP pong responses
-A INPUT -i eth0 -p icmp --icmp-type echo-reply -m state --state ESTABLISHED -j ACCEPT
-A INPUT -i wlan0 -p icmp --icmp-type echo-reply -m state --state ESTABLISHED -j ACCEPT
# Allow DHCP
-A OUTPUT -o eth0 -p udp --sport 68 --dport 67 -m state --state NEW,ESTABLISHED -j ACCEPT
-A OUTPUT -o wlan0 -p udp --sport 68 --dport 67 -m state --state NEW,ESTABLISHED -j ACCEPT
# Allow result of DHCP requests to be returned
-A INPUT -i eth0 -p udp --sport 67 --dport 68 -m state --state ESTABLISHED -j ACCEPT
-A INPUT -i wlan0 -p udp --sport 67 --dport 68 -m state --state ESTABLISHED -j ACCEPT
# Allow mDNS from the avahi daemon ('avahi', UID=108)
-A OUTPUT -o eth0 -p udp -m owner --uid-owner 108 --dport 5353 -j ACCEPT
-A OUTPUT -o wlan0 -p udp -m owner --uid-owner 108 --dport 5353 -j ACCEPT
-A INPUT -i eth0 -p udp -d 224.0.0.251 --dport 5353 -j ACCEPT
-A INPUT -i wlan0 -p udp -d 224.0.0.251 --dport 5353 -j ACCEPT
# Allow DNS queries by required apps daemon ('systemd-timesync', UID=100; '_apt', UID=104)
-A OUTPUT -o eth0 -p udp --dport 53 --sport 1024:65535 -m state --state NEW,ESTABLISHED -m owner --uid-owner 100 -j ACCEPT
-A OUTPUT -o wlan0 -p udp --dport 53 --sport 1024:65535 -m state --state NEW,ESTABLISHED -m owner --uid-owner 100 -j ACCEPT
-A OUTPUT -o eth0 -p udp --dport 53 --sport 1024:65535 -m state --state NEW,ESTABLISHED -m owner --uid-owner 104 -j ACCEPT
-A OUTPUT -o wlan0 -p udp --dport 53 --sport 1024:65535 -m state --state NEW,ESTABLISHED -m owner --uid-owner 104 -j ACCEPT
# Allow result of DNS queries to be returned
-A INPUT -i eth0 -p udp --sport 53 --dport 1024:65535 -m state --state ESTABLISHED -j ACCEPT
-A INPUT -i wlan0 -p udp --sport 53 --dport 1024:65535 -m state --state ESTABLISHED -j ACCEPT
# Allow NTP queries by NTP daemon ('systemd-timesync', UID=100)
-A OUTPUT -o eth0 -p udp --dport 123 -m state --state NEW,ESTABLISHED -m owner --uid-owner 100 -j ACCEPT
-A OUTPUT -o wlan0 -p udp --dport 123 -m state --state NEW,ESTABLISHED -m owner --uid-owner 100 -j ACCEPT
# Allow result of NTP queries to be returned
-A INPUT -i eth0 -p udp --sport 123 -m state --state ESTABLISHED -j ACCEPT
-A INPUT -i wlan0 -p udp --sport 123 -m state --state ESTABLISHED -j ACCEPT
# Allow incoming SSH connections
-A INPUT -i eth0 -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
-A INPUT -i wlan0 -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
-A OUTPUT -o eth0 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
-A OUTPUT -o wlan0 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
# Allow APT to fetch updates over HTTP and HTTPS. ('_apt', UID=104)
-A OUTPUT -o eth0 -p tcp --dport 80 -m state --state NEW,ESTABLISHED -m owner --uid-owner 104 -j ACCEPT
-A OUTPUT -o wlan0 -p tcp --dport 80 -m state --state NEW,ESTABLISHED -m owner --uid-owner 104 -j ACCEPT
-A OUTPUT -o eth0 -p tcp --dport 443 -m state --state NEW,ESTABLISHED -m owner --uid-owner 104 -j ACCEPT
-A OUTPUT -o wlan0 -p tcp --dport 443 -m state --state NEW,ESTABLISHED -m owner --uid-owner 104 -j ACCEPT
# Allow result of HTTP/HTTPS to be returned
-A INPUT -i eth0 -p tcp --sport 80 -m state --state ESTABLISHED -j ACCEPT
-A INPUT -i wlan0 -p tcp --sport 80 -m state --state ESTABLISHED -j ACCEPT
-A INPUT -i eth0 -p tcp --sport 443 -m state --state ESTABLISHED -j ACCEPT
-A INPUT -i wlan0 -p tcp --sport 443 -m state --state ESTABLISHED -j ACCEPT
# Log anything that will hit the default DROP-policy
-A INPUT -m limit --limit 20/min -j LOG --log-prefix \"iptables dropped: \" --log-level 7
-A OUTPUT -m limit --limit 20/min -j LOG --log-prefix \"iptables dropped: \" --log-level 7 --log-uid
-A FORWARD -m limit --limit 20/min -j LOG --log-prefix \"iptables dropped: \" --log-level 7 --log-uid
${additional_iptables_rules}
COMMIT
" | grep -v ${skipDevice} > /etc/iptables/rules.v4
iptables-restore --test /etc/iptables/rules.v4
iptables-restore --test /etc/iptables/rules.v6
if [ "${watchdog_enable}" = "true" ] ; then
echo "*** Enabling HW watchdog service..."
apt-get install -y watchdog
echo "
max-load-1 = 48
max-load-5 = 36
max-load-15 = 24
min-memory = 1
watchdog-device = /dev/watchdog
watchdog-timeout=15
interval=5
temperature-sensor = /sys/class/thermal/thermal_zone0/temp
max-temperature = 75
" >> /etc/watchdog.conf
fi
echo "*** Enable NTP..."
timedatectl set-ntp true
echo "*** Setting a up a message on login..."
echo "
*****************************************************************************
Raspbian base system configured by rpisetup.sh `date --rfc-3339=seconds`.
See /var/log/syslog for installation history.
Run /home/pi/verify.sh to quickly verify configuration.
*****************************************************************************" >> /etc/motd
echo "*** Adding verification script..."
echo "#!/bin/bash
echo \"**** Time and date ****\"
timedatectl status
echo \"**** Network interfaces ****\"
ip addr list
echo \"**** Swap ****\"
grep SwapTotal /proc/meminfo
echo \"**** Disk usage ****\"
df -h
echo \"**** Firewall ****\"
sudo systemctl status netfilter-persistent
sudo iptables -L -n
sudo ip6tables -L -n
echo \"**** OpenSSH configuration ****\"
grep -v \"#\" /etc/ssh/sshd_config | sed '/^$/d'
echo \"**** Account status ****\"
passwd --status pi
sudo passwd --status root
" > /home/pi/verify.sh
chown pi:pi /home/pi/verify.sh
chmod 500 /home/pi/verify.sh
if [ "x${also_apt_get_packages}" != "x" ] ; then
echo "*** Installing additional requested packages..."
apt-get install -y ${also_apt_get_packages}
if [[ $also_apt_get_packages == *"vim"* ]]; then
echo "
\" Avoid automatic indention during paste
set paste
\" Allow crtl+shift+c for copying mouse selects instead of visual mode
set mouse-=a
" | tee /root/.vimrc | tee /home/pi/.vimrc
chown pi:pi /home/pi/.vimrc
fi
fi
echo "*** Adding verification script..."
###
### Clean up
###
rm /etc/cron.d/rpisetup ./rpisetup-flag-part1 ./rpisetup-flag-part2 ./rpisetup.conf "${0}"
sync
echo "*** Done! System will now reboot..."
reboot
fi
Once added, unmount and deploy the RPi3 with the SD card.
sync sudo umount /mnt/rpi-rootfs/ sudo rmdir /mnt/rpi-rootfs sudo eject ${SDCARD_DEVICE}
Your RPI3 should come up after a few minutes with the chosen hostname.