⛏️

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}
GitHubで編集を提案

Discussion