openvpn で AWS Client VPN
概要
Debian12 にインストールした openvpn で AWS のクライアントVPNへ接続してみます。
利用する環境は https://zenn.dev/mnod/articles/48da54c1f813c6 と同様です。
AWSの設定は cli を利用します。
easyrsa による証明書の利用
AWSクライアントVPNではEC_prime256v1の証明書 は対応していないので、RSA2048で証明書を作る。
証明書について、openvpn では easy-rsa というツールがあるので、これを試してみる。
証明書の発行
Deiban では make-cadir コマンドを実行することで、ツールを準備できる。
$ make-cadir ~/easy-rsa
$ cd ~/easy-rsa/
$ ./easyrsa version
EasyRSA Version Information
Version: 3.1.0
Generated: Wed May 18 20:53:50 CDT 2022
SSL Lib: OpenSSL 3.0.16 11 Feb 2025 (Library: OpenSSL 3.0.16 11 Feb 2025)
Git Commit: 1600b3fe9bd71e229b8648cd24206c55917b2f9b
Source Repo: https://github.com/OpenVPN/easy-rsa
CAの初期化し、ルート証明書を作成する。
$ ./easyrsa init-pki
$ ./easyrsa build-ca nopass
$ ls -l pki/ca.crt pki/private/ca.key
-rw------- 1 debian debian 1204 Jul 11 07:34 pki/ca.crt
-rw------- 1 debian debian 1704 Jul 11 07:34 pki/private/ca.key
サーバ証明書を作成
$ ./easyrsa build-server-full test-server nopass
$ ls -l pki/issued/test-server.crt pki/private/test-server.key
-rw------- 1 debian debian 4635 Jul 11 07:37 pki/issued/test-server.crt
-rw------- 1 debian debian 1704 Jul 11 07:36 pki/private/test-server.key
クライアント証明書を作成
$ ./easyrsa build-client-full test-client nopass
$ ls -l pki/issued/test-client.crt pki/private/test-client.key
-rw------- 1 debian debian 4499 Jul 11 07:39 pki/issued/test-client.crt
-rw------- 1 debian debian 1704 Jul 11 07:39 pki/private/test-client.key
AWS設定
作成したサーバ証明書と秘密鍵、ルート証明書を、ACMへインポートする。
$ aws acm import-certificate --certificate fileb://test-server.crt --private-key fileb://test-server.key --certificate-chain fileb://root_ca.crt
インポートした証明書の確認
$ certificatearn=arn:aws:acm:<region>:<account>:certificate/<unique-id>
$ aws acm list-certificates
$ aws acm describe-certificate --certificate-arn ${certificatearn}
仮想プライベートエンドポイント (Virtual Private Endpoint) を作成
$ aws ec2 create-client-vpn-endpoint \
--client-cidr-block 10.10.0.0/22 \
--server-certificate-arn ${certificatearn} \
--authentication-options Type=certificate-authentication,MutualAuthentication={ClientRootCertificateChainArn=${certificatearn}} \
--connection-log-options Enabled=false \
--transport-protocol udp \
--region ap-northeast-1
作成したエンドポイントを確認
$ cvpnendpoint=cvpn-endpoint-<unique-id>
$ aws ec2 describe-client-vpn-endpoints
サブネットへの関連付け
$ subnetid=subnetid-<unique-id>
$ aws ec2 associate-client-vpn-target-network \
--client-vpn-endpoint-id ${cvpnendpoint} \
--subnet-id ${subnetid} \
--region ap-northeast-1
結果の確認 (ステータスは authorizing から active へ変化する)
$ cvpnassoc=cvpn-assoc-<unique-id>
$ aws ec2 describe-client-vpn-target-networks --client-vpn-endpoint-id ${cvpnendpoint}
認証ルールの追加
$ aws ec2 authorize-client-vpn-ingress \
--client-vpn-endpoint-id ${cvpnendpoint} \
--target-network-cidr 0.0.0.0/0 \
--authorize-all-groups \
--region ap-northeast-1
結果を確認 (ステータスは authorizing から active へ変化する)
$ aws ec2 describe-client-vpn-authorization-rules --client-vpn-endpoint-id ${cvpnendpoint}
openvpn で利用する設定ファイルを出力
$ aws ec2 export-client-vpn-client-configuration \
--client-vpn-endpoint-id ${cvpnendpoint} \
--region ap-northeast-1 \
--output text | tee awsclientvpn.conf
awsclientvpn.conf をVPNクライアントに配置する。
certとkey の項目を追加する。(verbの指定はお好みで)
client
dev tun
proto udp
remote cvpn-endpoint-<unique-id>.prod.clientvpn.<region>.amazonaws.com 443
remote-random-hostname
resolv-retry infinite
nobind
remote-cert-tls server
cipher AES-256-GCM
# verb 3
<ca>
ルート証明書
</ca>
cert test-client.crt
key test-client.key
reneg-sec 0
verify-x509-name test-2048 name
接続してみる。
$ sudo openvpn --config awsclientvpn.conf
2025-07-11 08:02:58 WARNING: file 'test-client.key' is group or others accessible
2025-07-11 08:02:58 OpenVPN 2.6.3 x86_64-pc-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] [DCO]
2025-07-11 08:02:58 library versions: OpenSSL 3.0.16 11 Feb 2025, LZO 2.10
2025-07-11 08:02:58 DCO version: N/A
2025-07-11 08:02:58 TCP/UDP: Preserving recently used remote address: [AF_INET]18.176.244.114:443
2025-07-11 08:02:58 UDPv4 link local: (not bound)
2025-07-11 08:02:58 UDPv4 link remote: [AF_INET]18.176.244.114:443
2025-07-11 08:02:58 [test-server] Peer Connection Initiated with [AF_INET]18.176.244.114:443
2025-07-11 08:02:58 Options error: Unrecognized option or missing or extra parameter(s) in [PUSH-OPTIONS]:2: block-outside-dns (2.6.3)
2025-07-11 08:02:58 TUN/TAP device tun0 opened
2025-07-11 08:02:58 net_iface_mtu_set: mtu 1500 for tun0
2025-07-11 08:02:58 net_iface_up: set tun0 up
2025-07-11 08:02:58 net_addr_v4_add: 10.10.0.34/27 dev tun0
2025-07-11 08:02:58 Initialization Sequence Completed
トンネルデバイスの確認
$ ip link show tun0
13: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN mode DEFAULT group default qlen 500
link/none
$ ip a show tun0
13: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 500
link/none
inet 10.10.0.130/27 scope global tun0
valid_lft forever preferred_lft forever
inet6 fe80::957f:1480:61da:6b68/64 scope link stable-privacy
valid_lft forever preferred_lft forever
疎通確認
$ ping 10.0.1.1
PING 10.0.1.1 (10.0.1.1) 56(84) bytes of data.
64 bytes from 10.0.1.1: icmp_seq=1 ttl=62 time=7.68 ms
接続状況の確認
$ aws ec2 describe-client-vpn-connections --client-vpn-endpoint-id ${cvpnendpoint}
CRLのテスト
証明書を失効させて、CRLを出力する。
$ ./easyrsa revoke test-client
$ ./easyrsa gen-crl
$ ls -l pki/crl.pem
-rw------- 1 debian debian 698 Jul 11 08:16 pki/crl.pem
$ openssl crl -in pki/crl.pem -text -noout
AWSクライアントVPNへインポートする。
$ aws ec2 import-client-vpn-client-certificate-revocation-list --client-vpn-endpoint-id ${cvpnendpoint} --certificate-revocation-list file://crl.pem
クライアント側から接続すると以下のようになる。
2025-07-11 08:24:02 TLS Error: TLS key negotiation failed to occur within 60 seconds (check your network connectivity)
2025-07-11 08:24:02 TLS Error: TLS handshake failed
AWSのお掃除
クライアントVPNの終了
$ aws ec2 revoke-client-vpn-ingress --client-vpn-endpoint-id ${cvpnendpoint} --target-network-cidr 0.0.0.0/0 --revoke-all-groups
$ aws ec2 disassociate-client-vpn-target-network --client-vpn-endpoint-id ${cvpnendpoint} --association-id ${cvpnassoc}
$ aws ec2 delete-client-vpn-endpoint --client-vpn-endpoint-id ${cvpnendpoint}
ACMにインポートした証明書の削除
$ aws acm delete-certificate --certificate-arn ${certificatearn}
step-ca による証明書の利用
中間証明書を使いたく、step-ca を試す。
- easy-rsa で作成したルート証明書をルート証明書とする。
- 中間証明書のCSRはstep-caで発行、easy-rsaで署名。rsa2048とする。
証明書の発行
step-ca の導入。環境は Alpine Linux 3.19 のDockerコンテナ。
STEP_LINUX_VER=0.25.2
CERTIFICATES_VER=0.28.3
cd /tmp && wget https://dl.smallstep.com/gh-release/cli/gh-release-header/v${STEP_LINUX_VER}/step_linux_${STEP_LINUX_VER}_amd64.tar.gz \
&& wget https://dl.smallstep.com/gh-release/certificates/gh-release-header/v${CERTIFICATES_VER}/step-ca_linux_${CERTIFICATES_VER}_amd64.tar.gz \
&& tar xzvf step_linux_${STEP_LINUX_VER}_amd64.tar.gz \
&& tar xzvf step-ca_linux_${CERTIFICATES_VER}_amd64.tar.gz \
&& mv step_${STEP_LINUX_VER}/bin/step /usr/local/bin \
&& mv step-ca /usr/local/bin \
&& rm -rf *.tar.gz LICENSE README.md step_${STEP_LINUX_VER}
初期化。勝手に作られた中間証明書の秘密鍵を削除。
easy-rsa で作成したルート証明書をルート証明書としてコピー。
中間証明書のCSRを作成する。
# step ca init
# cd ~/.step/
# shred -u secrets/root_ca_key
# mv /tmp/ca.crt.easyrsa certs/root_ca.crt
# step certificate create "my Intermediate CA" intermediate.csr intermediate_ca_key --csr
作成したCSRを easy-rsa 側でインポート
$ ./easyrsa import-req /tmp/intermediate.csr stepca
$ md5sum pki/reqs/stepca.req /tmp/intermediate.csr
79f44faba037146f536374279dbc4796 pki/reqs/stepca.req
79f44faba037146f536374279dbc4796 /tmp/intermediate.csr
$ openssl req -in pki/reqs/stepca.req --noout -text
CSRに署名
$ ./easyrsa sign-req ca stepca
$ ls -l pki/issued/stepca.crt
-rw------- 1 debian debian 3319 Jul 12 07:12 pki/issued/stepca.crt
証明してできた証明書を中間照明ととして配置。
# mv /tmp/stepca.crt certs/intermediate_ca.crt
# mv intermediate_ca_key secrets/intermediate_ca_key
step-ca を起動する。
# cd
# step-ca --password-file /root/.step/password-file /root/.step/config/ca.json &
# ls -l /root/.step/certs/intermediate_ca.crt /root/.step/certs/root_ca.crt
-rw-r--r-- 1 root root 932 Jul 11 22:14 /root/.step/certs/intermediate_ca.crt
-rw-r--r-- 1 root root 1204 Jul 11 21:59 /root/.step/certs/root_ca.crt
RSA2048でサーバ証明書を作成
# step ca certificate --kty RSA --size 2048 test-2048 test-server.crt test-server.key
~ # ls -l test-server.*
-rw------- 1 root root 1982 Jul 11 22:25 test-server.crt
-rw------- 1 root root 1679 Jul 11 22:25 test-server.key
RSA2048でクライアント証明書を作成
# step ca certificate --kty RSA --size 2048 test@example.net test-client.crt test-client.key
# ls -l test-client.*
-rw------- 1 root root 2002 Jul 11 22:26 test-client.crt
-rw------- 1 root root 1679 Jul 11 22:26 test-client.key
AWS設定
AWS ACMにインポートするために、中間証明書とルート証明書のチェーンファイルを作成
# cat intermediate_ca.crt root_ca.crt > chain.crt
AWS ACMにサーバ証明書、秘密鍵、チェーンファイルをインポート。
$ aws acm import-certificate --certificate fileb://test-server.crt --private-key fileb://test-server.key --certificate-chain fileb://chain.crt
$ certificatearn=arn:aws:acm:<region>:<account>:certificate/<unique-id>
$ aws acm describe-certificate --certificate-arn ${certificatearn}
Virtual Private Endpoint を作成
$ aws ec2 create-client-vpn-endpoint \
--client-cidr-block 10.10.0.0/22 \
--server-certificate-arn ${certificatearn} \
--authentication-options Type=certificate-authentication,MutualAuthentication={ClientRootCertificateChainArn=${certificatearn}} \
--connection-log-options Enabled=false \
--transport-protocol udp \
--region ap-northeast-1
$ cvpnendpoint=cvpn-endpoint-<unique-id>
$ aws ec2 describe-client-vpn-endpoints
$ aws ec2 associate-client-vpn-target-network \
--client-vpn-endpoint-id ${cvpnendpoint} \
--subnet-id ${subnetid} \
--region ap-northeast-1
$ cvpnassoc=cvpn-assoc-<unique-id>>
$ aws ec2 describe-client-vpn-target-networks --client-vpn-endpoint-id ${cvpnendpoint}
$ aws ec2 authorize-client-vpn-ingress \
--client-vpn-endpoint-id ${cvpnendpoint} \
--target-network-cidr 0.0.0.0/0 \
--authorize-all-groups \
--region ap-northeast-1
$ aws ec2 describe-client-vpn-authorization-rules --client-vpn-endpoint-id ${cvpnendpoint}
$ aws ec2 export-client-vpn-client-configuration \
--client-vpn-endpoint-id ${cvpnendpoint} \
--region ap-northeast-1 \
--output text | tee awsclientvpn.conf
client
dev tun
proto udp
remote cvpn-endpoint-<unique-id>.prod.clientvpn.<region>.amazonaws.com 443
remote-random-hostname
resolv-retry infinite
nobind
remote-cert-tls server
cipher AES-256-GCM
# verb 3
<ca>
中間証明書
ルート証明書
</ca>
cert test-client.crt
key test-client.key
reneg-sec 0
verify-x509-name test-2048 name
$ sudo openvpn --config awsclientvpn.conf
2025-07-12 08:37:56 WARNING: file 'test-client.key' is group or others accessible
2025-07-12 08:37:56 OpenVPN 2.6.3 x86_64-pc-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] [DCO]
2025-07-12 08:37:56 library versions: OpenSSL 3.0.16 11 Feb 2025, LZO 2.10
2025-07-12 08:37:56 DCO version: N/A
2025-07-12 08:37:56 TCP/UDP: Preserving recently used remote address: [AF_INET]52.198.164.18:443
2025-07-12 08:37:56 UDPv4 link local: (not bound)
2025-07-12 08:37:56 UDPv4 link remote: [AF_INET]52.198.164.18:443
2025-07-12 08:37:56 [test-2048] Peer Connection Initiated with [AF_INET]52.198.164.18:443
2025-07-12 08:37:56 Options error: Unrecognized option or missing or extra parameter(s) in [PUSH-OPTIONS]:2: block-outside-dns (2.6.3)
2025-07-12 08:37:56 TUN/TAP device tun0 opened
2025-07-12 08:37:56 net_iface_mtu_set: mtu 1500 for tun0
2025-07-12 08:37:56 net_iface_up: set tun0 up
2025-07-12 08:37:56 net_addr_v4_add: 10.10.0.2/27 dev tun0
2025-07-12 08:37:56 Initialization Sequence Completed
$ aws ec2 describe-client-vpn-connections --client-vpn-endpoint-id ${cvpnendpoint}
AWSのお掃除
$ aws ec2 revoke-client-vpn-ingress --client-vpn-endpoint-id ${cvpnendpoint} --target-network-cidr 0.0.0.0/0 --revoke-all-groups
$ aws ec2 disassociate-client-vpn-target-network --client-vpn-endpoint-id ${cvpnendpoint} --association-id ${cvpnassoc}
$ aws ec2 delete-client-vpn-endpoint --client-vpn-endpoint-id ${cvpnendpoint}
$ aws acm delete-certificate --certificate-arn ${certificatearn}
Discussion