AWS Client VPNクライアント証明書の管理手順を整理してみた
AWS Client VPNは2種類のクライアント認証を提供します。
- Active Directory 認証
- 証明書を使用した相互認証
本ブログでは、OpenVPN easy-rsaを使う、相互認証におけるクライアント証明書の基本的な管理方法について紹介します。
ポイント
- VPNエンドポイント作成時の証明書指定
- 相互認証のVPNエンドポイントを作成する場合、ACMにインポートしたサーバー証明書とクライアント証明書を指定
- サーバーとクライアントの証明書が同じCAから発行される場合、VPN作成時のクライアント証明書のARNには、サーバー証明書のARNを指定できる。クライアント証明書のACMインポートは不要
- クライアント証明書の発行
- 利用者毎に個別の証明書を発行できる
- 発行した証明書とVPNエンドポイントやACMとの関連付けは不要
- クライアント証明書の失効
- CA で失効で続きを行い、クライアント証明書失効リスト(CRL)を更新
- CRLをクライアントVPNエンドポイントにインポート
検証環境
- OS : Mac
- AWS CLI : 1系
- OpenVPN easy-rsa : 3.0.7
クライアントVPNの初期構築
まずは、「クライアント認証と認可 - AWS Client VPN」にある証明書の発行手順をなぞりながら、クライアントVPNの最低限の設定を済ませます。
1. OpenVPN easy-rsaをインストール
認証機関 (CA)を構築するサーバーにOpenVPN easy-rsaをインストールします。
Git でソースコードを取得することも可能ですが、次のURLからリリースされたアーカイブをダウンロードすることもできます。
Releases · OpenVPN/easy-rsa · GitHub
$ wget https://github.com/OpenVPN/easy-rsa/releases/download/v3.0.7/EasyRSA-3.0.7.tgz $ tar zxfv EasyRSA-3.0.7.tgz $ cd EasyRSA-3.0.7
2. PKI環境を初期化
新しい PKI 環境を初期化します。
$ ./easyrsa init-pki
3. 認証機関 (CA) を構築
新しい認証機関 (CA) を構築します。
$ ./easyrsa build-ca nopass
pki/ca.crt
がこのCAのルート証明書です。
認証局(Issuer)が自分自身(Subject)に対して自己署名しています。
$ openssl x509 -text -noout -in pki/ca.crt Certificate: Data: Version: 3 (0x2) Serial Number: ba:f6:6e:cf:78:74:62:2a Signature Algorithm: sha256WithRSAEncryption Issuer: CN=Easy-RSA CA Validity Not Before: May 18 06:48:58 2020 GMT Not After : May 16 06:48:58 2030 GMT Subject: CN=Easy-RSA CA ...
デフォルト設定では、有効期間がほぼ10年(3650日)あります。
4. サーバーとクライアント向けに証明書とキーを生成
サーバー向け
$ ./easyrsa build-server-full server nopass
クライアント向け
$ ./easyrsa build-client-full client1.domain.tld nopass
5. 主要ファイルをカスタムフォルダにコピー
サーバー証明書とキー、およびクライアント証明書とキーをカスタムフォルダにコピーしてから、カスタムフォルダに移動します。
$ mkdir ~/custom_folder/ $ cp pki/ca.crt ~/custom_folder/ $ cp pki/issued/server.crt ~/custom_folder/ $ cp pki/private/server.key ~/custom_folder/ $ cp pki/issued/client1.domain.tld.crt ~/custom_folder $ cp pki/private/client1.domain.tld.key ~/custom_folder/ $ cd ~/custom_folder/
ここまでは公式ドキュメントと同じです。
6. ACMに証明書をインポート
クライアント VPNエンドポイントを作成する前に、ACMに証明書を登録します。
ドキュメントに記載されているように、「クライアント証明書の認証機関 (発行者) がサーバー証明書の認証機関 (発行者) と異なる場合にのみ、クライアント証明書を ACM にアップロードする必要があります。」
今回の証明書の作成手順では、クライアント証明書とサーバー証明書で同じ認証機関を利用しているため、サーバー証明書だけをACMに登録します。
$ aws acm import-certificate \ --certificate file://server.crt \ --private-key file://server.key \ --certificate-chain file://ca.crt \ --region region { "CertificateArn": "arn:aws:acm:..." }
なお、証明書のCA情報は認証局鍵識別子(Authority Key Identifier)から確認することも可能です。
- server.crt
- client1.domain.tld.crt
の「X509v3 Authority Key Identifier」が同じであることを確認してください。
... X509v3 Authority Key Identifier: keyid:D9:FD:3C:41:44:1B:11:37:B2:9D:39:2E:64:82:A1:6A:57:CC:07:33 DirName:/CN=Easy-RSA CA serial:BA:F6:6E:CF:78:74:62:2A ...
openssl
コマンドで確認したルート証明書(pki/ca.crt
)のSerial Numberとも一致していますね。
7. クライアントVPNエンドポイントの作成
クライアント VPN エンドポイントを作成します。
「認証オプション」で「相互認証の使用」をチェックし、「認証情報」の
- サーバー証明書 ARN
- クライアント証明書 ARN
の両方に、先程アップロードしたサーバー証明書のARNを指定します。
8. VPN接続確認
VPNをプロビジョン後は、client1.domain.tld のキー・証明書でVPN接続できることを確認してください。
証明書の発行
全員が同じクライアント証明書を使い回すことも可能ですが、利用者ごとにクライアント証明書を発行して細かくアクセスコントロールするのが無難でしょう。
新規にクライアント証明書を発行するには、ユニークなエンティティ名を指定して easyrsa build-client-full
を実行します。
$ cd /path/to/easy-rsa/easyrsa3 $ ./easyrsa build-client-full client2.domain.tld nopass ...[snip] The Subject's Distinguished Name is as follows commonName :ASN.1 12:'client2.domain.tld' Certificate is to be certified until Aug 20 13:48:09 2022 GMT (825 days) Write out database with 1 new entries Data Base Updated
あとは、出力された
- (証明書)pki/issued/client2.domain.tld.crt
- (キー)pki/private/client2.domain.tld.key
を利用者に展開します。
新規証明書とAWS環境との関連付けは不要です。 証明書の発行はCA内の操作に閉じています。
証明書の更新
証明書には期限が存在します。期限を迎える前に、証明書を再発行しましょう。
証明書を更新するには $ ./easyrsa renew エンティティ nopass
を実行します。
エンティティ「client1.domain.tld」の証明書を更新する手順は以下の通りです。
# 証明書を更新 $ ./easyrsa renew client1.domain.tld nopass Note: using Easy-RSA configuration from: ./vars Using SSL: openssl OpenSSL 1.0.2t 10 Sep 2019 Please confirm you wish to renew the certificate with the following subject: subject= commonName = client1.domain.tld Type the word 'yes' to continue, or any other input to abort. Continue with renew: yes Generating a RSA private key ... The Subject's Distinguished Name is as follows commonName :ASN.1 12:'client1.domain.tld' Certificate is to be certified until Jun 22 12:20:25 2021 GMT (400 days) Write out database with 1 new entries Data Base Updated $
証明書の期限が400日後に延長されています。
出力された
- pki/issued/client1.domain.tld.crt
- pki/private/client1.domain.tld.key
をユーザーに展開します。
証明書の更新発行とAWS環境との関連付けは不要です。 証明書の発行はCA内の操作に閉じています。
証明書の期限管理
- 証明書の有効期間(
EASYRSA_CERT_EXPIRE
。デフォルトは 825日) - 期限の何日前から証明書を更新できるか(
EASYRSA_CERT_RENEW
。デフォルトは30日)
は設定ファイルで変更できます。
vars.example
を vars
にリネームし、該当行をコメントアウト、及び、値を変更して下さい。
... # In how many days should certificates expire? set_var EASYRSA_CERT_EXPIRE 400 ... # How many days before its expiration date a certificate is allowed to be # renewed? set_var EASYRSA_CERT_RENEW 30 ...
更新可能日よりも前に証明書を更新しようとすると、エラーが発生します。
次はEASYRSA_CERT_RENEW
が30日にも関わらず、証明書が30日以上有効な状態で更新しようとした場合のエラーです。
$ ./easyrsa renew client1.domain.tld nopass Note: using Easy-RSA configuration from: ./vars Using SSL: openssl OpenSSL 1.0.2t 10 Sep 2019 Please confirm you wish to renew the certificate with the following subject: subject= commonName = client1.domain.tld Type the word 'yes' to continue, or any other input to abort. Continue with renew: yes Easy-RSA error: Certificate expires in more than 30 days. Renewal not allowed.
証明書の更新切れチェック
easy-rsa に更新間近の証明書を簡単にチェックする仕組みはないようなので、証明書一覧を取得し、各証明書の期限をチェックするような処理を定期実行したほうが良いでしょう。
証明書を失効
キーが漏洩したり、クライアントVPNを利用しなくなったユーザーに対しては、証明書を失効させます。
CAの証明書失効リスト(Certificate Revocation List;CRL)を更新し、VPNエンドポイントとCRLを関連付けます。
証明書を失効
CAに対して証明書を失効させ、CRLを更新します。
エンティティ「client2.domain.tld」の証明書を失効させる手順は以下の通りです。
# 証明書を失効させる $ ./easyrsa revoke client2.domain.tld Note: using Easy-RSA configuration from: ./vars Using SSL: openssl OpenSSL 1.0.2t 10 Sep 2019 Please confirm you wish to revoke the certificate with the following subject: subject= commonName = client2.domain.tld Type the word 'yes' to continue, or any other input to abort. Continue with revocation: yes Using configuration from /Users/jsmith/EasyRSA-3.0.7/pki/easy-rsa-90112.wfP0sa/tmp.jrFGwa Revoking Certificate 0DACEEA5C11A6948B3C6E9AC3502CFA5. Data Base Updated IMPORTANT!!! Revocation was successful. You must run gen-crl and upload a CRL to your infrastructure in order to prevent the revoked cert from being accepted. # 証明書失効リスト(CRL)を更新 $ ./easyrsa gen-crl Note: using Easy-RSA configuration from: ./vars Using SSL: openssl OpenSSL 1.0.2t 10 Sep 2019 Using configuration from /Users/jsmith/EasyRSA-3.0.7/pki/easy-rsa-90205.2q2Aak/tmp.poeCn8 An updated CRL has been created. CRL file: /Users/jsmith/EasyRSA-3.0.7/pki/crl.pem
失効した証明書は、CAに問い合わせても見つかりません。
# 失効した証明書はCAに問い合わせてもみつからない $ ./easyrsa show-cert client2.domain.tld Using SSL: openssl OpenSSL 1.0.2t 10 Sep 2019 Easy-RSA error: No such cert file with a basename of 'client2.domain.tld' is present. Expected to find this file at: /Users/jsmith/EasyRSA-3.0.7/pki/issued/client2.domain.tld.crt # 失効した証明書はインデックスファイルで「V(alid)」ではなく「R(evoked)」扱い $ cat pki/index.txt V 220821064937Z 7172155BBEEEC5CEAE9A8A6CA5B0501B unknown /CN=server V 220821070413Z C069FFDE8575A1C98F109594C442E06D unknown /CN=client1.domain.tld R 220821070604Z 200518111534Z 0DACEEA5C11A6948B3C6E9AC3502CFA5 unknown /CN=client2.domain.tld
CRLをクライアントVPNエンドポイントに関連付け
更新したCRLをクライアントVPNエンドポイントに関連付けます。
$ aws ec2 import-client-vpn-client-certificate-revocation-list \ --certificate-revocation-list file:///Users/jsmith/EasyRSA-3.0.7/pki/crl.pem \ --client-vpn-endpoint-id cvpn-endpoint-XXX { "Return": true }
失効した証明書では接続できなくなっていることを確認してください。
クライアンとサーバーの認証機関が同じ場合、クライアント証明書をACMにアップロードしなくて良い理由
ドキュメント「クライアント認証と認可」には次の記載があります。
クライアント証明書の認証機関 (発行者) がサーバー証明書の認証機関 (発行者) と異なる場合にのみ、クライアント証明書を ACM にアップロードする必要があります。
この理由を考えます。
証明書は認証局が秘密鍵でデジタル署名します。 証明書を受け取ると、証明書を発行したCAのルート証明書(に含まれる公開鍵)を利用して署名を検証します。
相互認証なクライアントVPNエンドポイントの作成時には、ACMにインポートした証明書のARNを指定します。 今回ようなプライベートCAの場合、ACMへのインポート時に指定する証明書チェーンがルート証明書にあたります。
公式ドキュメントのGetting Startedチュートリアルでは、easy-rsaで新規に認証局を作成し、次のコマンドで証明書をインポートしています。
$ aws acm import-certificate \ --certificate file://client1.domain.tld.crt \ # 証明書 --private-key file://client1.domain.tld.key \ # プライベートキー --certificate-chain file://ca.crt \ # 証明書チェーン:ルート証明書 --region region
クライアント証明書の検証で必要になるのは、証明書チェーンで指定したルート証明書だけであり、クライアントの
- 証明書
- プライベートキー
は利用しません。
そのため、クライアントVPNエンドポイント作成時の[クライアント証明書 ARN] には、ルート証明書が同じサーバー証明書のARNを指定しても動作します。クライアント証明書をACMにアップロードする必要はありません。
冒頭の「クライアント証明書の認証機関 (発行者) がサーバー証明書の認証機関 (発行者) と異なる場合にのみ、クライアント証明書を ACM にアップロードする必要があります。」につながります。
まとめ
OpenVPNのeasy-rsaを利用したAWS Client VPN向けのクライアント証明書の管理方法を紹介しました。
ポイントは、CAのルート証明書がVPNエンドポイントに登録されている限り、CAに閉じた操作でクライアント証明書を発行できることです。
OpenVPN easy-rsaを利用すると、OpenSSLを直接利用するよりもはるかに簡単に証明書を管理できるものの、証明書の発行・失効・期限切れチェック・更新などの操作は、それなりに手間です。 証明書の数が増えると、運用負荷へのインパクトも大きいです。
AWS Client VPNは
- Active Directory認証
- 証明書を使用した相互認証(本ブログで紹介)
の2種類のクライアント認証に対応しています。
運用をイメージしながら、適切な認証方式をご採用ください。