カテゴリー別アーカイブ: 暗号化

暗号化に関すること

HTTP/2 (ALPN) 対応の nginx を SRPM からビルド

※以下はCentOS 7.3までの古い内容です。7.4 では OpenSSL 1.0.2 が標準となりました。

CentOS7.3 に含まれる標準パッケージの OpenSSL が 1.0.1 系なので、それをリンクしてビルドした nginx 公式のバイナリでは HTTP/2 (ALPN) が利用できない。そこで、openssl-1.0.2 系のソースツリーを使って nginx 公式の SRPM をリビルドすることとする。

ついでに、geoipモジュールとdav_extモジュールも使いたいので、追加した上でビルドする。

1. コンパイルに必要なパッケージをインストール

$ sudo yum install expat-devel pcre-devel zlib-devel GeoIP-devel

2. nginxの公式レポジトリを追加

レポジトリファイルを作成する。
$ sudo vi /etc/yum.repos.d/nginx.repo

[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=0
enabled=1

[nginx-source]
name=nginx repo - Source
baseurl=http://nginx.org/packages/centos/$releasever/SRPMS/
gpgcheck=0
enabled=1

3. ダウンロード

SRPMをダウンロード・インストールする。
$ sudo yum install -y yum-utils
$ yumdownloader --source nginx
$ rpm -ivh --nosignature nginx-1.12.1-1.el7.ngx.src.rpm

今後yum updateで勝手にアップデートされないように、nginxレポジトリを無効化しておく。
$ sudo yum-config-manager --disable nginx
$ sudo yum-config-manager --disable nginx-source

OpenSSL 1.0.2 のソースをダウンロードして展開する。
$ cd /tmp
$ wget https://www.openssl.org/source/openssl-1.0.2l.tar.gz
$ tar xzf openssl-1.0.2l.tar.gz
$ cd ~

OpenSSL のビルドはしなくてよい。

4. カスタマイズ

SRPM の spec ファイルを編集する。
$ vi rpmbuild/SPECS/nginx.spec

青字の部分は追加、赤字で打消し線のところは削除する。

#
%define nginx_home %{_localstatedir}/cache/nginx
%define nginx_user nginx
%define nginx_group nginx
%define nginx_loggroup adm

# distribution specific definitions
%define use_systemd (0%{?fedora} && 0%{?fedora} >= 18) || (0%{?rhel} && 0%{?rhel
} >= 7) || (0%{?suse_version} == 1315)

%if 0%{?rhel} == 5
%define _group System Environment/Daemons
Requires(pre): shadow-utils
Requires: initscripts >= 8.36
Requires(post): chkconfig
Requires: openssl
BuildRequires: openssl-devel
%endif

%if 0%{?rhel} == 6
%define _group System Environment/Daemons
Requires(pre): shadow-utils
Requires: initscripts >= 8.36
Requires(post): chkconfig
Requires: openssl >= 1.0.1
BuildRequires: openssl-devel >= 1.0.1
%endif

%if 0%{?rhel} == 7
%define _group System Environment/Daemons
%define epoch 1
Epoch: %{epoch}
Requires(pre): shadow-utils
Requires: systemd
Requires: openssl >= 1.0.1
BuildRequires: systemd
BuildRequires: openssl-devel >= 1.0.1
BuildRequires: GeoIP-devel
BuildRequires: expat-devel
%endif

%if 0%{?suse_version} == 1315
%define _group Productivity/Networking/Web/Servers
%define nginx_loggroup trusted
Requires(pre): shadow
Requires: systemd
BuildRequires: libopenssl-devel
BuildRequires: systemd
%endif

# end of distribution specific definitions

%define main_version 1.12.1
%define main_release 1%{?dist}.ngx

%define bdir %{_builddir}/%{name}-%{main_version}

%define WITH_CC_OPT $(echo %{optflags} $(pcre-config --cflags)) -fPIC
%define WITH_LD_OPT -Wl,-z,relro -Wl,-z,now -pie
%define BASE_CONFIGURE_ARGS $(echo "--prefix=%{_sysconfdir}/nginx --sbin-path=%{
_sbindir}/nginx --modules-path=%{_libdir}/nginx/modules --conf-path=%{_sysconfdi
r}/nginx/nginx.conf --error-log-path=%{_localstatedir}/log/nginx/error.log --htt
p-log-path=%{_localstatedir}/log/nginx/access.log --pid-path=%{_localstatedir}/r
un/nginx.pid --lock-path=%{_localstatedir}/run/nginx.lock --http-client-body-tem
p-path=%{_localstatedir}/cache/nginx/client_temp --http-proxy-temp-path=%{_local
statedir}/cache/nginx/proxy_temp --http-fastcgi-temp-path=%{_localstatedir}/cach
e/nginx/fastcgi_temp --http-uwsgi-temp-path=%{_localstatedir}/cache/nginx/uwsgi_
temp --http-scgi-temp-path=%{_localstatedir}/cache/nginx/scgi_temp --user=%{ngin
x_user} --group=%{nginx_group} --with-compat --with-file-aio --with-threads --wi
th-http_addition_module --with-http_auth_request_module --with-http_dav_module -
-with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module -
-with-http_mp4_module --with-http_random_index_module --with-http_realip_module 
--with-http_secure_link_module --with-http_slice_module --with-http_ssl_module -
-with-http_stub_status_module --with-http_sub_module --with-http_v2_module --wit
h-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-s
tream_ssl_module --with-stream_ssl_preread_module --with-http_geoip_module --add
-module=./nginx-dav-ext-module --with-openssl=/tmp/openssl-1.0.2l")

Summary: High performance web server
Name: nginx
Version: %{main_version}
Release: %{main_release}
Vendor: Nginx, Inc.
URL: http://nginx.org/
Group: %{_group}

Source0: http://nginx.org/download/%{name}-%{version}.tar.gz
Source1: logrotate
Source2: nginx.init.in
Source3: nginx.sysconf
Source4: nginx.conf
Source5: nginx.vh.default.conf
Source7: nginx-debug.sysconf
Source8: nginx.service
Source9: nginx.upgrade.sh
Source10: nginx.suse.logrotate
Source11: nginx-debug.service
Source12: COPYRIGHT
Source13: nginx.check-reload.sh

License: 2-clause BSD-like license

BuildRoot: %{_tmppath}/%{name}-%{main_version}-%{main_release}-root
BuildRequires: zlib-devel
BuildRequires: pcre-devel

Provides: webserver

%description
nginx [engine x] is an HTTP and reverse proxy server, as well as
a mail proxy server.

%if 0%{?suse_version} == 1315
%debug_package
%endif

%prep
%setup -q
cp %{SOURCE2} .
sed -e 's|%%DEFAULTSTART%%|2 3 4 5|g' -e 's|%%DEFAULTSTOP%%|0 1 6|g' \
    -e 's|%%PROVIDES%%|nginx|g' < %{SOURCE2} > nginx.init
sed -e 's|%%DEFAULTSTART%%||g' -e 's|%%DEFAULTSTOP%%|0 1 2 3 4 5 6|g' \
    -e 's|%%PROVIDES%%|nginx-debug|g' < %{SOURCE2} > nginx-debug.init
git clone https://github.com/arut/nginx-dav-ext-module.git

%build
./configure %{BASE_CONFIGURE_ARGS} \
    --with-cc-opt="%{WITH_CC_OPT}" \
    --with-ld-opt="%{WITH_LD_OPT}" \
    --with-debug --with-openssl-opt="-fPIC"
make %{?_smp_mflags}
%{__mv} %{bdir}/objs/nginx \
    %{bdir}/objs/nginx-debug
./configure %{BASE_CONFIGURE_ARGS} \
    --with-cc-opt="%{WITH_CC_OPT}" \
    --with-ld-opt="%{WITH_LD_OPT}" --with-openssl-opt="-fPIC"
make %{?_smp_mflags}

(以下略)

5. ビルド、インストール

ビルドを実行する。
$ rpmbuild -ba rpmbuild/SPECS/nginx.spec

出来上がったら、RPMをインストールする。
$ sudo yum localinstall rpmbuild/RPMS/x86_64/nginx-1.12.1-1.el7.centos.ngx.x86_64.rpm

展開した openssl ソースを掃除しておく。
$ rm -r /tmp/openssl-1.0.2l

6. 起動

デーモンを起動する。
$ sudo systemctl enable nginx
$ sudo systemctl start nginx

参考URL:
HTTP/2対応nginxのrpmパッケージ作成とインストール

~/.ssh/known_hosts の記述

どうでもいい小ネタ。

多数のサーバで同一のsshホスト鍵を使う場合、クライアントの known_hosts ファイルには同一ホスト公開鍵が大量に残ることになる。
まあ気にしなければ良いのだが、ワイルドカードが書けるので集約することもできる。

server1.domain.local ssh-rsa ホスト公開鍵文字列
server2.domain.local ssh-rsa ホスト公開鍵文字列
server3.domain.local ssh-rsa ホスト公開鍵文字列
192.168.100.1 ssh-rsa ホスト公開鍵文字列
192.168.100.2 ssh-rsa ホスト公開鍵文字列
192.168.100.3 ssh-rsa ホスト公開鍵文字列

上記を、以下のようにまとめられる。
*.domain.local ssh-rsa ホスト公開鍵文字列
192.168.100.* ssh-rsa ホスト公開鍵文字列

これをやっておくと、新しいサーバが増えた時に改めて
Are you sure you want to continue connecting (yes/no)?
みたいなことを聞かれなくて済む。

外部からVPSへのL2TP/IPsecとVPS-自宅間IPsecの組み合わせ

前回記事のリモートアクセスVPN (L2TP/IPsec) と、さらにその前の記事で構築済みのVPS-自宅間VPN (IPsec) を組み合わせて利用する。

これにより、動的IPアドレスの自宅へ、外部からいつでもログイン可能となる。

前提:
・サーバはすべて Ubuntu 14.04 LTS である。
・IPsec実装は strongswan を利用し、サーバ間はRSA証明書認証を行う。
・外部端末-VPS間はL2TP/IPsecとし、認証はIPsec事前共有鍵+L2TPのMSCHAPv2とする。

ネットワーク構成は以下の通り。
06

すでに記事としては前回前々回で記述している。
今回のポイントは、VPS への L2TP アクセスで割り振られる PPP IPアドレスを、VPS-自宅間IPsecのトンネルに入るよう設定することである。

1. myvps1 と myserver1 の /etc/sysctl.conf

$ sudo vi /etc/sysctl.conf

net.ipv4.ip_forward=1  #28行目のコメントを外す
# 以下、追記する
net.ipv4.conf.default.send_redirects=0
net.ipv4.conf.all.send_redirects=0
net.ipv4.conf.eth0.accept_redirects=0
net.ipv4.conf.eth0.send_redirects=0
net.ipv4.conf.lo.accept_redirects=0
net.ipv4.conf.lo.send_redirects=0
net.ipv6.conf.eth0.accept_redirects=0
net.ipv6.conf.lo.accept_redirects=0
vpn1:~$ sudo sysctl -p /etc/sysctl.conf

2. myserver1上にCAを作成し、myserver1用とmyvps1用の証明書・秘密鍵の組を作成する

前々回記事を参照。

myserver1 には
/etc/ipsec.d/cacerts/ca1.crt (CA証明書)
/etc/ipsec.d/certs/myserver1.crt (サーバ証明書)
/etc/ipsec.d/private/myserver1.key (サーバ秘密鍵)

myvps1 には
/etc/ipsec.d/cacerts/ca1.crt (CA証明書)
/etc/ipsec.d/certs/myvps1.crt (サーバ証明書)
/etc/ipsec.d/private/myvps1.key (サーバ秘密鍵)

以上のファイルを配置する。

3. strongswan の設定 (myserver1側)

/etc/ipsec.conf:

config setup セクションの後に以下の内容を追加する。rightsubnet に L2TP クライアントの IP アドレス領域を追加しておく。

conn myhome-to-vps
	authby=rsasig
	auto=start
	closeaction=restart
	dpdaction=restart
	left=192.168.100.240
	leftsubnet=192.168.100.0/24
	leftcert=myserver1.crt
	right=203.0.113.180
	rightsubnet=203.0.113.180/32,172.16.1.0/24 # ←L2TPのクライアントアドレスを追加
	rightid="C=JP, ST=Aichi, O=Home, OU=Server, CN=myvps1.vpsnet.example.jp"

※strongswan だと leftsubnet / rightsubnet に複数のサブネットが記述できるが、openswan で複数サブネットの場合は leftsubnets / rightsubnets と書く必要がある。

/etc/ipsec.secrets:

: RSA myserver1.key

4. strongswan の設定 (myvps1側)

/etc/ipsec.conf:

config setup セクションの後に、以下の2つの記述を追加する。
myhome-to-vps の方の leftsubnet には、L2TP クライアントアドレス領域を追加しておく。

conn myhome-to-vps
	authby=rsasig
	auto=add
	closeaction=clear
	dpdaction=clear
	left=203.0.113.180
	leftsubnet=203.0.113.180/32,172.16.1.0/24 # ←L2TPのクライアントアドレスを追加
	leftcert=myvps1.crt
	right=%any
	rightsubnet=192.168.100.0/24
	rightid="C=JP, ST=Aichi, O=Home, OU=Server, CN=myserver1.domain.local"

conn L2TP-PSK
        authby=secret
        auto=add
        closeaction=clear
        dpdaction=clear
        type=transport
        rekey=no
        left=203.0.113.180
        leftprotoport=17/1701
        right=%any
        rightprotoport=17/%any

/etc/ipsec.secrets:
自宅IPsec用のRSA秘密鍵と、L2TP/IPsec用の事前共有鍵文字列を両方記述する。

: RSA myvps1.key
: PSK "mypresharedkey"

5. xl2tpd の設定 (myvps1側)

/etc/xl2tpd/xl2tpd.conf:

[global]
port = 1701

[lns default]
ip range = 172.16.1.11-172.16.1.30
local ip = 172.16.1.254
length bit = yes
require chap = yes
refuse pap = yes
require authentication = yes
name = myvps1.vpsnet.example.jp
ppp debug = no
pppoptfile = /etc/ppp/xl2tpd-options

/etc/ppp/xl2tpd-options:

ipcp-accept-local
ipcp-accept-remote
ms-dns 172.16.1.254  (myvps1にキャッシュDNSサーバが立っている前提)
noccp
auth
crtscts
idle 1800
mtu 1300
mru 1300
nodefaultroute
lock
connect-delay 5000
refuse-pap
refuse-chap
refuse-mschap
require-mschap-v2

/etc/ppp/chap-secrets:

username	*	"l2tppassworddesu"	*

一般ユーザで読めない権限にしておくこと。

6. サービス起動と確認

myserver1:~$ sudo service strongswan restart
myvps1:~$ sudo service strongswan restart
myvps1:~$ sudo service xl2tpd restart

iOS/Android 端末からの L2TP/IPsec 接続 (strongswan+xl2tpd)

iOSやAndroid端末、あるいは Windows PC などからもリモートアクセスできるよう、VPS マシンに VPN 接続を設定しておく。

PPTPについては既に脆弱性が発見されており、OSによってはサポート対象外になっているため、VPN プロトコルとしては L2TP/IPsec を使う。

前提:
対象サーバはVPSのUbuntu 14.04。

IPsec 実装としては strongswan、L2TP 実装としては xl2tpd を利用する。

ネットワーク図は以下の通り。
05

1. インストール

myvps1:~$ sudo apt-get install strongswan xl2tpd

カーネルパラメータをパケット転送できるよう設定する。

myvps1:~$ sudo vi /etc/sysctl.conf
net.ipv4.ip_forward=1  #28行目のコメントを外す
# 以下、追記する
net.ipv4.conf.default.send_redirects=0
net.ipv4.conf.all.send_redirects=0
net.ipv4.conf.eth0.accept_redirects=0
net.ipv4.conf.eth0.send_redirects=0
net.ipv4.conf.lo.accept_redirects=0
net.ipv4.conf.lo.send_redirects=0
net.ipv6.conf.eth0.accept_redirects=0
net.ipv6.conf.lo.accept_redirects=0
myvps1:~$ sudo sysctl -p /etc/sysctl.conf

ファイアウォール(ufw)を閉じている場合は、ESP、UDP 500・4500 を空けておくこと。

2. ipsec.confの設定

myvps1:~$ sudo vi /etc/ipsec.conf

以下の内容を追記する。

conn L2TP-PSK
        authby=secret
        auto=add
        closeaction=clear
        dpdaction=clear
        type=transport
        rekey=no
        left=203.0.113.180
        leftprotoport=17/1701
        right=%any
        rightprotoport=17/%any

IPsec はトランスポートモードを使用する。ペイロードに L2TP を通すので、ルーティングはそちらに任せる。

再接続等はクライアント側に任せたいため、こちらからは何もしない設定である。接続が切れた場合はセッションをクリアする。

3. IPsecの事前共有鍵の設定

myvps1:~$ sudo vi /etc/ipsec.secrets

事前共有鍵を平文で記述する。

: PSK "mypresharedkey"

4. xl2tpd.conf の設定

myvps1:~$ sudo vi /etc/xl2tpd/xl2tpd.conf

以下の設定を追記する。

[global]
port = 1701

[lns default]
ip range = 172.16.1.11-172.16.1.30
local ip = 172.16.1.254
length bit = yes
require chap = yes
refuse pap = yes
require authentication = yes
name = myvps1.vpsnet.example.jp
ppp debug = no
pppoptfile = /etc/ppp/xl2tpd-options

接続クライアント側には、172.16.1.11 から 30 の間でアドレスが割り振られる。

5. xl2tpd-options の設定

myvps1:~$ sudo vi /etc/ppp/xl2tpd-options

L2TPの設定を記述する。

ipcp-accept-local
ipcp-accept-remote
ms-dns 172.16.1.254  (myvps1:172.16.1.254にキャッシュDNSサーバが立っている前提)
noccp
auth
crtscts
idle 1800
mtu 1300
mru 1300
nodefaultroute
lock
connect-delay 5000
refuse-pap
refuse-chap
refuse-mschap
require-mschap-v2

6. chap-secrets の設定

myvps1:~$ sudo vi /etc/ppp/chap-secrets
username	*	"l2tppassworddesu"	*

一般ユーザで読めない権限にしておく。

7. デーモンの起動

myvps1:~$ sudo service strongswan restart
myvps1:~$ sudo service xl2tpd restart

この状態で、iPhoneなどから接続してみる。
iPhoneであれば「設定」→「VPN」→「VPN構成を追加…」で「L2TP」を選択して設定を追加する。
サーバ欄にはVPSのホスト名(IPアドレス)、アカウントにはL2TPユーザ名、パスワードにはL2TPパスワード、シークレットにはIPsec事前共有鍵を設定する。

クライアント機器が、公衆無線LANなどのプライベートネットワーク中に居る状態も想定しなければならない。その場合は NAT-Traversal を使うことになるが、Ubuntu 14.04 の strongswan は標準でNAT-Traversal を自動検出してくれるようなので、特別な設定をしなくても接続できる (ただし、UDP 4500番ポートについてファイアウォールが空いている必要はある)。

自宅-VPS間でIPsec (strongswan X.509証明書認証)

IPsecトンネルの認証に証明書認証を導入する検証を実施してみたが、Ubuntu 14.04 標準パッケージの openswan では trusted_ca returning with failed というエラーが出てうまくいかなかった。

strongswan で試したところ成功したので、この設定を以下に説明する。(strongswanとopenswanの比較はこちら)

ネットワーク構成は前の記事と同じで、以下の図のようになる。
03

前提:
・両側のサーバはともに Ubuntu 14.04 LTS である。
・IPsec実装は strongswanを利用する。
・証明書作成にはOpenSSLを使い、PEMファイルの形で管理する。
・CAは自宅側のIPsec端点(ホスト名:myserver1)と同一のサーバに作成しておき、この上で両側の端点用の証明書を発行する。

1. strongswan インストール

myserver1:~$ sudo apt-get purge openswan
myserver1:~$ sudo apt-get install strongswan
myvps1:~$ sudo apt-get purge openswan
myvps1:~$ sudo apt-get install strongswan

カーネルパラメータは前々回の記事と同一の設定をしておく。

vpn1:~$ sudo vi /etc/sysctl.conf
net.ipv4.ip_forward=1  #28行目のコメントを外す
# 以下、追記する
net.ipv4.conf.default.send_redirects=0
net.ipv4.conf.all.send_redirects=0
net.ipv4.conf.eth0.accept_redirects=0
net.ipv4.conf.eth0.send_redirects=0
net.ipv4.conf.lo.accept_redirects=0
net.ipv4.conf.lo.send_redirects=0
net.ipv6.conf.eth0.accept_redirects=0
net.ipv6.conf.lo.accept_redirects=0
vpn1:~$ sudo sysctl -p /etc/sysctl.conf

ファイアウォール(ufw)を閉じている場合は、UDP 500 と 4500 を空けておくこと。

2. myserver1上にCAのためのディレクトリと設定を準備する

myserver1:~$ sudo mkdir /etc/ssl/CA
myserver1:~$ sudo mkdir /etc/ssl/newcerts
myserver1:~$ sudo sh -c "echo '01' > /etc/ssl/CA/serial"
myserver1:~$ sudo sh -c "echo '01' > /etc/ssl/CA/crlnumber"
myserver1:~$ sudo touch /etc/ssl/CA/index.txt
myserver1:~$ sudo vi /etc/ssl/openssl.cnf

/etc/ssl/openssl.cnfの抜粋:

dir		= /etc/ssl		# Where everything is kept
database	= $dir/CA/index.txt	# database index file.
certificate	= $dir/certs/ca1.crt 	# The CA certificate
serial		= $dir/CA/serial 		# The current serial number
crlnumber	= $dir/CA/crlnumber # the current crl number
                    # must be commented out to leave a V1 CRL
crl     = $dir/crl/crl.pem
private_key	= $dir/private/ca1.key

3. CAの証明書・鍵を作成する

myserver1:~$ sudo openssl req -new -x509 -extensions v3_ca -keyout /etc/ssl/private/ca1.key -out /etc/ssl/certs/ca1.crt -days 3652
(snip)
Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:Aichi
Locality Name (eg, city) []:Nagoya
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Home
Organizational Unit Name (eg, section) []:CA
Common Name (e.g. server FQDN or YOUR name) []:ca1.domain.local
Email Address []:

4. myserver1ホストの秘密鍵を作成する

myserver1:~$ openssl genrsa -aes256 -out myserver1.key 2048
Enter pass phrase for myserver1.key:********
(後でパスワードを削除するので、パスワードはここでは適当に決める)
Verifying - Enter pass phrase for myserver1.key:********

秘密鍵ファイルのパスワードを削除しておく

myserver1:~$ openssl rsa -in myserver1.key -out myserver1.key
Enter pass phrase for myserver1.key:********
writing RSA key

5. CSRを作成する

myserver1:~$ openssl req -new -days 1826 -key myserver1.key -out myserver1.csr
(snip)
Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:Aichi
Locality Name (eg, city) []:Nagoya
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Home
Organizational Unit Name (eg, section) []:Server
Common Name (e.g. server FQDN or YOUR name) []:myserver1.domain.local
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

6. CA鍵を使って署名する

myserver1:~$ sudo openssl ca -in myserver1.csr -config /etc/ssl/openssl.cnf
Enter pass phrase for /etc/ssl/private/ca.key:********
(snip)
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y
(snip)
Data Base Updated

7. CA証明書とホスト証明書・鍵を /etc/ipsec.d にコピーしておく

myserver1:~$ sudo cp -p /etc/ssl/certs/ca1.crt /etc/ipsec.d/cacerts/
myserver1:~$ sudo cp -p /etc/ssl/newcerts/01.pem /etc/ipsec.d/certs/myserver1.crt
myserver1:~$ sudo cp myserver1.key /etc/ipsec.d/private/

8. myvps1用の証明書も同様に作成する

myserver1:~$ openssl genrsa -aes256 -out myvps1.key 2048
myserver1:~$ openssl rsa -in myvps1.key -out myvps1.key
myserver1:~$ openssl req -new -days 1826 -key myvps1.key -out myvps1.csr
myserver1:~$ sudo openssl ca -in myvps1.csr -config /etc/ssl/openssl.cnf

9. myvps1 にホスト証明書・鍵、CA証明書をコピーする

myserver1:~$ cp /etc/ssl/certs/ca1.crt .
myserver1:~$ cp /etc/ssl/newcerts/02.pem ./myvps1.crt
myserver1:~$ scp ca1.crt myvps1.crt myvps1.key myvps1:

myvps1:~$ sudo cp ca1.crt /etc/ipsec.d/cacerts/
myvps1:~$ sudo cp myvps1.crt /etc/ipsec.d/certs/
myvps1:~$ sudo cp myvps1.key /etc/ipsec.d/private/
myvps1:~$ rm ca1.crt myvps1.crt myvps1.key
myserver1:~$ rm ca1.crt myvps1.crt myvps1.key

10. strongswan の設定 (myserver1側)

設定ファイルを編集する。

myserver1:~$ sudo vi /etc/ipsec.conf

config setup セクションの後に以下の内容を追加する。

conn myhome-to-vps
	authby=rsasig
	auto=start
	closeaction=restart
	dpdaction=restart
	left=192.168.100.240
	leftsubnet=192.168.100.0/24
	leftcert=myserver1.crt
	right=203.0.113.180
	rightsubnet=203.0.113.180/32
	rightid="C=JP, ST=Aichi, O=Home, OU=Server, CN=myvps1.vpsnet.example.jp"

こちら側から接続を開始するため、auto=start を記述する。また接続が切れたときにはこちら側から再接続を実行するため、closeaction=restart と dpdaction=restart を記述する。

パスワードファイルには秘密鍵のファイル名を記述する。

myserver1:~$ sudo vi /etc/ipsec.secrets

/etc/ipsec.secrets:

: RSA myserver1.key

11. strongswan の設定 (myvps1側)

こちらも設定ファイルを編集する。

myvps1:~$ sudo vi /etc/ipsec.conf

config setup セクションの後に以下の内容を追加する。

conn myhome-to-vps
	authby=rsasig
	auto=add
	closeaction=clear
	dpdaction=clear
	left=203.0.113.180
	leftsubnet=203.0.113.180/32
	leftcert=myvps1.crt
	right=%any
	rightsubnet=192.168.100.0/24
	rightid="C=JP, ST=Aichi, O=Home, OU=Server, CN=myserver1.domain.local"

パスワードファイルには秘密鍵のファイル名を記述する。

myvps1:~$ sudo vi /etc/ipsec.secrets

/etc/ipsec.secrets:

: RSA myvps1.key

12. サービス起動と確認

サービスを起動する。

myserver1:~$ sudo service strongswan start
myvps1:~$ sudo service strongswan start

接続できたかどうか、ip xfrm state と ip xfrm policy コマンドで確認する。

myserver1:~$ sudo ip xfrm state
src 192.168.100.240 dst 203.0.113.180
	proto esp spi 0xbaef12dc reqid 1 mode tunnel
	replay-window 32 flag af-unspec
	auth-trunc hmac(sha1) 0x6bde34f03f729b5a3c1d93c112ea6a40bf312742 96
	enc cbc(aes) 0x4f2fa3876e41e825be32a4e710a5f193
	encap type espinudp sport 4500 dport 4500 addr 0.0.0.0
src 203.0.113.180 dst 192.168.100.240
	proto esp spi 0xbb4b32e0 reqid 1 mode tunnel
	replay-window 32 flag af-unspec
	auth-trunc hmac(sha1) 0x44b52fad2bf912e10b61706add1337f823ec344e 96
	enc cbc(aes) 0xaf32405118ac467efb02f5f76e59aad1
	encap type espinudp sport 4500 dport 4500 addr 0.0.0.0

myserver1:~$ sudo ip xfrm policy
src 203.0.113.180/32 dst 192.168.100.0/24 
	dir fwd priority 1827 
	tmpl src 203.0.113.180 dst 192.168.100.240
		proto esp reqid 1 mode tunnel
src 203.0.113.180/32 dst 192.168.100.0/24 
	dir in priority 1827 
	tmpl src 203.0.113.180 dst 192.168.100.240
		proto esp reqid 1 mode tunnel
src 192.168.100.0/24 dst 203.0.113.180/32 
	dir out priority 1827 
	tmpl src 192.168.100.240 dst 203.0.113.180
		proto esp reqid 1 mode tunnel
(snip)

自宅-VPS間でIPsec (openswan)

自宅(動的IPアドレス)とVPS(固定IPアドレス)の間で、IPsecトンネルを常時接続してみる。これには、自宅のIPアドレスが変わっても、VPS経由で自宅に入れるというメリットがある。

ネットワーク図 (IPアドレスは例示用)
03

OS: Ubuntu 14.04 LTS
ソフトウェア: openswan

1. VPS側
ipsec.confを編集する。

myvps:~$ sudo vi /etc/ipsec.conf

/etc/ipsec.conf:

config setup
	protostack=netkey #autoから変更
(snip)
conn myhome-to-vps
    authby=secret
    auto=add
    left=203.0.113.180
    leftsubnet=203.0.113.180/32
    right=%any
    rightsubnet=192.168.24.0/24
    rightid=192.168.24.252

事前共有鍵を設定する。

myvps:~$ sudo vi /etc/ipsec.secrets

/etc/ipsec.secrets:

: PSK "mypresharedkey"

2. 自宅側
ipsec.confを編集する。

myvps:~$ sudo vi /etc/ipsec.conf

/etc/ipsec.conf:

config setup
	protostack=netkey #autoから変更
(snip)
conn myhome-to-vps
    authby=secret
    auto=start
    left=192.168.24.252
    leftsubnet=192.168.24.0/24
    right=203.0.113.180
    rightsubnet=203.0.113.180/32

VPS側と同じ事前共有鍵を設定する。

myvps:~$ sudo vi /etc/ipsec.secrets

/etc/ipsec.secrets:

: PSK "mypresharedkey"

以上の設定で接続できる。NAPTを越えることが自動的に検出されて、IPsecパケットはNAT-Traversalでカプセル化される。iptablesでUDP 4500が閉じている場合は、ACCEPTするように変更すること。

自宅グローバルIPアドレスは不定のため、IPsecのピアIDとしては適当な文字列(ここではプライベートIPアドレス)を使う。通常、片側の端点が動的IPアドレスの場合は Aggressive モードを使うものだが、上記の設定であれば Main モードでつながるようだ。このへんの仕組みがよくわからない…

また、上記は事前共有鍵による認証を使っているが、OpenSSLで生成したRSA証明書認証を設定しようとするとうまくいかない。このあたり試行錯誤が必要だ。
(※追記: openswanだとうまくいかないので、strongswanに切り替えました。strongswanとopenswanの比較はこちら)

Linux サーバ間 IPsec 接続 (openswan)

Linuxサーバ同士の間で通常のIPsecを接続したことが無かったので、検証してみた。

I. 前提

環境は以下の通り。
01

vpn1、vpn2、host1、host2、router1 OSは全てUbuntu 14.04である。

vpn1←→vpn2の間で、openswanでトンネルモードIPsec接続をする。10.0.1.0/24 から 10.0.2.0/24 へのパケット、またその逆方向のパケットはトンネルへ入るようにする。つまり、例えばhost1からhost2へpingを打つとトンネルを通ることになる。10.0.1.0/24や10.0.2.0/24へのスタティックルートはrouter1に追加しないようにしておくので、VPNトンネルが出来なければhost1からhost2へのpingは到達できない。

vpn2側に自動接続開始の設定を入れることで、VPNトンネルを自動的に張ることにする。

II. 設定

以下、設定を記述する(IPアドレス設定など基本的なところは省略)

1. router1 の設定:

router1:~$ sudo vi /etc/sysctl.conf
net.ipv4.ip_forward=1  #28行目のコメントを外す
router1:~$ sudo sysctl -p /etc/sysctl.conf

2. vpn1の設定:

デフォルトルートは router1 に向けておく。向いていなかったら /etc/network/interfaces などを編集して変更する。

vpn1$ ip route
default via 1.2.3.1 dev eth1
1.2.3.0/24 dev eth1  proto kernel  scope link  src 1.2.3.4
10.0.1.0/24 dev eth0  proto kernel  scope link  src 10.0.1.1

OpenSWANをインストールする。

vpn1:~$ sudo apt-get install openswan

カーネルパラメータを設定する。

vpn1:~$ sudo vi /etc/sysctl.conf
net.ipv4.ip_forward=1  #28行目のコメントを外す
# 以下、追記する
net.ipv4.conf.default.send_redirects=0
net.ipv4.conf.all.send_redirects=0
net.ipv4.conf.eth0.accept_redirects=0
net.ipv4.conf.eth0.send_redirects=0
net.ipv4.conf.lo.accept_redirects=0
net.ipv4.conf.lo.send_redirects=0
net.ipv6.conf.eth0.accept_redirects=0
net.ipv6.conf.lo.accept_redirects=0
vpn1:~$ sudo sysctl -p /etc/sysctl.conf

IPsecの事前共有鍵を設定する。

vpn1:~$ sudo vi /etc/ipsec.secrets
# 以下の行を追記
: PSK "passwordstring"

IPsecの接続設定を記述する。

vpn1:~$ sudo vi /etc/ipsec.conf
config setup	# protostack以外はデフォルトのまま
	dumpdir=/var/run/pluto/
	nat_traversal=yes
	virtual_private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v4:25.0.0.0/8,%v6:fd00::/8,%v6:fe80::/10
	oe=off
	protostack=netkey	# auto から変更
# 以下、追記
conn linux-to-linux
	authby=secret	# 共有鍵認証とする
	left=1.2.3.4	# 自ホストのIPアドレス
	leftsubnet=10.0.1.0/24	# 自分側のプライベートネットワーク
	right=5.6.7.8	# 対向側ホストのIPアドレス
	rightsubnet=10.0.2.0/24	# 対向側のプライベートネットワーク
	auto=add	# こちら側からはVPN接続を自動開始しない

デーモンを再起動する。

vpn1:~$ sudo service ipsec restart

3. vpn2 の設定:

デフォルトルートは router1 に向けておく。向いていなかったら /etc/network/interfaces などを編集して変更する。

vpn1$ ip route
default via 5.6.7.1 dev eth1
5.6.7.0/24 dev eth1  proto kernel  scope link  src 5.6.7.8
10.0.2.0/24 dev eth0  proto kernel  scope link  src 10.0.2.1

OpenSWANをインストールする。

vpn1:~$ sudo apt-get install openswan

カーネルパラメータを変更する。

vpn2:~$ sudo vi /etc/sysctl.conf	# vpn1と同じ記述をする。
vpn2:~$ sudo sysctl -p /etc/sysctl.conf

IPsec事前共有鍵を設定する。

vpn2:~$ sudo vi /etc/ipsec.secrets	# これもvpn1と同じ記述をする。

IPsecの設定を記述する。

vpn2:~$ sudo vi /etc/ipsec.conf
config setup	# protostack以外はデフォルトのまま
	dumpdir=/var/run/pluto/
	nat_traversal=yes
	virtual_private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v4:25.0.0.0/8,%v6:fd00::/8,%v6:fe80::/10
	oe=off
	protostack=netkey	# auto から変更
# 以下、追記する。right/leftをvpn1側とは入れ換える。
conn linux-to-linux
	authby=secret
	left=5.6.7.8
	leftsubnet=10.0.2.0/24
	right=1.2.3.4
	rightsubnet=10.0.1.0/24
	auto=start	# こちら側からVPN接続を自動開始する

デーモンを再起動する。

vpn1:~$ sudo service ipsec restart

これで完成。

III. 確認

ipsec verify を実行すると FAILED が出るが、気にしなくてよい。

vpn1:~$ sudo ipsec verify
Two or more interfaces found, checking IP forwarding        [FAILED]

router1でtcpdumpを仕掛けておき、host1からhost2あてにpingを打ってみる。

host1:~$ ping 10.0.2.100
router1:~$ sudo tcpdump -n -i eth1 not tcp port 22
10:49:22.294046 IP 1.2.3.4 > 5.6.7.8: ESP(spi=0x8f3ac7ea,seq=0x1), length 132
10:49:22.294543 IP 5.6.7.8 > 1.2.3.4: ESP(spi=0x0293d289,seq=0x1), length 132
10:49:23.295411 IP 1.2.3.4 > 5.6.7.8: ESP(spi=0x8f3ac7ea,seq=0x2), length 132
10:49:23.295890 IP 5.6.7.8 > 1.2.3.4: ESP(spi=0x0293d289,seq=0x2), length 132

ESPにカプセル化されてパケットが通過していることが確認できた。

※パケットがトンネルに入るか入らないかは、IPルーティングではなくxfrmポリシーによって決まっている。
ip xfrm state、ip xfrm policy コマンドで確認できる。

vpn1:~$ sudo ip xfrm state
src 1.2.3.4 dst 5.6.7.8
	proto esp spi 0x8f3ac7ea reqid 16385 mode tunnel
	replay-window 32 flag af-unspec
	auth-trunc hmac(sha1) 0xdbc2f99d8243e36fc8920c790c0b6b9d85c84a48 96
	enc cbc(aes) 0x506786cc1fbf21c272ddeab0c4deb739
src 5.6.7.8 dst 1.2.3.4
	proto esp spi 0x0293d289 reqid 16385 mode tunnel
	replay-window 32 flag af-unspec
	auth-trunc hmac(sha1) 0x10110db5180fb3773d47cb538b29ae9371137ebd 96
	enc cbc(aes) 0xb29c28de3d0e40111f6f9720fddf117f
vpn1:~$ sudo ip xfrm policy
src 10.0.1.0/24 dst 10.0.2.0/24 
	dir out priority 2344 
	tmpl src 1.2.3.4 dst 5.6.7.8
		proto esp reqid 16385 mode tunnel
src 10.0.2.0/24 dst 10.0.1.0/24 
	dir fwd priority 2344 
	tmpl src 5.6.7.8 dst 1.2.3.4
		proto esp reqid 16385 mode tunnel
src 10.0.2.0/24 dst 10.0.1.0/24 
	dir in priority 2344 
	tmpl src 5.6.7.8 dst 1.2.3.4
		proto esp reqid 16385 mode tunnel
(snip)

Ubuntuで独自CA構築

Webサーバ上に独自CAを構築して証明書を作成する。
OS: Ubuntu12.04
参考URL: Ubuntu documentation: Certificates

必要なディレクトリを作成
$ sudo mkdir /etc/ssl/CA
$ sudo mkdir /etc/ssl/newcerts

シリアルとインデックス管理ファイルを作成する
$ sudo sh -c “echo ’01’ > /etc/ssl/CA/serial”
$ sudo touch /etc/ssl/CA/index.txt

openssl.cnfファイルを編集する。
$ sudo cp -p /etc/ssl/openssl.cnf{,.orig}
$ sudo vi /etc/ssl/openssl.cnf
dir = /etc/ssl # Where everything is kept
database = $dir/CA/index.txt # database index file.
certificate = $dir/certs/cacert.pem # The CA certificate
serial = $dir/CA/serial # The current serial number

CAの鍵と証明書を作成 (有効期間10年)
sudo openssl req -new -x509 -extensions v3_ca -keyout cakey.pem -out cacert.pem -days 3652

Enter PEM pass phrase: ********
Verifying – Enter PEM pass phrase: ********

Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:Aichi
Locality Name (eg, city) []:Nagoya
Organization Name (eg, company) [Internet Widgits Pty Ltd]: MyHome
Organizational Unit Name (eg, section) []: Dept. for general purpose
Common Name (e.g. server FQDN or YOUR name) []:MyCA
Email Address []: oreore@example.jp

出来上がった鍵と証明書をディレクトリに配置する。
sudo mv cakey.pem /etc/ssl/private/
sudo mv cacert.pem /etc/ssl/certs/
sudo chmod go-rwx /etc/ssl/private/cakey.pem

以上でCAの構築は完了。

以下、サーバ証明書を作成する。
サーバ鍵の作成
openssl genrsa -aes256 -out server.key 2048
鍵ファイルに付いてしまったパスワードを削除する。
openssl rsa -in server.key -out server.key

CSR作成 (有効期間は5年にしてみる)
openssl req -new -days 1826 -key server.key -out server.csr
Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:Aichi
Locality Name (eg, city) []:Nagoya
Organization Name (eg, company) [Internet Widgits Pty Ltd]:MyHome
Organizational Unit Name (eg, section) []: Dept. for general purpose
Common Name (e.g. server FQDN or YOUR name) []:www.example.jp
Email Address []: oreore@example.jp
Please enter the following ‘extra’ attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

先ほど作成したCAでサーバCSRに署名する
$ sudo openssl ca -in server.csr -config /etc/ssl/openssl.cnf
Using configuration from /etc/ssl/openssl.cnf
Enter pass phrase for /etc/ssl/private/cakey.pem: ********
….

証明書が/etc/ssl/newcerts/01.pemとして作成される。
—–BEGIN CERTIFICATE—– から —–END CERTIFICATE—– までをコピーし、証明書ファイルに保存する。
$ sudo vi /etc/ssl/certs/server.crt
(上記の文字列をペースト)

鍵ファイルも保存しておく
$ sudo mv server.key /etc/ssl/private/server.key
$ sudo chown root:root /etc/ssl/private/server.key
$ sudo chmod go-rwx /etc/ssl/private/server.key