├── .gitignore ├── LICENSE ├── README.md ├── pillar ├── config.sls └── top.sls └── salt ├── base-system ├── init.sls ├── locale │ └── init.sls ├── non-root-user │ └── init.sls └── timezone │ └── init.sls ├── dnsmasq ├── custom.conf └── init.sls ├── masterless-minion └── init.sls ├── networking ├── init.sls └── interfaces ├── openvpn ├── etc_openvpn │ ├── dnsmasq.settings.default │ └── login.settings.default ├── init.sls ├── openvpn@.service.d │ └── restart.conf └── up.sh ├── sshd ├── .gitignore ├── init.sls └── sshd_config ├── top.sls ├── ufw ├── etc_default_ufw ├── etc_ufw │ ├── after.rules │ ├── before.rules │ ├── sysctl.conf │ └── ufw.conf ├── init.sls └── lib_ufw │ └── user.rules └── unattended-upgrades └── init.sls /.gitignore: -------------------------------------------------------------------------------- 1 | salt/openvpn/etc_openvpn/* 2 | !salt/openvpn/etc_openvpn/*.default 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 SUSE 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above 11 | copyright notice, this list of conditions and the following disclaimer 12 | in the documentation and/or other materials provided with the 13 | distribution. 14 | * Neither the name of Google Inc. nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Raspberry Pi OpenVPN sharing gateway 2 | 3 | This project allows you to give access to a VPN tunnel through multiple machines via a [Raspberry Pi](https://www.raspberrypi.org/) (1 or 2) with two network interfaces. 4 | 5 | Network topology follows: 6 | 7 | ``` 8 | +--------------+ 9 | | | X XXXXXX 10 | | host 1 +------+ XX XXX 11 | | | | X X 12 | +--------------+ | XX XX XX XX 13 | | X XX 14 | +--------------+ | +----------------+ eth0 +----------------+ eth1 XXXXX XX +-----------------+ 15 | | | +---->| | integrated | | USB XXX X | | 16 | | host 2 +----------->| switch +----------->+ Raspberry Pi +----------> X Internet XX ------>+ VPN endpoint | 17 | | | +---->| | | | X XX | | 18 | +--------------+ | +----------------+ +----------------+ XXX XXX XX +-----------------+ 19 | | XXX X XX X X 20 | +--------------+ | XX XXX XXX 21 | | | | XXX XXXX XXXX 22 | | host 3 +------+ 23 | | | 24 | +--------------+ 25 | 26 | ``` 27 | 28 | Raspberry Pi acts as router, very basic firewall, DHCP server, DNS cache and VPN endpoint. This project provides [SaltStack](http://saltstack.com/) files to configure the Pi. 29 | 30 | ## Hardware requirements 31 | 32 | - [Raspberry Pi 2](https://www.raspberrypi.org/products/raspberry-pi-2-model-b/) (original Model B Raspberry Pi also works but it's limited in bandwidth); 33 | - [Raspberry Pi case](https://www.raspberrypi.org/products/raspberry-pi-case/); 34 | - USB power adapter (5v, 2000mA, 10W) with micro USB plug; 35 | - microSD card (4GB or more); 36 | - [TRENDNET TU3-ETG USB3 Gigabit Ethernet adapter](https://www.trendnet.com/products/proddetail.asp?prod=315_TU3-ETG) (eth1 in the diagram above); 37 | 38 | ## Raspberry Pi base image preparation 39 | 40 | Follow the [official instructions](https://www.raspberrypi.org/documentation/installation/installing-images/README.md) to install Raspbian Lite. On a Linux host, you can also use the following quicker ones: 41 | 42 | ``` 43 | wget http://director.downloads.raspberrypi.org/raspbian_lite/images/raspbian_lite-2017-04-10/2017-04-10-raspbian-jessie-lite.zip 44 | unzip *.zip 45 | sudo dd bs=4M if=`ls *.img` of=/dev/mmcblk0 # replace with your SD device (check journalctl) 46 | ``` 47 | 48 | Enable SSH, as it's by [disabled by default](https://www.raspberrypi.org/documentation/remote-access/ssh/) 49 | 50 | ``` 51 | mkdir -p /tmp/raspberrypi 52 | sudo mount -t vfat /dev/mmcblk0p1 /tmp/raspberrypi # see above for the device name 53 | touch /tmp/raspberrypi/ssh 54 | sudo umount /tmp/raspberrypi 55 | ``` 56 | 57 | ## Boot your Raspberry PI 58 | 59 | Connect your Raspberry PI (just Ethernet and power, you do not need a screen). 60 | 61 | ## Providing configuration 62 | ### Prepare OpenVPN configuration 63 | 64 | You need to have a proper OpenVPN configuration file, say `VPN.conf`, to use this project (for a starting point, see the [official HOWTO](https://openvpn.net/index.php/open-source/documentation/howto.html#config). It is recommended to test it separately. 65 | 66 | Copy that file and any other file it refers to in `salt/openvpn/etc_openvpn`. The configuration script will copy them to `/etc/openvpn`, so any file reference should point there (eg. `ca`, `cert`, `key`, etc.). 67 | 68 | Ensure your configuration file contains the following lines: 69 | 70 | ``` 71 | # reads username and password from the first two lines of login.settings 72 | auth-user-pass login.settings 73 | 74 | # runs when the connection is up 75 | up /etc/openvpn/up.sh 76 | ``` 77 | 78 | Copy `salt/openvpn/etc_openvpn/login.settings.default` to `salt/openvpn/etc_openvpn/login.settings` and edit it. This file must contain your VPN credentials, if any are needed, for the VPN to be started automatically. 79 | 80 | Finally, make a copy of `salt/openvpn/etc_openvpn/dnsmasq.settings.default` by saving as `salt/openvpn/etc_openvpn/dnsmasq.settings` to configure any VPN-specific dnsmasq options (eg. search domains to be resolved inside the VPN, domain names to be resolved by DNS servers from inside the VPN, etc.). 81 | 82 | ### SSH configuration 83 | 84 | Copy the public SSH key you want to use to access the Raspberry Pi in `salt/sshd/authorized_keys` (password authentication is disabled in the next step). From the repo directory you can use: 85 | 86 | ``` 87 | cp ~/.ssh/id_rsa.pub salt/sshd/authorized_keys 88 | ``` 89 | 90 | ### Salt installation 91 | 92 | This project uses Salt to configure the Raspberry Pi. 93 | 94 | To install it, insert the SD card in your Raspberry Pi and connect it to a network where you can access it. Don't connect the USB Ethernet interface yet, and run the following commands: 95 | 96 | ``` 97 | ssh pi@raspberrypi.local # password is raspberry 98 | 99 | sudo raspi-config 100 | # change password 101 | # advanced options -> expand filesystem 102 | # localisation options -> change locale (personal preference: en-US.UTF-8) 103 | # localisation options -> change timezone 104 | # finish and reboot 105 | 106 | echo deb http://debian.saltstack.com/debian jessie-saltstack main | sudo tee --append /etc/apt/sources.list 107 | gpg --keyserver pgpkeys.mit.edu --recv-key B09E40B0F2AE6AB9 108 | gpg -a --export B09E40B0F2AE6AB9 | sudo apt-key add - 109 | sudo apt-get update 110 | sudo apt-get -y install salt-minion 111 | sudo chown -R pi /srv 112 | ``` 113 | 114 | Now copy configuration files from this project onto the Raspberry Pi: 115 | 116 | ``` 117 | scp -r . pi@raspberrypi.local://srv 118 | ``` 119 | 120 | Run Salt to configure it and finally reboot: 121 | 122 | ``` 123 | ssh pi@raspberrypi.local 124 | 125 | sudo salt-call --local state.highstate 126 | sudo shutdown -h now 127 | ``` 128 | 129 | Now change your network cables to the configuration above, done! 130 | 131 | ## Post-install access 132 | 133 | A personal user has been created as you defined in `pillar/config.sls`. Password for 134 | this user has been set to `changeme`. Upon the first connection, (remember to use your SSH key that you copied in `salt/sshd/authorized_keys`), you will be asked to 135 | change it. 136 | 137 | SSH is configured to accept connections on port 22. Note that security settings are [tuned as per recent recommended standards](https://stribika.github.io/2015/01/04/secure-secure-shell.html), including the fact that the RSA key is regenerated with key length 4096 bits, so you will get warnings on first connection attempt. 138 | 139 | ## Tweaking 140 | 141 | You can change the domain name for the Raspberry Pi subnetwork in `pillar/config.sls`. 142 | 143 | The Raspberry Pi subnet is `192.168.188.0/24` as specified in `salt/dnsmasq/dnsmasq.settings` and `salt/networking/interfaces`. You have to change those files if you want a different subnetwork. 144 | 145 | Any other aspect can be tweaked directly in SaltStack files, which should be pretty self-explainatory. 146 | 147 | If you make an improvement don't forget to open a pull request! 148 | -------------------------------------------------------------------------------- /pillar/config.sls: -------------------------------------------------------------------------------- 1 | hostname: raspberrypi 2 | domain: moio 3 | # additional_search_domains: mycompany.example, myothercompany.example 4 | locale: en_US 5 | additional_locale: en_GB 6 | timezone: Europe/Rome 7 | preferred_raspbian_mirror: http://raspbian.mirror.garr.it/mirrors/raspbian/raspbian/ 8 | user_name: user 9 | user_real_name: User 10 | -------------------------------------------------------------------------------- /pillar/top.sls: -------------------------------------------------------------------------------- 1 | base: 2 | '*': 3 | - config 4 | -------------------------------------------------------------------------------- /salt/base-system/init.sls: -------------------------------------------------------------------------------- 1 | include: 2 | - base-system.locale 3 | - base-system.timezone 4 | - base-system.non-root-user 5 | 6 | hosts-file: 7 | file.replace: 8 | - name: /etc/hosts 9 | - pattern: "127\\.0\\.1\\.1.*" 10 | - repl: "127.0.1.1 {{ salt['pillar.get']('hostname','raspberrypi') }}.{{ salt['pillar.get']('domain','moio') }} {{ salt['pillar.get']('hostname','raspberrypi') }}" 11 | - append_if_not_found: true 12 | 13 | set-temporary-hostname: 14 | cmd.run: 15 | - name: hostnamectl set-hostname {{ salt['pillar.get']('hostname','raspberrypi') }} 16 | - unless: "hostnamectl status | grep -o 'Static hostname: {{ salt['pillar.get']('hostname','raspberrypi') }}'" 17 | 18 | set-permanent-hostname: 19 | file.managed: 20 | - name: /etc/hostname 21 | - contents: {{ salt['pillar.get']('hostname','raspberrypi') }} 22 | 23 | trust Salt repo key: 24 | cmd.run: 25 | - name: apt-key adv --keyserver keyserver.ubuntu.com --recv-keys B09E40B0F2AE6AB9 26 | - unless: apt-key list | grep '4096R/F2AE6AB9' 27 | 28 | replace default repo with preferred: 29 | file.replace: 30 | - name: /etc/apt/sources.list 31 | - pattern: deb http://mirrordirector.raspbian.org/raspbian/ 32 | - repl: deb {{ salt['pillar.get']('preferred_raspbian_mirror', 'http://raspbian.mirror.garr.it/mirrors/raspbian/raspbian/') }} 33 | - unless: grep {{ salt['pillar.get']('preferred_raspbian_mirror', 'http://raspbian.mirror.garr.it/mirrors/raspbian/raspbian/') }} /etc/apt/sources.list 34 | 35 | upgrade all packages: 36 | pkg.uptodate: 37 | - refresh: True 38 | - require: 39 | - cmd: trust Salt repo key 40 | - file: replace default repo with preferred 41 | -------------------------------------------------------------------------------- /salt/base-system/locale/init.sls: -------------------------------------------------------------------------------- 1 | locale-gen-config: 2 | file.replace: 3 | - name: /etc/locale.gen 4 | - pattern: "# {{ salt['pillar.get']('locale','en_US') }}.UTF-8 UTF-8" 5 | - repl: "{{ salt['pillar.get']('locale','en_US') }}.UTF-8 UTF-8" 6 | - backup: False 7 | - unless: grep "^{{ salt['pillar.get']('locale','en_US') }}.UTF-8 UTF-8" /etc/locale.gen 8 | 9 | locale-gen-config-additional: 10 | file.replace: 11 | - name: /etc/locale.gen 12 | - pattern: "# {{ salt['pillar.get']('additional_locale','en_GB') }}.UTF-8 UTF-8" 13 | - repl: "{{ salt['pillar.get']('additional_locale','en_GB') }}.UTF-8 UTF-8" 14 | - backup: False 15 | - unless: grep "^{{ salt['pillar.get']('additional_locale','en_GB') }}.UTF-8 UTF-8" /etc/locale.gen 16 | 17 | locale-config: 18 | file.managed: 19 | - name: /etc/default/locale 20 | - contents: "LANG={{ salt['pillar.get']('locale','en_US') }}.UTF-8\nLC_TIME=\"{{ salt['pillar.get']('additional_locale','en_GB') }}.UTF-8\"\nLC_PAPER=\"{{ salt['pillar.get']('additional_locale','en_GB') }}.UTF-8\"\nLC_MEASUREMENT=\"{{ salt['pillar.get']('additional_locale','en_GB') }}.UTF-8\"\n" 21 | 22 | locale-reconfigure: 23 | cmd.run: 24 | - name: dpkg-reconfigure -f noninteractive locales 25 | - require: 26 | - file: locale-gen-config 27 | - file: locale-gen-config-additional 28 | - file: locale-config 29 | - onchanges: 30 | - file: /etc/locale.gen 31 | - file: /etc/default/locale 32 | 33 | locale-update: 34 | cmd.run: 35 | - name: update-locale LANG={{ salt['pillar.get']('locale','en_US') }}.UTF-8 36 | - require: 37 | - cmd: locale-reconfigure 38 | - onchanges: 39 | - file: /etc/locale.gen 40 | - file: /etc/default/locale 41 | -------------------------------------------------------------------------------- /salt/base-system/non-root-user/init.sls: -------------------------------------------------------------------------------- 1 | user-creation: 2 | user.present: 3 | - name: {{ salt['pillar.get']('user_name', 'user') }} 4 | - password: $1$LioLpkU4$3HYx.bRJmq79nCZcvyoDw1 # changeme 5 | - enforce_password: False 6 | - gid: users 7 | - fullname: {{ salt['pillar.get']('user_real_name', 'User') }} 8 | - shell: /bin/bash 9 | - groups: 10 | - sudo 11 | - adm 12 | - dialout 13 | - cdrom 14 | - audio 15 | - video 16 | - plugdev 17 | - games 18 | - input 19 | - netdev 20 | - spi 21 | - i2c 22 | - gpio 23 | 24 | user-creation-force-password-change: 25 | cmd.run: 26 | - name: "chage -d 0 {{ salt['pillar.get']('user_name') }}" 27 | - onchanges: 28 | - user: user-creation 29 | 30 | /srv: 31 | file.directory: 32 | - user: {{ salt['pillar.get']('user_name', 'user') }} 33 | - group: users 34 | - recurse: 35 | - user 36 | - group 37 | - onchanges: 38 | - user: user-creation 39 | 40 | pi-user-deletion: 41 | user.absent: 42 | - name: pi 43 | - purge: True 44 | - force: True 45 | require: 46 | - sls: sshd 47 | -------------------------------------------------------------------------------- /salt/base-system/timezone/init.sls: -------------------------------------------------------------------------------- 1 | timezone-config: 2 | file.managed: 3 | - name: /etc/timezone 4 | - contents: {{ salt['pillar.get']('timezone','Europe/Rome') }} 5 | 6 | timezone-reconfigure: 7 | cmd.run: 8 | - name: dpkg-reconfigure -f noninteractive tzdata 9 | - require: 10 | - file: timezone-config 11 | - onchanges: 12 | - file: /etc/timezone 13 | -------------------------------------------------------------------------------- /salt/dnsmasq/custom.conf: -------------------------------------------------------------------------------- 1 | # Never forward plain names (without a dot or domain part) 2 | domain-needed 3 | 4 | # Never forward addresses in the non-routed address spaces. 5 | bogus-priv 6 | 7 | # Queries in these domains are answered from /etc/hosts or DHCP only 8 | local=/{{ salt['pillar.get']('domain', 'moio') }}/ 9 | 10 | # Interface _not_ to listen on 11 | except-interface=eth1 12 | 13 | # Domain for dnsmasq 14 | domain={{ salt['pillar.get']('domain', 'moio') }} 15 | 16 | # Enable the integrated DHCP server on this range of addresses, with the 17 | # specified lease time 18 | dhcp-range=192.168.188.50,192.168.188.150,12h 19 | 20 | # Set the NTP time server address to be the dnsmasq host 21 | dhcp-option=42,0.0.0.0 22 | 23 | # Do not use data from /etc/hosts 24 | no-hosts 25 | 26 | # Use data from /etc/hosts.dnsmasq instead 27 | addn-hosts=/etc/hosts.dnsmasq 28 | 29 | # Send RFC-3397 DNS domain search DHCP option 30 | dhcp-option=option:domain-search,{{ salt['pillar.get']('domain', 'local') }},{{ salt['pillar.get']('additional_search_domains', '') }} 31 | 32 | # Include openVPN specific settings 33 | conf-file=/etc/openvpn/dnsmasq.settings 34 | -------------------------------------------------------------------------------- /salt/dnsmasq/init.sls: -------------------------------------------------------------------------------- 1 | dnsmasq: 2 | pkg: 3 | - installed 4 | service: 5 | - running 6 | - enable: True 7 | - require: 8 | - pkg: dnsmasq 9 | - watch: 10 | - file: /etc/dnsmasq.d/custom.conf 11 | - file: /etc/hosts.dnsmasq 12 | 13 | dnsmasq_custom_config_file: 14 | file.managed: 15 | - name: /etc/dnsmasq.d/custom.conf 16 | - source: salt://dnsmasq/custom.conf 17 | - template: jinja 18 | - user: root 19 | - group: root 20 | - mode: 644 21 | - require: 22 | - pkg: dnsmasq 23 | 24 | dnsmasq_hosts_file: 25 | file.managed: 26 | - name: /etc/hosts.dnsmasq 27 | - contents: 192.168.188.1 {{ salt['pillar.get']('hostname','raspberrypi') }}.{{ salt['pillar.get']('domain','moio') }} {{ salt['pillar.get']('hostname','raspberrypi') }} 28 | - user: root 29 | - group: root 30 | - mode: 644 31 | -------------------------------------------------------------------------------- /salt/masterless-minion/init.sls: -------------------------------------------------------------------------------- 1 | set masterless minion: 2 | file.append: 3 | - name: /etc/salt/minion 4 | - text: "file_client: local" 5 | 6 | salt-minion: 7 | service: 8 | - running 9 | - enable: True 10 | - watch: 11 | - file: /etc/salt/minion 12 | -------------------------------------------------------------------------------- /salt/networking/init.sls: -------------------------------------------------------------------------------- 1 | networking: 2 | service: 3 | - running 4 | - enable: True 5 | - watch: 6 | - file: /etc/network/interfaces 7 | 8 | /etc/network/interfaces: 9 | file.managed: 10 | - source: salt://networking/interfaces 11 | - template: jinja 12 | - user: root 13 | - group: root 14 | - mode: 644 15 | -------------------------------------------------------------------------------- /salt/networking/interfaces: -------------------------------------------------------------------------------- 1 | auto lo 2 | iface lo inet loopback 3 | 4 | # Raspberry Pi's builtin port, connected to the internal network 5 | auto eth0 6 | iface eth0 inet static 7 | address 192.168.188.1 8 | netmask 255.255.255.0 9 | 10 | # USB adapter port, connected to the Internet 11 | auto eth1 12 | iface eth1 inet dhcp 13 | -------------------------------------------------------------------------------- /salt/openvpn/etc_openvpn/dnsmasq.settings.default: -------------------------------------------------------------------------------- 1 | # Use the 10.160.1.1 DNS server from inside the VPN to resolve hostnames in the vpndomain.com domain 2 | # NOTE: rename this file to `dnsmasq.settings` before calling salt highstate 3 | server=/vpndomain.com/10.160.1.1 4 | -------------------------------------------------------------------------------- /salt/openvpn/etc_openvpn/login.settings.default: -------------------------------------------------------------------------------- 1 | # replace this line with your username 2 | # replace this line with your password 3 | -------------------------------------------------------------------------------- /salt/openvpn/init.sls: -------------------------------------------------------------------------------- 1 | openvpn: 2 | pkg: 3 | - installed 4 | service: 5 | - running 6 | - enable: True 7 | - require: 8 | - pkg: openvpn 9 | - watch: 10 | - file: /etc/openvpn 11 | - file: /etc/systemd/system/openvpn@.service.d/restart.conf 12 | 13 | /etc/openvpn: 14 | file.recurse: 15 | - source: salt://openvpn/etc_openvpn 16 | - template: jinja 17 | - user: root 18 | - group: root 19 | - file_mode: 600 20 | 21 | /etc/openvpn/up.sh: 22 | file.managed: 23 | - source: salt://openvpn/up.sh 24 | - user: root 25 | - group: root 26 | - mode: 700 27 | 28 | /etc/systemd/system/openvpn@.service.d/restart.conf: 29 | file.managed: 30 | - source: salt://openvpn/openvpn@.service.d/restart.conf 31 | - user: root 32 | - group: root 33 | - mode: 644 34 | - dir_mode: 755 35 | - makedirs: True 36 | -------------------------------------------------------------------------------- /salt/openvpn/openvpn@.service.d/restart.conf: -------------------------------------------------------------------------------- 1 | [Service] 2 | Restart=always 3 | RestartSec=30 4 | -------------------------------------------------------------------------------- /salt/openvpn/up.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | /sbin/iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE 4 | -------------------------------------------------------------------------------- /salt/sshd/.gitignore: -------------------------------------------------------------------------------- 1 | authorized_keys -------------------------------------------------------------------------------- /salt/sshd/init.sls: -------------------------------------------------------------------------------- 1 | generate rsa key: 2 | cmd.run: 3 | - name: | 4 | cd /etc/ssh && rm ssh_host_*key* 5 | ssh-keygen -t ed25519 -N "" -f ssh_host_ed25519_key 6 | ssh-keygen -t rsa -N "" -b 4096 -f ssh_host_rsa_key 7 | - unless: openssl rsa -text -noout -in /etc/ssh/ssh_host_rsa_key | grep "4096 bit" && test -f /etc/ssh/ssh_host_ed25519_key 8 | - require: 9 | - pkg: sshd 10 | 11 | purge moduli: 12 | cmd.run: 13 | - name: | 14 | awk '$5 > 2000' /etc/ssh/moduli > /tmp/moduli && mv /tmp/moduli /etc/ssh/moduli 15 | - onlyif: awk '$5 <= 2000' /etc/ssh/moduli | grep '.' 16 | - require: 17 | - pkg: sshd 18 | 19 | authorized_keys: 20 | file.managed: 21 | - source: salt://sshd/authorized_keys 22 | - name: /home/pi/.ssh/authorized_keys 23 | - makedirs: True 24 | - user: pi 25 | - group: pi 26 | - mode: 600 27 | 28 | sshd_config: 29 | file.managed: 30 | - source: salt://sshd/sshd_config 31 | - name: /etc/ssh/sshd_config 32 | - user: root 33 | - group: root 34 | - mode: 644 35 | - require: 36 | - pkg: sshd 37 | - cmd: generate rsa key 38 | - file: authorized_keys 39 | 40 | sshd: 41 | pkg.installed: 42 | - pkgs: 43 | - openssh-server 44 | - openssl 45 | service.running: 46 | - name: ssh 47 | - enable: True 48 | - watch: 49 | - file: sshd_config 50 | - require: 51 | - pkg: sshd 52 | - file: sshd_config 53 | -------------------------------------------------------------------------------- /salt/sshd/sshd_config: -------------------------------------------------------------------------------- 1 | # Package generated configuration file 2 | # See the sshd_config(5) manpage for details 3 | 4 | # What ports, IPs and protocols we listen for 5 | Port 22 6 | # Use these options to restrict which interfaces/protocols sshd will bind to 7 | #ListenAddress :: 8 | #ListenAddress 0.0.0.0 9 | Protocol 2 10 | # HostKeys for protocol version 2 11 | HostKey /etc/ssh/ssh_host_ed25519_key 12 | HostKey /etc/ssh/ssh_host_rsa_key 13 | 14 | # Disable weak crypto - https://presentations.nordisch.org/olddognewtricks/#/ 15 | KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256 16 | Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr 17 | MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-ripemd160-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,hmac-ripemd160,umac-128@openssh.com 18 | 19 | PubkeyAuthentication yes 20 | PasswordAuthentication no 21 | # reenable if you want to use OTP together with ssh keys 22 | ChallengeResponseAuthentication no 23 | 24 | #Privilege Separation is turned on for security 25 | UsePrivilegeSeparation yes 26 | 27 | # Lifetime and size of ephemeral version 1 server key 28 | KeyRegenerationInterval 3600 29 | ServerKeyBits 1024 30 | 31 | # Logging 32 | SyslogFacility AUTH 33 | LogLevel INFO 34 | 35 | # Authentication: 36 | LoginGraceTime 120 37 | PermitRootLogin without-password 38 | StrictModes yes 39 | 40 | RSAAuthentication yes 41 | PubkeyAuthentication yes 42 | AuthorizedKeysFile %h/.ssh/authorized_keys 43 | 44 | # Don't read the user's ~/.rhosts and ~/.shosts files 45 | IgnoreRhosts yes 46 | # For this to work you will also need host keys in /etc/ssh_known_hosts 47 | RhostsRSAAuthentication no 48 | # similar for protocol version 2 49 | HostbasedAuthentication no 50 | # Uncomment if you don't trust ~/.ssh/known_hosts for RhostsRSAAuthentication 51 | #IgnoreUserKnownHosts yes 52 | 53 | # To enable empty passwords, change to yes (NOT RECOMMENDED) 54 | PermitEmptyPasswords no 55 | 56 | # Change to yes to enable challenge-response passwords (beware issues with 57 | # some PAM modules and threads) 58 | ChallengeResponseAuthentication no 59 | 60 | # Change to no to disable tunnelled clear text passwords 61 | PasswordAuthentication no 62 | 63 | # Kerberos options 64 | #KerberosAuthentication no 65 | #KerberosGetAFSToken no 66 | #KerberosOrLocalPasswd yes 67 | #KerberosTicketCleanup yes 68 | 69 | # GSSAPI options 70 | #GSSAPIAuthentication no 71 | #GSSAPICleanupCredentials yes 72 | 73 | X11Forwarding yes 74 | X11DisplayOffset 10 75 | PrintMotd no 76 | PrintLastLog yes 77 | TCPKeepAlive yes 78 | #UseLogin no 79 | 80 | #MaxStartups 10:30:60 81 | #Banner /etc/issue.net 82 | 83 | # Allow client to pass locale environment variables 84 | AcceptEnv LANG LC_* 85 | 86 | Subsystem sftp /usr/lib/openssh/sftp-server 87 | 88 | # Set this to 'yes' to enable PAM authentication, account processing, 89 | # and session processing. If this is enabled, PAM authentication will 90 | # be allowed through the ChallengeResponseAuthentication and 91 | # PasswordAuthentication. Depending on your PAM configuration, 92 | # PAM authentication via ChallengeResponseAuthentication may bypass 93 | # the setting of "PermitRootLogin without-password". 94 | # If you just want the PAM account and session checks to run without 95 | # PAM authentication, then enable this but set PasswordAuthentication 96 | # and ChallengeResponseAuthentication to 'no'. 97 | UsePAM yes 98 | 99 | ClientAliveInterval 30 100 | ClientAliveCountMax 10 101 | -------------------------------------------------------------------------------- /salt/top.sls: -------------------------------------------------------------------------------- 1 | base: 2 | '*': 3 | - base-system 4 | - masterless-minion 5 | - sshd 6 | - networking 7 | - ufw 8 | - openvpn 9 | - dnsmasq 10 | - unattended-upgrades 11 | -------------------------------------------------------------------------------- /salt/ufw/etc_default_ufw: -------------------------------------------------------------------------------- 1 | # /etc/default/ufw 2 | # 3 | 4 | # Set to yes to apply rules to support IPv6 (no means only IPv6 on loopback 5 | # accepted). You will need to 'disable' and then 'enable' the firewall for 6 | # the changes to take affect. 7 | IPV6=yes 8 | 9 | # Set the default input policy to ACCEPT, ACCEPT_NO_TRACK, DROP, or REJECT. 10 | # ACCEPT enables connection tracking for NEW inbound packets on the INPUT 11 | # chain, whereas ACCEPT_NO_TRACK does not use connection tracking. Please note 12 | # that if you change this you will most likely want to adjust your rules. 13 | DEFAULT_INPUT_POLICY="DROP" 14 | 15 | # Set the default output policy to ACCEPT, ACCEPT_NO_TRACK, DROP, or REJECT. 16 | # ACCEPT enables connection tracking for NEW outbound packets on the OUTPUT 17 | # chain, whereas ACCEPT_NO_TRACK does not use connection tracking. Please note 18 | # that if you change this you will most likely want to adjust your rules. 19 | DEFAULT_OUTPUT_POLICY="ACCEPT" 20 | 21 | # Set the default forward policy to ACCEPT, DROP or REJECT. Please note that 22 | # if you change this you will most likely want to adjust your rules 23 | DEFAULT_FORWARD_POLICY="ACCEPT" 24 | 25 | # Set the default application policy to ACCEPT, DROP, REJECT or SKIP. Please 26 | # note that setting this to ACCEPT may be a security risk. See 'man ufw' for 27 | # details 28 | DEFAULT_APPLICATION_POLICY="SKIP" 29 | 30 | # By default, ufw only touches its own chains. Set this to 'yes' to have ufw 31 | # manage the built-in chains too. Warning: setting this to 'yes' will break 32 | # non-ufw managed firewall rules 33 | MANAGE_BUILTINS=no 34 | 35 | # 36 | # IPT backend 37 | # 38 | # only enable if using iptables backend 39 | IPT_SYSCTL=/etc/ufw/sysctl.conf 40 | 41 | # Extra connection tracking modules to load. Complete list can be found in 42 | # net/netfilter/Kconfig of your kernel source. Some common modules: 43 | # nf_conntrack_irc, nf_nat_irc: DCC (Direct Client to Client) support 44 | # nf_conntrack_netbios_ns: NetBIOS (samba) client support 45 | # nf_conntrack_pptp, nf_nat_pptp: PPTP over stateful firewall/NAT 46 | # nf_conntrack_ftp, nf_nat_ftp: active FTP support 47 | # nf_conntrack_tftp, nf_nat_tftp: TFTP support (server side) 48 | IPT_MODULES="nf_conntrack_ftp nf_nat_ftp nf_conntrack_netbios_ns" 49 | 50 | -------------------------------------------------------------------------------- /salt/ufw/etc_ufw/after.rules: -------------------------------------------------------------------------------- 1 | # 2 | # rules.input-after 3 | # 4 | # Rules that should be run after the ufw command line added rules. Custom 5 | # rules should be added to one of these chains: 6 | # ufw-after-input 7 | # ufw-after-output 8 | # ufw-after-forward 9 | # 10 | 11 | # Don't delete these required lines, otherwise there will be errors 12 | *filter 13 | :ufw-after-input - [0:0] 14 | :ufw-after-output - [0:0] 15 | :ufw-after-forward - [0:0] 16 | # End required lines 17 | 18 | # don't log noisy services by default 19 | -A ufw-after-input -p udp --dport 137 -j ufw-skip-to-policy-input 20 | -A ufw-after-input -p udp --dport 138 -j ufw-skip-to-policy-input 21 | -A ufw-after-input -p tcp --dport 139 -j ufw-skip-to-policy-input 22 | -A ufw-after-input -p tcp --dport 445 -j ufw-skip-to-policy-input 23 | -A ufw-after-input -p udp --dport 67 -j ufw-skip-to-policy-input 24 | -A ufw-after-input -p udp --dport 68 -j ufw-skip-to-policy-input 25 | 26 | # don't log noisy broadcast 27 | -A ufw-after-input -m addrtype --dst-type BROADCAST -j ufw-skip-to-policy-input 28 | 29 | # don't delete the 'COMMIT' line or these rules won't be processed 30 | COMMIT 31 | -------------------------------------------------------------------------------- /salt/ufw/etc_ufw/before.rules: -------------------------------------------------------------------------------- 1 | # 2 | # rules.before 3 | # 4 | # Rules that should be run before the ufw command line added rules. Custom 5 | # rules should be added to one of these chains: 6 | # ufw-before-input 7 | # ufw-before-output 8 | # ufw-before-forward 9 | # 10 | 11 | # nat table rules 12 | *nat 13 | :POSTROUTING ACCEPT [0:0] 14 | 15 | # forward traffic from eth0 to eth1 16 | -A POSTROUTING -s 192.168.188.0/24 -o eth1 -j MASQUERADE 17 | 18 | # don't delete or the nat table won't be processed 19 | COMMIT 20 | 21 | # Don't delete these required lines, otherwise there will be errors 22 | *filter 23 | :ufw-before-input - [0:0] 24 | :ufw-before-output - [0:0] 25 | :ufw-before-forward - [0:0] 26 | :ufw-not-local - [0:0] 27 | # End required lines 28 | 29 | 30 | # allow all on loopback 31 | -A ufw-before-input -i lo -j ACCEPT 32 | -A ufw-before-output -o lo -j ACCEPT 33 | 34 | # quickly process packets for which we already have a connection 35 | -A ufw-before-input -m state --state RELATED,ESTABLISHED -j ACCEPT 36 | -A ufw-before-output -m state --state RELATED,ESTABLISHED -j ACCEPT 37 | 38 | # drop INVALID packets (logs these in loglevel medium and higher) 39 | -A ufw-before-input -m state --state INVALID -j ufw-logging-deny 40 | -A ufw-before-input -m state --state INVALID -j DROP 41 | 42 | # ok icmp codes 43 | -A ufw-before-input -p icmp --icmp-type destination-unreachable -j ACCEPT 44 | -A ufw-before-input -p icmp --icmp-type source-quench -j ACCEPT 45 | -A ufw-before-input -p icmp --icmp-type time-exceeded -j ACCEPT 46 | -A ufw-before-input -p icmp --icmp-type parameter-problem -j ACCEPT 47 | -A ufw-before-input -p icmp --icmp-type echo-request -j ACCEPT 48 | 49 | # allow dhcp client to work 50 | -A ufw-before-input -p udp --sport 67 --dport 68 -j ACCEPT 51 | 52 | # 53 | # ufw-not-local 54 | # 55 | -A ufw-before-input -j ufw-not-local 56 | 57 | # if LOCAL, RETURN 58 | -A ufw-not-local -m addrtype --dst-type LOCAL -j RETURN 59 | 60 | # if MULTICAST, RETURN 61 | -A ufw-not-local -m addrtype --dst-type MULTICAST -j RETURN 62 | 63 | # if BROADCAST, RETURN 64 | -A ufw-not-local -m addrtype --dst-type BROADCAST -j RETURN 65 | 66 | # all other non-local packets are dropped 67 | -A ufw-not-local -m limit --limit 3/min --limit-burst 10 -j ufw-logging-deny 68 | -A ufw-not-local -j DROP 69 | 70 | # allow MULTICAST mDNS for service discovery (be sure the MULTICAST line above 71 | # is uncommented) 72 | -A ufw-before-input -p udp -d 224.0.0.251 --dport 5353 -j ACCEPT 73 | 74 | # allow MULTICAST UPnP for service discovery (be sure the MULTICAST line above 75 | # is uncommented) 76 | -A ufw-before-input -p udp -d 239.255.255.250 --dport 1900 -j ACCEPT 77 | 78 | # don't delete the 'COMMIT' line or these rules won't be processed 79 | COMMIT 80 | -------------------------------------------------------------------------------- /salt/ufw/etc_ufw/sysctl.conf: -------------------------------------------------------------------------------- 1 | # 2 | # Configuration file for setting network variables. Please note these settings 3 | # override /etc/sysctl.conf and /etc/sysctl.d. If you prefer to use 4 | # /etc/sysctl.conf, please adjust IPT_SYSCTL in /etc/default/ufw. See 5 | # Documentation/networking/ip-sysctl.txt in the kernel source code for more 6 | # information. 7 | # 8 | 9 | # Uncomment this to allow this host to route packets between interfaces 10 | net/ipv4/ip_forward=1 11 | #net/ipv6/conf/default/forwarding=1 12 | #net/ipv6/conf/all/forwarding=1 13 | 14 | # IP Spoofing protection 15 | net/ipv4/conf/all/rp_filter = 1 16 | net/ipv6/conf/all/rp_filter = 1 17 | net/ipv4/conf/default/rp_filter = 1 18 | net/ipv6/conf/default/rp_filter = 1 19 | 20 | # Disable ICMP redirects. ICMP redirects are rarely used but can be used in 21 | # MITM (man-in-the-middle) attacks. Disabling ICMP may disrupt legitimate 22 | # traffic to those sites. 23 | net/ipv4/conf/all/accept_redirects=0 24 | net/ipv4/conf/default/accept_redirects=0 25 | net/ipv6/conf/all/accept_redirects=0 26 | net/ipv6/conf/default/accept_redirects=0 27 | net/ipv4/conf/all/send_redirects = 0 28 | net/ipv6/conf/all/send_redirects = 0 29 | net/ipv4/conf/default/send_redirects = 0 30 | net/ipv6/conf/default/send_redirects = 0 31 | 32 | # Disable source packet routing 33 | net/ipv4/conf/all/accept_source_route = 0 34 | net/ipv6/conf/all/accept_source_route = 0 35 | net/ipv4/conf/default/accept_source_route = 0 36 | net/ipv6/conf/default/accept_source_route = 0 37 | 38 | # Block SYN attacks 39 | net/ipv4/tcp_syncookies = 1 40 | net/ipv4/tcp_max_syn_backlog = 2048 41 | net/ipv4/tcp_synack_retries = 2 42 | net/ipv4/tcp_syn_retries = 5 43 | 44 | # Ignore ICMP broadcast requests 45 | net/ipv4/icmp_echo_ignore_broadcasts=1 46 | 47 | # Ignore bogus ICMP errors 48 | net/ipv4/icmp_ignore_bogus_error_responses=1 49 | net/ipv4/icmp_echo_ignore_all=0 50 | 51 | # Don't log Martian Packets (impossible addresses) 52 | # packets 53 | net/ipv4/conf/all/log_martians=0 54 | net/ipv4/conf/default/log_martians=0 55 | 56 | #net/ipv4/tcp_fin_timeout=30 57 | #net/ipv4/tcp_keepalive_intvl=1800 58 | 59 | # Uncomment this to turn off ipv6 autoconfiguration 60 | #net/ipv6/conf/default/autoconf=1 61 | #net/ipv6/conf/all/autoconf=1 62 | 63 | # Uncomment this to enable ipv6 privacy addressing 64 | #net/ipv6/conf/default/use_tempaddr=2 65 | #net/ipv6/conf/all/use_tempaddr=2 66 | -------------------------------------------------------------------------------- /salt/ufw/etc_ufw/ufw.conf: -------------------------------------------------------------------------------- 1 | # /etc/ufw/ufw.conf 2 | # 3 | 4 | # Set to yes to start on boot. If setting this remotely, be sure to add a rule 5 | # to allow your remote connection before starting ufw. Eg: 'ufw allow 22/tcp' 6 | ENABLED=yes 7 | 8 | # Please use the 'ufw' command to set the loglevel. Eg: 'ufw logging medium'. 9 | # See 'man ufw' for details. 10 | LOGLEVEL=low 11 | -------------------------------------------------------------------------------- /salt/ufw/init.sls: -------------------------------------------------------------------------------- 1 | ufw: 2 | pkg: 3 | - installed 4 | service: 5 | - running 6 | - enable: True 7 | - require: 8 | - pkg: ufw 9 | - watch: 10 | - file: /etc/ufw 11 | - file: /lib/ufw 12 | - file: /etc/default/ufw 13 | 14 | /etc/ufw: 15 | file.recurse: 16 | - source: salt://ufw/etc_ufw 17 | 18 | /lib/ufw: 19 | file.recurse: 20 | - source: salt://ufw/lib_ufw 21 | 22 | /etc/default/ufw: 23 | file.managed: 24 | - source: salt://ufw/etc_default_ufw 25 | -------------------------------------------------------------------------------- /salt/ufw/lib_ufw/user.rules: -------------------------------------------------------------------------------- 1 | *filter 2 | :ufw-user-input - [0:0] 3 | :ufw-user-output - [0:0] 4 | :ufw-user-forward - [0:0] 5 | :ufw-before-logging-input - [0:0] 6 | :ufw-before-logging-output - [0:0] 7 | :ufw-before-logging-forward - [0:0] 8 | :ufw-user-logging-input - [0:0] 9 | :ufw-user-logging-output - [0:0] 10 | :ufw-user-logging-forward - [0:0] 11 | :ufw-after-logging-input - [0:0] 12 | :ufw-after-logging-output - [0:0] 13 | :ufw-after-logging-forward - [0:0] 14 | :ufw-logging-deny - [0:0] 15 | :ufw-logging-allow - [0:0] 16 | :ufw-user-limit - [0:0] 17 | :ufw-user-limit-accept - [0:0] 18 | ### RULES ### 19 | 20 | ### tuple ### allow tcp 22 0.0.0.0/0 any 0.0.0.0/0 in_eth0 21 | -A ufw-user-input -i eth0 -p tcp --dport 22 -j ACCEPT 22 | 23 | ### tuple ### allow udp 53 0.0.0.0/0 any 0.0.0.0/0 in_eth0 24 | -A ufw-user-input -i eth0 -p udp --dport 53 -j ACCEPT 25 | 26 | ### tuple ### allow udp 67 0.0.0.0/0 any 0.0.0.0/0 in_eth0 27 | -A ufw-user-input -i eth0 -p udp --dport 67 -j ACCEPT 28 | 29 | ### tuple ### allow tcp 22 0.0.0.0/0 any 0.0.0.0/0 in_tun0 30 | -A ufw-user-input -i tun0 -p tcp --dport 22 -j ACCEPT 31 | 32 | ### END RULES ### 33 | 34 | ### LOGGING ### 35 | -A ufw-after-logging-input -j LOG --log-prefix "[UFW BLOCK] " -m limit --limit 3/min --limit-burst 10 36 | -I ufw-logging-deny -m state --state INVALID -j RETURN -m limit --limit 3/min --limit-burst 10 37 | -A ufw-logging-deny -j LOG --log-prefix "[UFW BLOCK] " -m limit --limit 3/min --limit-burst 10 38 | -A ufw-logging-allow -j LOG --log-prefix "[UFW ALLOW] " -m limit --limit 3/min --limit-burst 10 39 | ### END LOGGING ### 40 | 41 | ### RATE LIMITING ### 42 | -A ufw-user-limit -m limit --limit 3/minute -j LOG --log-prefix "[UFW LIMIT BLOCK] " 43 | -A ufw-user-limit -j REJECT 44 | -A ufw-user-limit-accept -j ACCEPT 45 | ### END RATE LIMITING ### 46 | COMMIT 47 | -------------------------------------------------------------------------------- /salt/unattended-upgrades/init.sls: -------------------------------------------------------------------------------- 1 | unattended-upgrades: 2 | pkg: 3 | - installed 4 | 5 | debconf.set: 6 | - data: 7 | 'unattended-upgrades/enable_auto_updates': 8 | type: boolean 9 | value: "true" 10 | - require: 11 | - pkg: unattended-upgrades 12 | 13 | cmd.wait: 14 | - name: "dpkg-reconfigure unattended-upgrades" 15 | - env: 16 | DEBIAN_FRONTEND: noninteractive 17 | DEBCONF_NONINTERACTIVE_SEEN: "true" 18 | - require: 19 | - pkg: unattended-upgrades 20 | - watch: 21 | - debconf: unattended-upgrades 22 | 23 | unattended-upgrades-config-source: 24 | file.replace: 25 | - name: /etc/apt/apt.conf.d/50unattended-upgrades 26 | - pattern: "// \"o=Raspbian,n=jessie\";" 27 | - repl: " \"o=Raspbian,n=jessie\";" 28 | - backup: False 29 | --------------------------------------------------------------------------------