Added Raspberry Pi OS server guide

This commit is contained in:
Sun Knudsen 2020-12-07 10:03:03 -05:00
parent 6e46d09d15
commit b6b792380e
No known key found for this signature in database
GPG Key ID: 1FA767862BBD1305
3 changed files with 438 additions and 17 deletions

View File

@ -0,0 +1,421 @@
<!--
Title: How to configure hardened Raspberry Pi OS server
Description: Learn how to configure hardened Raspberry Pi OS server.
Author: Sun Knudsen <https://github.com/sunknudsen>
Contributors: Sun Knudsen <https://github.com/sunknudsen>
Reviewers:
Publication date: 2020-11-27T10:00:26.807Z
Listed: true
-->
# How to configure hardened Raspberry Pi OS server
## Requirements
- [Raspberry Pi](https://www.raspberrypi.org/)
- Power adapter, keyboard and HDMI cable (and SD card reader if computer doesnt have one built-in)
- Linux or macOS computer
## Caveats
- When copy/pasting commands that start with `$`, strip out `$` as this character is not part of the command
- When copy/pasting commands that start with `cat << "EOF"`, select all lines at once (from `cat << "EOF"` to `EOF` inclusively) as they are part of the same (single) command
## Guide
### Step 1: create SSH key pair (on computer)
When asked for file in which to save key, enter `pi`.
When asked for passphrase, use output from `openssl rand -base64 24` (and store passphrase in password manager).
```shell
$ mkdir -p ~/.ssh
$ cd ~/.ssh
$ ssh-keygen -t rsa -C "pi"
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/sunknudsen/.ssh/id_rsa): pi
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in pi.
Your public key has been saved in pi.pub.
The key fingerprint is:
SHA256:NZkr0Bmu6tpQfDp2GHTIPyBz253uZk/gOmoqzEszGM0 pi
The key's randomart image is:
+---[RSA 3072]----+
| . |
| . . o o o |
| o * o + = |
| o * * + o o |
|. E = * S . |
|.. . * + o |
|++. * . o . |
|ooo=.o.oo. |
| o+++..+... |
+----[SHA256]-----+
$ cat pi.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCqEWjWQZY8HoLQEF7SmU/7f8dJuy/4r7/X6PbwrDzASym+5vCLz3QJIlLuJuQL557FsTzsz/sLFoTJnDkiQ3lZtFOofynyYQQiRDkZPy9nGz/j+rTHm6vfp17o8k1LeADKRq2mHpAljlf6/ywkKbzmGhXwnVsvxA0RvvNoujnpiLoSZFrq0wsfzIOi67ZzySlzxKmL0/Uxs9LJ+XFyKlVOILD+TMCayB6UNJ38PkghDZ/8spSSH44jkhmElPdqsqaJ/hqYYXT8q4sSB7Yp5RSYWDYIQiIs2cailho/gOCq/0AskREuGEuwPGL3ivOa2uBN544zrJHbegeliRwTwxSvFat9MoXjpWpEtTVpR5Skr2nGxwXZWYEGZ1u+iJc+Y67k7vabZYADAk1Q8VePAh2BOfhkhZfdAnBZJn9s/XISi/T8WxsLoG3twu1OMWtoiNMlwCUzeIzVRg5BMiFJjEtsANiETdrCuH/Ms9G/EMRo9gKh7moVbfwI+Urf0StIx3k= pi
```
### Step 2: generate heredoc (the output of following command will be used at [step 10](#step-10-configure-pi-ssh-authorized-keys))
```shell
cat << EOF
cat << _EOF > /home/pi/.ssh/authorized_keys
$(cat ~/.ssh/pi.pub)
_EOF
EOF
```
### Step 3: download latest version of [Raspberry Pi OS Lite](https://www.raspberrypi.org/software/operating-systems/)
### Step 4: clone "Raspberry Pi OS Lite" to SD card
> WARNING: DO NOT RUN THE FOLLOWING COMMANDS AS-IS.
Run `diskutil list` to find disk ID of SD card to override with "Raspberry Pi OS Lite" (`disk2` in the following example).
Replace `diskn` and `rdiskn` with disk ID of SD card (`disk2` and `rdisk2` in the following example) and `2020-12-02-raspios-buster-armhf-lite.img` with current image.
```console
$ diskutil list
/dev/disk0 (internal, physical):
#: TYPE NAME SIZE IDENTIFIER
0: GUID_partition_scheme *500.3 GB disk0
1: EFI EFI 209.7 MB disk0s1
2: Apple_APFS Container disk1 500.1 GB disk0s2
/dev/disk1 (synthesized):
#: TYPE NAME SIZE IDENTIFIER
0: APFS Container Scheme - +500.1 GB disk1
Physical Store disk0s2
1: APFS Volume Macintosh HD - Data 340.9 GB disk1s1
2: APFS Volume Preboot 85.9 MB disk1s2
3: APFS Volume Recovery 529.0 MB disk1s3
4: APFS Volume VM 3.2 GB disk1s4
5: APFS Volume Macintosh HD 11.3 GB disk1s5
/dev/disk2 (internal, physical):
#: TYPE NAME SIZE IDENTIFIER
0: FDisk_partition_scheme *15.9 GB disk2
1: Windows_FAT_32 boot 268.4 MB disk2s1
2: Linux 15.7 GB disk2s2
$ sudo diskutil unmount /dev/diskn
disk2 was already unmounted or it has a partitioning scheme so use "diskutil unmountDisk" instead
$ sudo diskutil unmountDisk /dev/diskn (if previous step fails)
Unmount of all volumes on disk2 was successful
$ sudo dd bs=1m if=/Users/sunknudsen/Downloads/2020-12-02-raspios-buster-armhf-lite.img of=/dev/rdiskn
1772+0 records in
1772+0 records out
1858076672 bytes transferred in 40.449002 secs (45936280 bytes/sec)
$ sudo diskutil unmountDisk /dev/diskn
Unmount of all volumes on disk2 was successful
```
### Step 5: log in as pi (using keyboard) and change password using `passwd`
> Heads-up: default password is `raspberry`.
### Step 6: configure Wi-Fi (if not using ethernet)
```shell
sudo raspi-config
```
Select “System Options”, then “Wireless LAN”, choose country, then select “OK”, enter “SSID”, enter passphrase.
### Step 7: enable SSH
```shell
sudo raspi-config
```
Select “Interface Options”, then “SSH”, then “Yes”, then “OK” and finally “Finish”.
When asked if you wish to reboot, select “No”.
### Step 8: find IP of Raspberry Pi (see `eth0` if using ethernet or `wlan0` if using Wi-Fi)
```shell
ip a
```
### Step 9: log in to Raspberry Pi over SSH
Replace `10.0.1.69` with IP of Raspberry Pi.
When asked for password, enter password from [step 5](#step-5-log-in-as-pi-using-keyboard-and-change-password-using-passwd).
```shell
ssh pi@10.0.1.69
```
### Step 10: configure pi SSH authorized keys
#### Create `.ssh` folder
```shell
mkdir -p /home/pi/.ssh
```
#### Create `/home/pi/.ssh/authorized_keys` using heredoc generated at [step 2](#step-2-generate-heredoc-the-output-of-following-command-will-be-used-at-step-10)
```shell
cat << _EOF > /home/pi/.ssh/authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCqEWjWQZY8HoLQEF7SmU/7f8dJuy/4r7/X6PbwrDzASym+5vCLz3QJIlLuJuQL557FsTzsz/sLFoTJnDkiQ3lZtFOofynyYQQiRDkZPy9nGz/j+rTHm6vfp17o8k1LeADKRq2mHpAljlf6/ywkKbzmGhXwnVsvxA0RvvNoujnpiLoSZFrq0wsfzIOi67ZzySlzxKmL0/Uxs9LJ+XFyKlVOILD+TMCayB6UNJ38PkghDZ/8spSSH44jkhmElPdqsqaJ/hqYYXT8q4sSB7Yp5RSYWDYIQiIs2cailho/gOCq/0AskREuGEuwPGL3ivOa2uBN544zrJHbegeliRwTwxSvFat9MoXjpWpEtTVpR5Skr2nGxwXZWYEGZ1u+iJc+Y67k7vabZYADAk1Q8VePAh2BOfhkhZfdAnBZJn9s/XISi/T8WxsLoG3twu1OMWtoiNMlwCUzeIzVRg5BMiFJjEtsANiETdrCuH/Ms9G/EMRo9gKh7moVbfwI+Urf0StIx3k= pi
_EOF
```
### Step 11: log out
```shell
exit
```
### Step 12: log in to Raspberry Pi over SSH (using `pi` private key)
Replace `10.0.1.69` with IP of Raspberry Pi.
When asked for password, enter password from [step 1](#step-1-create-ssh-key-pair-on-computer).
```shell
ssh pi@10.0.1.69 -i ~/.ssh/pi
```
### Step 13: disable pi Bash history
```shell
sed -i -E 's/^HISTSIZE=/#HISTSIZE=/' ~/.bashrc
sed -i -E 's/^HISTFILESIZE=/#HISTFILESIZE=/' ~/.bashrc
echo "HISTFILESIZE=0" >> ~/.bashrc
source ~/.bashrc
```
### Step 14: switch to root
```shell
sudo su -
```
### Step 15: disable root Bash history
```shell
echo "HISTFILESIZE=0" >> ~/.bashrc
source ~/.bashrc
```
### Step 16: set root password
When asked for password, use output from `openssl rand -base64 24` (and store password in password manager).
```shell
passwd
```
### Step 17: uninstall sudo
```shell
apt remove -y sudo
```
### Step 18: disable root login and password authentication
```shell
sed -i -E 's/^(#)?PermitRootLogin (prohibit-password|yes)/PermitRootLogin no/' /etc/ssh/sshd_config
sed -i -E 's/^(#)?PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
systemctl restart ssh
```
### Step 19: disable Bluetooth and Wi-Fi
> Heads-up: will take effect after reboot.
#### Disable Bluetooth
```shell
echo "dtoverlay=disable-bt" | tee -a /boot/config.txt
systemctl disable hciuart
```
#### Disable Wi-Fi (if using ethernet)
```shell
echo "dtoverlay=disable-wifi" | tee -a /boot/config.txt
```
### Step 20: update APT index and upgrade packages
#### Update APT index
```shell
apt update
```
#### Upgrade packages
```shell
apt upgrade -y
```
### Step 21: install and configure Vim
#### Install Vim
```shell
apt install -y vim
```
#### Configure Vim
```shell
cat << "EOF" > ~/.vimrc
set encoding=UTF-8
set termencoding=UTF-8
set nocompatible
set backspace=indent,eol,start
set autoindent
set tabstop=2
set shiftwidth=2
set expandtab
set smarttab
set ruler
set paste
syntax on
EOF
```
### Step 22: set timezone (the following is for Montreal time)
See [https://en.wikipedia.org/wiki/List_of_tz_database_time_zones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) for available timezones.
```shell
timedatectl set-timezone America/Montreal
```
### Step 23: configure sysctl (if server is IPv4-only)
> Heads-up: only run the following if server is IPv4-only.
```shell
cp /etc/sysctl.conf /etc/sysctl.conf.backup
cat << "EOF" >> /etc/sysctl.conf
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
EOF
sysctl -p
```
### Step 24: install iptables-persistent
When asked to save current IPv4 or IPv6 rules, answer `Yes`.
```shell
apt install -y iptables-persistent
```
### Step 25: configure iptables
```shell
iptables -N SSH_BRUTE_FORCE_MITIGATION
iptables -A SSH_BRUTE_FORCE_MITIGATION -m recent --name SSH --set
iptables -A SSH_BRUTE_FORCE_MITIGATION -m recent --name SSH --update --seconds 300 --hitcount 10 -m limit --limit 1/second --limit-burst 100 -j LOG --log-prefix "iptables[ssh-brute-force]: "
iptables -A SSH_BRUTE_FORCE_MITIGATION -m recent --name SSH --update --seconds 300 --hitcount 10 -j DROP
iptables -A SSH_BRUTE_FORCE_MITIGATION -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -p tcp --dport 22 --syn -m conntrack --ctstate NEW -j SSH_BRUTE_FORCE_MITIGATION
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
iptables -A OUTPUT -p tcp --dport 53 -m state --state NEW -j ACCEPT
iptables -A OUTPUT -p udp --dport 53 -m state --state NEW -j ACCEPT
iptables -A OUTPUT -p tcp --dport 80 -m state --state NEW -j ACCEPT
iptables -A OUTPUT -p udp --dport 123 -m state --state NEW -j ACCEPT
iptables -A OUTPUT -p tcp --dport 443 -m state --state NEW -j ACCEPT
iptables -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -P FORWARD DROP
iptables -P INPUT DROP
iptables -P OUTPUT DROP
```
If server is IPv4-only, run:
```shell
ip6tables -P FORWARD DROP
ip6tables -P INPUT DROP
ip6tables -P OUTPUT DROP
```
If server is dual stack (IPv4 + IPv6) run:
```shell
ip6tables -A INPUT -i lo -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type destination-unreachable -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type packet-too-big -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type time-exceeded -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type parameter-problem -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type router-advertisement -m hl --hl-eq 255 -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type neighbor-solicitation -m hl --hl-eq 255 -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type neighbor-advertisement -m hl --hl-eq 255 -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type redirect -m hl --hl-eq 255 -j ACCEPT
ip6tables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
ip6tables -A OUTPUT -o lo -j ACCEPT
ip6tables -A OUTPUT -p ipv6-icmp --icmpv6-type destination-unreachable -j ACCEPT
ip6tables -A OUTPUT -p ipv6-icmp --icmpv6-type packet-too-big -j ACCEPT
ip6tables -A OUTPUT -p ipv6-icmp --icmpv6-type time-exceeded -j ACCEPT
ip6tables -A OUTPUT -p ipv6-icmp --icmpv6-type parameter-problem -j ACCEPT
ip6tables -A OUTPUT -p ipv6-icmp --icmpv6-type router-solicitation -m hl --hl-eq 255 -j ACCEPT
ip6tables -A OUTPUT -p ipv6-icmp --icmpv6-type neighbour-solicitation -m hl --hl-eq 255 -j ACCEPT
ip6tables -A OUTPUT -p ipv6-icmp --icmpv6-type neighbour-advertisement -m hl --hl-eq 255 -j ACCEPT
ip6tables -A OUTPUT -p tcp --dport 53 -m state --state NEW -j ACCEPT
ip6tables -A OUTPUT -p udp --dport 53 -m state --state NEW -j ACCEPT
ip6tables -A OUTPUT -p tcp --dport 80 -m state --state NEW -j ACCEPT
ip6tables -A OUTPUT -p udp --dport 123 -m state --state NEW -j ACCEPT
ip6tables -A OUTPUT -p tcp --dport 443 -m state --state NEW -j ACCEPT
ip6tables -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
ip6tables -P FORWARD DROP
ip6tables -P INPUT DROP
ip6tables -P OUTPUT DROP
```
### Step 26: log out and log in to confirm iptables didnt block SSH
#### Log out
```shell
exit
exit
```
#### Log in
Replace `10.0.1.69` with IP of Raspberry Pi.
When asked for password, enter password from [step 1](#step-1-create-ssh-key-pair-on-computer).
```shell
ssh pi@10.0.1.69 -i ~/.ssh/pi
```
#### Switch to root
When asked, enter root password.
```shell
su -
```
### Step 27: make iptables rules persistent
```shell
iptables-save > /etc/iptables/rules.v4
ip6tables-save > /etc/iptables/rules.v6
```
👍

View File

@ -12,7 +12,7 @@ Listed: true
## Requirements ## Requirements
- [Hardened Debian server](../how-to-configure-hardened-debian-server) 📦 - [Hardened Debian server](../how-to-configure-hardened-debian-server) 📦 or [hardened Raspberry Pi OS server](../how-to-configure-hardened-raspberry-pi-os-server) 📦
- Linux or macOS computer - Linux or macOS computer
## Caveats ## Caveats
@ -113,7 +113,7 @@ EOF
### Step 4: log in to server ### Step 4: log in to server
Replace `185.112.147.115` with IP of server. Replace `server-admin@185.112.147.115` with SSH destination of server and `~/.ssh/server` with path to associated private key.
```shell ```shell
ssh server-admin@185.112.147.115 -i ~/.ssh/server ssh server-admin@185.112.147.115 -i ~/.ssh/server

View File

@ -427,7 +427,7 @@ systemctl restart dnsmasq
### Step 23: install strongSwan ### Step 23: install strongSwan
If you are shown an “Old runlevel management superseded” warning, answer `Ok`. If you are shown an “Old runlevel management superseded” warning, answer “Ok”.
```shell ```shell
apt install -y strongswan libcharon-extra-plugins apt install -y strongswan libcharon-extra-plugins
@ -595,7 +595,7 @@ EOF
cd /etc/strongswan.d/charon cd /etc/strongswan.d/charon
sed -i 's/load = yes/load = no/' ./*.conf sed -i 's/load = yes/load = no/' ./*.conf
sed -i 's/load = no/load = yes/' ./eap-tls.conf ./aes.conf ./dhcp.conf ./farp.conf ./gcm.conf ./hmac.conf ./kernel-netlink.conf ./nonce.conf ./openssl.conf ./pem.conf ./pgp.conf ./pkcs12.conf ./pkcs7.conf ./pkcs8.conf ./pubkey.conf ./random.conf ./revocation.conf ./sha2.conf ./socket-default.conf ./stroke.conf ./x509.conf sed -i 's/load = no/load = yes/' ./eap-tls.conf ./aes.conf ./dhcp.conf ./farp.conf ./gcm.conf ./hmac.conf ./kernel-netlink.conf ./nonce.conf ./openssl.conf ./pem.conf ./pgp.conf ./pkcs12.conf ./pkcs7.conf ./pkcs8.conf ./pubkey.conf ./random.conf ./revocation.conf ./sha2.conf ./socket-default.conf ./stroke.conf ./x509.conf
cd cd -
``` ```
#### Backup and edit `/lib/systemd/system/strongswan.service` #### Backup and edit `/lib/systemd/system/strongswan.service`
@ -624,7 +624,7 @@ cd ~/Desktop/strongswan-certs
Each client is configured using a unique common name ending with `@vpn-server.com`. Each client is configured using a unique common name ending with `@vpn-server.com`.
```shell ```shell
STRONGSWAN_CLIENT_COMMON_NAME=john@vpn-server.com STRONGSWAN_CLIENT_COMMON_NAME=alice@vpn-server.com
``` ```
#### Create OpenSSL config file #### Create OpenSSL config file
@ -696,25 +696,25 @@ Getting CA Private Key
When asked for export password, use output from `openssl rand -base64 24` (and store password in password manager). When asked for export password, use output from `openssl rand -base64 24` (and store password in password manager).
```console ```console
$ openssl genrsa -out john.key 4096 $ openssl genrsa -out alice.key 4096
Generating RSA private key, 4096 bit long modulus Generating RSA private key, 4096 bit long modulus
.........++ .........++
............................................................................++ ............................................................................++
e is 65537 (0x10001) e is 65537 (0x10001)
$ openssl req -new -config openssl.cnf -extensions client -key john.key -subj "/C=US/O=Self-hosted strongSwan VPN/CN=$STRONGSWAN_CLIENT_COMMON_NAME" -out john.csr $ openssl req -new -config openssl.cnf -extensions client -key alice.key -subj "/C=US/O=Self-hosted strongSwan VPN/CN=$STRONGSWAN_CLIENT_COMMON_NAME" -out alice.csr
$ openssl x509 -req -extfile openssl.cnf -extensions client -in john.csr -CA ca.crt -CAkey ca.key -CAcreateserial -days 3650 -out john.crt $ openssl x509 -req -extfile openssl.cnf -extensions client -in alice.csr -CA ca.crt -CAkey ca.key -CAcreateserial -days 3650 -out alice.crt
Signature ok Signature ok
subject=/C=US/O=Self-hosted strongSwan VPN/CN=john@vpn-server.com subject=/C=US/O=Self-hosted strongSwan VPN/CN=alice@vpn-server.com
Getting CA Private Key Getting CA Private Key
$ openssl pkcs12 -in john.crt -inkey john.key -certfile ca.crt -export -out john.p12 $ openssl pkcs12 -in alice.crt -inkey alice.key -certfile ca.crt -export -out alice.p12
Enter Export Password: Enter Export Password:
Verifying - Enter Export Password: Verifying - Enter Export Password:
``` ```
### Step 30: copy/paste the content of `ca.crt`, `server.key` and `server.crt` to server and make private key root-only. ### Step 30: copy/paste content of `ca.crt`, `server.key` and `server.crt` to server and make private key root-only.
On Mac: run `cat ca.crt` On Mac: run `cat ca.crt`
@ -779,7 +779,7 @@ In “General”, enter “Self-hosted strongSwan VPN” in “Name”.
![apple-configurator-general](apple-configurator-general.png?shadow=1) ![apple-configurator-general](apple-configurator-general.png?shadow=1)
In “Certificates”, click “Configure” and select “ca.crt”. Then click “+” and select “john.p12”. The password is the one from [step 29](#step-29-generate-client-cert). In “Certificates”, click “Configure” and select “ca.crt”. Then click “+” and select “alice.p12”. The password is the one from [step 29](#step-29-generate-client-cert).
![apple-configurator-certificates](apple-configurator-certificates.png?shadow=1) ![apple-configurator-certificates](apple-configurator-certificates.png?shadow=1)
@ -789,7 +789,7 @@ The “Child SA Params” are the same as “IKE SA Params”.
![apple-configurator-vpn](apple-configurator-vpn.png?shadow=1) ![apple-configurator-vpn](apple-configurator-vpn.png?shadow=1)
Finally, click “File”, then “Save”, and save file as “john.mobileconfig”. Finally, click “File”, then “Save”, and save file as “alice.mobileconfig”.
### Step 34: add VPN profile to iPhone using Apple Configurator 2 ### Step 34: add VPN profile to iPhone using Apple Configurator 2
@ -797,24 +797,24 @@ Unlock iPhone, connect it to Mac using USB cable and open Apple Configurator 2.
In “All Devices”, double-click on iPhone, then “Add”, and finally “Profiles”. In “All Devices”, double-click on iPhone, then “Add”, and finally “Profiles”.
Select “john.mobileconfig” and follow instructions. Select “alice.mobileconfig” and follow instructions.
On iPhone, open “Settings”, then “Profile Downloaded” and tap “Install”. On iPhone, open “Settings”, then “Profile Downloaded” and tap “Install”.
**If this steps fails (a recent update to Apple Configurator 2 has introduced a bug), please run the following and try again.** **If this steps fails (a recent update to Apple Configurator 2 has introduced a bug), please run the following and try again.**
```shell ```shell
sed -i '' '/<key>DNS<\/key>/,/<\/dict>/d' ~/Desktop/strongswan-certs/john.mobileconfig sed -i '' '/<key>DNS<\/key>/,/<\/dict>/d' ~/Desktop/strongswan-certs/alice.mobileconfig
``` ```
### Step 35: add VPN profile to Mac ### Step 35: add VPN profile to Mac
This step is super simple, simply double-click “john.mobileconfig” and follow instructions. This step is super simple, simply double-click “alice.mobileconfig” and follow instructions.
**If this steps fails (a recent update to Apple Configurator 2 has introduced a bug), please run the following and try again.** **If this steps fails (a recent update to Apple Configurator 2 has introduced a bug), please run the following and try again.**
```shell ```shell
sed -i '' '/<key>DNS<\/key>/,/<\/dict>/d' ~/Desktop/strongswan-certs/john.mobileconfig sed -i '' '/<key>DNS<\/key>/,/<\/dict>/d' ~/Desktop/strongswan-certs/alice.mobileconfig
``` ```
### Step 36: connect to VPN on iPhone or Mac ### Step 36: connect to VPN on iPhone or Mac