CentOS 8とopenSUSE(Raspberry Pi)でIPsecゲートウェイの簡易VPN構築 - 1.StrongSwan導入

# 前提と準備

## Linuxサーバー構築の記事
- [Sambaでファイルサーバー構築(CentOS 8.1・openSUSE 15.1・Ubuntu 20.04)](https://qiita.com/kazumi75kitty/items/4298795029ba9f67b9d2)
- [LinuxでApache2.4＋PHP7.4をソースコンパイル - 1.Apache導入](https://qiita.com/kazumi75kitty/items/daaf8ff8feb50ad04f41) /[【Raspberry Pi】](https://qiita.com/kazumi75kitty/items/67686eccaaec73251458)
- [LinuxでApache2.4＋PHP7.4をソースコンパイル - 2.PHP導入](https://qiita.com/kazumi75kitty/items/fca116b1b387fe56c93c) /[【Raspberry Pi】](https://qiita.com/kazumi75kitty/items/50f1a447f6ebc2ee2b61)
- [LinuxでApache2.4＋PHP7.4をソースコンパイル - 3.MySQL導入](https://qiita.com/kazumi75kitty/items/76807c637c096618a0e1)/[【Raspberry Pi】](https://qiita.com/kazumi75kitty/items/4212dacc45944f27ca94)
- [LinuxでApache2.4＋PHP7.4 - 4.セキュリティ(chownとfirewalld)](https://qiita.com/kazumi75kitty/items/8ad51806ac50bd04b644)
- LinuxでIPsecゲートウェイをVPN構築 - 1.StrongSwan導入【この記事】 /[【Ubuntu 20.04＋Raspberry Pi】](https://qiita.com/kazumi75kitty/items/08259681247a6c2ebd0d)
- [LinuxでIPsecゲートウェイをVPN構築 - 2.VPNへの接続確認](https://qiita.com/kazumi75kitty/items/f5a33abda9f8edd5c47f) /[【Ubuntu 20.04＋Raspberry Pi】](https://qiita.com/kazumi75kitty/items/c83f920f052d83d62457)

個人でもLinuxのコマンドさえこなせば、最低7～8時間で接続やインストールができちゃいます✩°｡⋆⸜(\* ॑꒳ ॑\* )⸝ 1人で作業して1時間2000円かかるものとすると、だいたいかかる作業費用は16000円か…【複数台を同時に作業したほうが効率がよさそうだな…1人2～3台くらいは同時進行できそうな気がする】

IPsecゲートウェイはStrongSwanのソースコンパイルさえできれば、Raspberry Piと中古のノートPCでできるので、ぜひともネットワークを安全なVPN領域にとどめたい場合には、この構築の方法が最適かもしれないので、ぜひやってみました！(˶ ･ᴗ･ )੭⚐⚑

## 環境
- IPsecプログラム：StrongSwan 5.9.0(ソースコンパイル)
- IPsec交渉受信側：Raspberry Pi 3B+ / openSUSE 15.1 Leap(aarm64)
- IPsec交渉発信側：Hyper-V(第2世代)のx64仮想機 / CentOS 8.1(x86_64)
![Raspberry Pi＋openSUSE](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617906/67b0bcb1-e48c-3095-e75b-d2623e613abb.jpeg)

## 前提
- OSは最小限のインストール。また、最新の状態でOSをアップデートしていること
- ユーザーはrootでインストール(私の検証ではadminという管理者アカウントにて、そこからsudoで処理しています)
- どのディストリビューションでも、ファイアウォールはfirewalldを使う(ディストリビューション方言のファイアウォールよりも、firewalldでディストリビューションで共通の操作をしたい)
- CentOSについては、セキュリティはファイルシステム組み込みのSELinuxは煩雑になるため使わず(/etc/selinux/config編集後は再起動も必要)、firewalldを使うこと。

```CentOS8.1
# vi /etc/selinux/config
```

```ini:/etc/selinux/config
SELINUX=disabled
```

```CentOS8.1
# reboot
```

## サーバー条件
### IPアドレスとネットワーク構築図
- IPsec交渉受信側ゲートウェイ(下の図の左、Raspberry Pi)：
 - インターネット側(eth0)：192.168.1.22
 - VPN領域側(eth1)：192.168.2.1

- IPsec交渉発信側ゲートウェイ(下の図の右、CentOS 8.1)：
 - インターネット側(eth0)：192.168.1.18
 - VPN領域側(eth1)：192.168.5.1

- ネットワークセグメント：
 - インターネット接続可能：192.168.1.0/24
 - Raspberry Pi(図の左の交渉受信側)セキュアセグメント：192.168.2.0/24
 - CentOS 8(図の右の交渉発信側)セキュアセグメント：192.168.5.0/24

- IPsec領域関連：
 - トンネリング区間：192.168.1.22 ～ 192.168.1.18間
 - VPN連携：192.168.2.0/24 ～ 192.168.5.0/24をVPN接続
![sswan00_IPsecGW図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617906/c71f67d0-b486-00c0-4653-cd952ad3a3a9.png)

### パッケージを個別ダウンロードしてインストールする機能とバージョン(2020年9月時点)
- zlib-1.2.11.tar.gz
- strongswan-5.9.0.tar.gz

それ以外の必要なパッケージは、ディストリビューションの標準パッケージコマンド(dnfやaptなど)でインストールし、個別ダウンロードは不要です。

ダウンロードについては、公式サイトにアクセスして、そこからダウンロードしてFTPで転送するか、ダウンロードファイルのURLさえわかれば、wgetで入手することもできますが、入手方法は省略しています。

# 作業手順
## 準備
### makeやcmake、パッケージ解凍機能のインストール
Hyper-V仮想マシンとラズパイでディストリビューションごとのインストールをします(ソースコンパイルは両方とも同じ)

```CentOS8.1(Hyper-V/x64)
# dnf -y install make cmake tar bzip2
```

```openSUSE15.1(RaspberryPi)
# zypper -n install make cmake tar bzip2
```

### GCCとC++コンパイラのインストール

```CentOS8.1(Hyper-V/x64)
# dnf -y install gcc gcc-c++
```

```openSUSE15.1(RaspberryPi)
# zypper -n install gcc gcc-c++
```

### zlibのソースインストール
zlibの配置場所はデフォルトのまま変えないでインストールしました。ソースコンパイルはHyper-V仮想マシンとラズパイで同じです

```
# cd [zlibの書庫ファイルが置いてあるディレクトリ]
# tar zxvf zlib-1.2.11.tar.gz
# cd zlib-1.2.11/
# ./configure
# make
# make install
```

### IP転送の有効化
IPsecゲートウェイとして動作するためには、IP転送を有効化しなければならないので、有効化します。Hyper-V仮想マシンのCentOS 8.1では以下のコマンドを実行することで転送を有効化します。ラズパイのopenSUSEはYaSTで設定することができます。

```CentOS8.1(Hyper-V/x64)
# cat /proc/sys/net/ipv4/ip_forward
0
# vi /etc/sysctl.d/01-ipv4fwd.conf
```

```conf:/etc/sysctl.d/01-ipv4fwd.conf(CentOS)
# Controls IP packet forwarding
net.ipv4.ip_forward = 1
```

```openSUSE15.1(RaspberryPi)
# yast
[あとはYaSTの設定に従ってネットワークやセキュリティの設定から、IPv4の転送を有効化する]
```

### VPN領域のネットワークアダプタの増設
Hyper-V仮想マシンとRaspberry Piともに、IP転送の有効化＋ネットワークアダプタを増設するため、**いったん電源を切ります**。私の場合は、ラズパイはUSBでVPN向けの有線LANアダプタを増設し、Hyper-Vは設定で、ネットワークアダプタを増設しました。

増設後は「eth1」が追加されているか確認しますが、もちろんIPアドレスはまだ割り振られていません。

```
# ip addr

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether [最初からあるネットワークアダプタのMACアドレス] brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.18/24 brd 192.168.1.255 scope global noprefixroute eth0
       valid_lft forever preferred_lft forever
    inet6 [最初からあるネットワークアダプタのIPv6アドレス] scope global dynamic noprefixroute
       valid_lft 14373sec preferred_lft 12573sec
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether [増設ネットワークアダプタのMACアドレス] brd ff:ff:ff:ff:ff:ff
    inet6 [増設ネットワークアダプタのIPv6アドレス] scope link noprefixroute
       valid_lft forever preferred_lft forever

# ip route

default via 192.168.1.1 dev eth0 proto static metric 100
192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.18 metric 100
```

CentOSの場合は、コマンドでIP転送の有効化を操作しているので、有効(ip_forwardが1)になっているか確認をします。

```CentOS8.1(Hyper-V/x64)
# cat /proc/sys/net/ipv4/ip_forward
1

# sysctl --system
…(中略)
* Applying /etc/sysctl.d/01-ipv4fwd.conf ...
net.ipv4.ip_forward = 1
…(中略)
```

### StrongSwanをコンパイルするために必要なパッケージをディストリビューション標準パッケージコマンドでインストール
注意：面倒くさくても実行しないと、パッケージがない、とエラーが出てコンパイルが中止されるんです(´•ω•̥`)

```CentOS8.1(Hyper-V/x64)
# dnf -y install gmp-devel openssl-devel
```

```openSUSE15.1(RaspberryPi)
# zypper -n install gmp-devel libopenssl-devel
```

## StrongSwan 5.9.0のソースコンパイルのインストール
Hyper-V仮想機とラズパイ共通です。この作業は結構時間がかかりました(特にRaspberry Piだと、20～30分かかりました)

### configureとmake

```
# cd [strongswan-5.9.0.tar.gzが置いてあるディレクトリ]
# tar xvzf strongswan-5.9.0.tar.gz
# cd strongswan-5.9.0/
# ./configure --prefix=/usr --sysconfdir=/etc --enable-openssl
# make
# make install
```

エラーなくコンパイルできれば、インストールは完了です♪(\*˘︶˘\*).｡.:\*♡

### StrongSwanの環境設定
ソースコンパイルでStrongSwanをインストールすると、設定ファイルは/etc/ipsec.confに格納されるので、その中にIPsecの接続設定を行います。

```
[Apacheの基本設定]
# vi /etc/ipsec.conf
```

IPsecを確立する側(確立を発信する方)、そう、まずはHyper-VのCentOS 8.1の設定を行います。「サーバー条件」の項にある通り、Hyper-Vマシン側からは、自分のIPアドレスが192.168.1.18、確立相手のRaspberry Piが192.168.1.22になるので、その対を設定ファイルに書き込みます。

「left」は確立を交渉発信する自分を、「right」は確立相手の情報を書き込むとのことです([StrongSwan公式のマニュアルから](https://wiki.strongswan.org/projects/strongswan/wiki/ConnSection))

```conf:CentOS8.1(Hyper-V/x64)
…
# 以下を追記する
conn [識別名 例：linux-2-linux]
      authby=secret
      auto=start				# IPsec交渉を発信する
      closeaction=restart
      dpdaction=restart
      left=192.168.1.18			# leftは自分側のIPsecゲートウェイ
      leftid=192.168.1.18		# IPsec交渉するのに自分を識別するID
      leftsubnet=192.168.5.0/24
      right=192.168.1.22		# rightは相手側のIPsecゲートウェイ
      rightid=192.168.1.22		# IPsec交渉相手を識別するID
      rightsubnet=192.168.2.0/24
…
```
ちなみにIDは、私の場合は簡単のためIPアドレスを使用しましたが、文字列でもOKです。そんでleftsubnetとrightsubnetというのは、自分側と相手側の受け持つVPN領域なので、leftsubnetは自分の持っているVPN領域なので192.168.5.0/24を、rightsubnetは相手のラズパイのVPN領域なので192.168.2.0/24を入れました。

続いて、ラズパイのopenSUSEの設定も行います。「サーバー条件」の項にある通り、確立を受ける自分のIPアドレスが192.168.1.22、確立してくる相手側のHyper-V CentOS 8が192.168.1.18になるので、Hyper-V(CentOS8)とは逆の内容を設定ファイルに書き込みます。

```conf:openSUSE15.1(RaspberryPi)
# 以下を追記する
conn [識別名 例：linux-2-linux]
      authby=secret
      auto=add				# IPsec交渉を受信する
      closeaction=clear
      dpdaction=clear
      left=192.168.1.22
      leftid=192.168.1.22
      leftsubnet=192.168.2.0/24
      right=192.168.1.18
      rightid=192.168.1.18
      rightsubnet=192.168.5.0/24
```

要は、auto=addとすることで、IPsec確立交渉を受信する側に設定し、leftの内容とrightの内容を真逆にするというところだね。そうすれば、識別名(connの後ろの文字列)が一致すれば、IPsecの接続を確立できる、ということ

StrongSwanのデフォルトでは、PSK方式で、標準でAES/SHA暗号方式を採用しています。それ以外の暗号方式を設定する必要がある場合はまた別途設定するが、ここでは省略。

余談ですが、この時点でのStrongSwanはNAT-Tに対応していて、IPsecをNATに適用させることもできる(かつてはIPsecをNATに適用することができなかった)ので、インターネットでNATが使われている空間でさえも、StrongSwanで構築されたVPNをインターネット越しに通信できるそうです(実験したことはありませんが…)

```
[StrongSwanの鍵の設定]
# vi /etc/ipsec.secrets
```

```conf:/etc/ipsec.secrets
…
: PSK "[適当な文字列：例…kazumi75kitty]"
…
```
デフォルトのPSK方式を使っているので、Hyper-V仮想マシンとラズパイともに同じにします。


## StrongSwanの起動
### サービスの起動スクリプト作成＆有効化
StrongSwanに必要な環境設定がそろったので、起動できるようにしたいと思います。起動スクリプトはSystemdなので、/etc/systemd/systemに作成します

```
# cd /etc/systemd/system
# vi strongswan.service
```

```ini:strongswan.service
[Unit]
Description=strongSwan

[Service]
Type=forking
ExecStart=/usr/sbin/ipsec start
ExecStop=/usr/sbin/ipsec stop

[Install]
WantedBy=multi-user.target
```

ここではSystemdのスクリプトは詳しく説明しませんが、起動と停止は親プロセスからはバックグランドで実行されるため、strongSwanでは[Service]のTypeはforkingとなっています。

### firewalldの設定
続いて、firewalldの設定で、IPsecを受け付けます(IPsecでやりとりされる暗号化データそのものと、IPsecの交渉が受け付けることができる)。ただしここでの設定だと、トンネリングをかます192.168.1.0/24内部限定を明記していなく、ほかのネットワークセグメントからもIPsecのパケットが通行可能であれば受信できてしまいます。しかしここまで対策すると煩雑になるので今回は簡単のためIPsecの許可のみとします。

```
# firewall-cmd --permanent --add-service=ipsec
# firewall-cmd --reload

# firewall-cmd --list-all

public (active)
  target: default
  icmp-block-inversion: no
  interfaces: eth0
  sources:
  services: cockpit dhcpv6-client ipsec
  ports:
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:
        rule family="ipv4" source address="192.168.1.0/24" port port="12345" protocol="tcp" accept

```

Hyper-V仮想マシンとラズパイの両方で共通のコマンドです。

### 起動と動作確認
それでは、起動します。enableでの常時起動有効化＆statusで「Active」「Running」になっていることを確認。

**まずはIPsec確立交渉を受信する側からStrongSwanを起動したのちに、IPsec確立を発信する側の順に起動させています**。ここではラズパイのStrongSwanを起動後に、Hyper-V仮想マシンのStrongSwanを起動させています。

```
# systemctl start strongswan
# systemctl enable strongswan
# systemctl status strongswan
```
![起動成功](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617906/1ef9b980-8ef9-95ab-6aaa-d8f966338f23.png)

Hyper-V仮想マシンとラズパイで「Active」「Running」になっていることを確認し、いよいよIPsecトンネリングが確立されているかをチェック。

```CentOS8.1(Hyper-V/x64)
# /usr/sbin/ipsec status
Security Associations (1 up, 0 connecting):
linux-2-linux[1]: ESTABLISHED 2 minutes ago, 192.168.1.18[192.168.1.18]...192.168.1.22[192.168.1.22]
linux-2-linux{1}:  INSTALLED, TUNNEL, reqid 1, ESP SPIs: ********_i ********_o
linux-2-linux{1}:   192.168.5.0/24 === 192.168.2.0/24

# ip xfrm policy
src 192.168.5.0/24 dst 192.168.2.0/24
        dir out priority 375423 ptype main
        tmpl src 192.168.1.18 dst 192.168.1.22
                proto esp spi 0x******** reqid 1 mode tunnel
src 192.168.2.0/24 dst 192.168.5.0/24
        dir fwd priority 375423 ptype main
        tmpl src 192.168.1.22 dst 192.168.1.18
                proto esp reqid 1 mode tunnel
src 192.168.2.0/24 dst 192.168.5.0/24
        dir in priority 375423 ptype main
        tmpl src 192.168.1.22 dst 192.168.1.18
                proto esp reqid 1 mode tunnel
```

```openSUSE15.1(RaspberryPi)
# /usr/sbin/ipsec status
Security Associations (1 up, 0 connecting):
linux-2-linux[1]: ESTABLISHED 2 minutes ago, 192.168.1.22[192.168.1.22]...192.168.1.18[192.168.1.18]
linux-2-linux{1}:  INSTALLED, TUNNEL, reqid 1, ESP SPIs: ********_i ********_o
linux-2-linux{1}:   192.168.2.0/24 === 192.168.5.0/24

# ip xfrm policy
src 192.168.2.0/24 dst 192.168.5.0/24
        dir out priority 375423 ptype main
        tmpl src 192.168.1.22 dst 192.168.1.18
                proto esp spi 0x******** reqid 1 mode tunnel
src 192.168.5.0/24 dst 192.168.2.0/24
        dir fwd priority 375423 ptype main
        tmpl src 192.168.1.18 dst 192.168.1.22
                proto esp reqid 1 mode tunnel
src 192.168.5.0/24 dst 192.168.2.0/24
        dir in priority 375423 ptype main
        tmpl src 192.168.1.18 dst 192.168.1.22
                proto esp reqid 1 mode tunnel
```

IPsecトンネリングが、Hyper-V仮想マシンとラズパイでちゃんと確立されてました(˶ ･ᴗ･ )੭⚐⚑

## おまけ(ipsec.confのIDにドメインなど文字列を指定)
StrongSwanの設定ファイル/etc/ipsec.confで、leftidやrightidで、IPアドレスではなく文字列を使った場合もキャプチャ画面を載せておきます(\*´꒳`\*)

たぶんこっちのほうがわかりやすいかもしれません。
例では「raspberrypi」と「testonly@kazumi-jam」を識別させています
![ipsec.confのIDに文字列やドメインを指定する](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617906/1c2c198b-cde6-3e2a-7c8a-051e036f5d48.png)

## 補足(IPsecトンネリングがNATを経由する場合)

わかりやすい画像はまだないけど、ipsec.confでのleftとrightのIPアドレスは、それぞれ自分自身のIPアドレスと、自分から見たNAT変換後の相手のIPアドレスを入れます。その際、leftidとrightidは、必ず自分と相手で対に一致していることが必要になります。

例：
192.168.1.0/24 → 192.168.120.0/28 がNATで仕切られている場合

IPsecGW-1(192.168.1.0/24内)
　left=192.168.1.22
　leftid="gw1"
　right=192.168.1.18
　rightid="gw2"
IPsecGW-2(192.168.120.0/28内)
　left=**192.168.120.1**
　leftid="gw2"
　right=**192.168.120.3**
　rightid="gw1"

という風に、IPアドレスはNATを考慮したものを入れることでIPsecが確立できるけど、詳しくはまた後で載せてみます。

# 次回
一通りのStrongSwan導入で、Raspberry PiとHyper-V上のCentOS 8.1で、IPsecゲートウェイの構築が完了しました。次はそのIPsecゲートウェイにつながったVPNにクライアントとサーバーを接続して、互いに接続できるかを試します( ˶˙ᵕ˙˶ )