プロローグ
思えば、自分がAWS上でのVPNに触れたのは、数年前に出逢ったこちらの記事がきっかけでした。
今や、SoftEther/WindowsVPN/VyOSの経験を経て、思えば遠くに来たもんだ。
このたび、一周回って、OpenVPNをSSL-VPN(Point-to-Site VPN/SW-VPN)として改めてAWS上で利用する機会がありまして、今自分が具備する経験・知識を総動員して、下記にトライしました:
- OpenVPNサーバ(EC2)に挿すNIC(ENI)を、PublicとPrivateで分けて2枚に!
- CloudFormationでの全自動化!
- OpenVPNサーバのインストール
- CA作成~ファーストユーザの証明書/秘密鍵作成
- CRL作成(dummyユーザを作成&削除)
- ビルトインのec2-userを削除し、別のVPN管理者ユーザを作成(SSH接続&sudo利用、おっけー)
- OpenVPNクライアント用の設定ファイルのテンプレートの出力
- 【未着手】
FlowLogs用設定投入(LogStream/LogGroup作成&IAM-Role作成) - 【未着手】
OpenVPNログのローテーション機能を追加
- 敢えてのOpenVPN Clientの利用(お気に入りのvpnuxClientもおっけー)
- Man-in-the-Middle対策(よりセキュアに)
- CRYPTRECの推奨暗号リストやIPAの暗号推奨期間を受けて、AES256/SHA256(SHA1は非推奨)の採用(よりセキュアに)
⇒以下に挙げる設定値等に関して、こうしたらどう?とか、それはアカン!とかあったら、ご指摘いただけると幸いです。
環境構築手順
別にCloudFormationでなくても、下記の手順を踏めばおっけー。
(CloudFormationファイル(YAML)にご興味ある方、個別にご連絡いただければ♬)
①必要なSWのインストール
②OpenVPNサーバの設定
③OpenVPNサーバの環境構築手順(スクリプト)
④OpenVPNクライアントの設定
①必要なSWのインストール
Amazon Linuxであれば、下記でおっけー:
# yum update -y
# yum install ec2-net-utils -y
# yum install tcpdump -y (任意/オマケ)
# yum install openvpn -y
# yum install easy-rsa --enablerepo=epel -y
※CloudFormation中では「runcmd:」で実行しています。
②OpenVPNサーバの設定
下記の『server.conf』でおっけー:
port 443
proto tcp
dev tun
server 《VPNに割り当てるCIDR》 255.255.255.0
ifconfig-pool-persist ipp.txt
push "route 《プライベートサブネットのCIDR》 255.255.255.0" # Example
ca ca.crt # Certificate Authority
cert server.crt # Server Certificate
key server.key # Server Private Key
dh dh2048.pem # DH parametar key for DH key exchange
crl-verify crl.pem # Certificate Revocation List
tls-auth ta.key 0 # Symmetric key for TLS-Auth ("0" means "server")
cipher AES-256-CBC # should match with client-side
auth SHA256 # should match with client-side
keepalive 10 60
ping-timer-rem
persist-tun
persist-key
comp-lzo
max-clients 30
status /var/log/openvpn-status.log
log /var/log/openvpn.log
log-append /var/log/openvpn.log
user nobody
group nobody
verb 3
③OpenVPNサーバの環境構築手順(スクリプト)
下記の『openvpn_config.sh』を実行すればおっけー:
#!/bin/sh
export OPENVPN_CONFIG=/etc/openvpn
export KEY_HOME=/usr/share/easy-rsa/2.0
cd $KEY_HOME
# "Overwriting" env parameters in "vars" here
echo 'export KEY_COUNTRY="JP"' >> $KEY_HOME/vars
echo 'export KEY_PROVINCE="XXX"' >> $KEY_HOME/vars
echo 'export KEY_CITY="XXX"' >> $KEY_HOME/vars
echo 'export KEY_ORG="XXX"' >> $KEY_HOME/vars
echo 'export KEY_EMAIL="XXX@YYY.ZZZ"' >> $KEY_HOME/vars
echo 'export KEY_OU="IT Admin"' >> $KEY_HOME/vars
echo 'export KEY_SIZE=2048' >> $KEY_HOME/vars
echo 'export CA_EXPIRE=3650' >> $KEY_HOME/vars # [Days]
echo 'export KEY_EXPIRE=3650' >> $KEY_HOME/vars # [Days]
source $KEY_HOME/vars
$KEY_HOME/clean-all # Initialize CA
$KEY_HOME/pkitool --initca # Build CA (in non-interactive mode)
$KEY_HOME/pkitool --server server # Build server certificate & private key (in non-interactive mode)
$KEY_HOME/build-dh # Build DH parametar (prime number?) for DH key exchange
$KEY_HOME/pkitool $* dummy # Preparation for generating crl file (creating "dummy" user cert)
$KEY_HOME/revoke-full dummy # Generate crl (Certificate Revocation List)
openvpn --genkey --secret $OPENVPN_CONFIG/ta.key # Generating tls-auth key (symmetric)
ln -s $KEY_HOME/keys/ca.crt $OPENVPN_CONFIG
ln -s $KEY_HOME/keys/server.crt $OPENVPN_CONFIG
ln -s $KEY_HOME/keys/server.key $OPENVPN_CONFIG
ln -s $KEY_HOME/keys/dh2048.pem $OPENVPN_CONFIG
# crl.pem is specially treated.
mv $KEY_HOME/keys/crl.pem $OPENVPN_CONFIG
chmod 666 $OPENVPN_CONFIG/crl.pem
ln -s $OPENVPN_CONFIG $KEY_HOME/keys/crl.pem
# Add a new OS/SSH user "vpnadmin" instead of the built-in user "ec2-user".
/usr/sbin/useradd vpnadmin
/usr/sbin/usermod -G wheel vpnadmin
mkdir /home/vpnadmin/.ssh
chown vpnadmin:wheel /home/vpnadmin/.ssh
chmod 700 /home/vpnadmin/.ssh
cp /home/ec2-user/.ssh/authorized_keys /home/vpnadmin/.ssh/authorized_keys
chown vpnadmin:wheel /home/vpnadmin/.ssh/authorized_keys
chmod 600 /home/vpnadmin/.ssh/authorized_keys
$KEY_HOME/pkitool $* vpnadmin
# Delete the built-in user for security
/usr/sbin/userdel -r ec2-user
sysctl -w net.ipv4.ip_forward=1 # Transient config
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf # Permanent config
# IP masquerade (from VPN clients to AWS private servers)
iptables -F
iptables -t nat -F
iptables -X
iptables -t nat -A POSTROUTING -s 《VPNクライアントのCIDR》 -d 《プライベートサブネットのCIDR》 -j MASQUERADE
/sbin/chkconfig --add openvpn
service openvpn start
特記事項としては、『外部からの通信をAWSが受け付ける』ために、下記の(A)か(B)が必要:
(A)SecurityGroupで通信を許可する。
⇒Allow From 《VPNクライアントのCIDR》
(B)IPマスカレードの設定を投入する。
⇒《VPNクライアントのCIDR》からの通信を、OpenVPNサーバから来た通信に見せる(マスカレード=仮面舞踏会、♬きらめく光~):
iptables -t nat -A POSTROUTING -s 《VPNクライアントのCIDR》 -d 《プライベートサブネットのCIDR》 -j MASQUERADE
⇒AWSの仕様/制約に、「AWSが把握していない(払い出したのではない)IPアドレスは受け付けない(ドロップする)」というルールに基づく。
⇒(A)/(B)どちらが「正解」かはわからない。
⇒(A)/(B)いずれもおっけーなことは確認済み。
⇒「トレーサビリティ(A)」と「疎結合(B)」のいずれを取るかのトレードオフ。
⇒今回の自動化では(敷居がHigherな)「疎結合(B)」を採用。
また、「ビルトインユーザec2-userの削除」は、ec2-userでSSHログインしている場合はエラーが起こる(自分自身を消そうとする)ので、別ユーザ(vpnadmin等)でSSHログインしなおしてから実行する必要がある。
(CloudFormationならイキナリvpnadminでの接続になる)
④VPNクライアントの設定
(甲) OpnVPNクライアントの場合
下記の設定ファイル『client.conf』でおっけー。
client
dev tun
proto tcp
remote 《OpenVPNサーバのEIP》 443
# Assuming the certificate files below are put in the same folder as the client config file:
ca ca.crt # Certificate Authority
cert vpnadmin.crt # Client Certificate
key vpnadmin.key # Client Private Key
remote-cert-tls server
;ns-cert-type server # Will be deprecated
tls-auth ta.key 1 # ("1" means "client")
cipher AES-256-CBC # should match with server-side
auth SHA256 # should match with server-side
comp-lzo
nobind
persist-key
persist-tun
resolv-retry infinite
verb 3
⇒OpenVPNクライアントからOpenVPNサーバとの接続コマンドは、コマンドプロンプトから下記のコマンドを一発(GUIとかもありますが):
C:\> openvpn --config client.ovpn
※注意点は、コマンドプロンプトを管理者権限で起動すること(スタティックルートを追加するため)
⇒ログがずるずる出て、『Initialization Sequence Completed』が出たらおっけー。
(乙) vpnuxClientの場合
下記の設定画面(2画面)でおっけー。
⇒ログがずるずる出て、『Initialization Sequence Completed』が出たらおっけー。
小咄:crl.pemファイルが読めなくてハマった噺ぃ~
当初、「crl.pem(証明書失効リスト)」ファイルも、「server.*」ファイルと同様に、EasyRSAで作成したディレクトリに存在するマスタファイルに対して/etc/openvpn(=OPENVPN_CONFIG)からシンボリックリンクを張るアプローチでした:
# ln -s $KEY_HOME/keys/crl.pem $OPENVPN_CONFIG
が、これだと『crl.pem cannot read』というエラーが発生する。パーミッションが原因だけど、$KEY_HOME/keysフォルダの権限も開放しないといけない?そこで、
# mv $KEY_HOME/keys/crl.pem $OPENVPN_CONFIG
# chmod 666 $OPENVPN_CONFIG/crl.pem
# ln -s $OPENVPN_CONFIG $KEY_HOME/keys/crl.pem
と変更したところグー。
「server.*」ファイルなんかもOPENVPN_CONFIGへmvしようかどうか、悩ましいところです。
(一番更新されうるだろうcrl.pemをmvしているから、基本不変なserver.*ファイルも。。。)
エピローグ
...SSL-VPNは、OpenVPNでもvpnuxClientでもそうだけど、コネクション初期化フェーズをログでtailしているときに、疎通が成功するときはログがずるずるスムーズに流れて『Initialization Sequence Completed』が登場する。これがカタルシスっっっ☆ ☆ ☆
(うまくいかないときは、『Restarting』やらなんやらでグダグダ)
参考情報
-
AWS環境にOpenVPNでVPNを構築
⇒ワタクシのあらゆるVPN知識の産みのヲヤ。 -
基本的なOpenVPNの構築手順
⇒特にta.keyについて。EasyRSA 3.0は未着手。。。 -
OpenVPN サーバ構築
⇒本格的ですごい。。。脱帽。 -
OpenVPN クライアント設定
⇒3.のクライアント設定編。 -
iptablesで特定のポートを別のホストへ転送する方法
⇒特にNATテーブル(IPマスカレード)の設定。 -
sudoers は編集せずに sudoers.d の中に設定を書こう
⇒特にsudoersの追加を自動化する方法。