IBM Cloud：Client VPN for VPCにおけるAPI CRL管理（VPN Server) 

# はじめに
インターネット環境に接続可能なクライアント端末からIBM Cloud VPC環境に接続してクラウドを利用する際は、仮想的な暗号通信を実現するClient VPN for VPC機能を利用します。本機能利用の際は、利用される証明書やCRL（Certificate Revocation List)と言われる証明書失効リストの運用が発生します。
特にCRLについては、クライアント証明書を開発者や利用者が長期に渡り利用する場合、棚卸しの意図も兼ねて定期的に更新申請を実施して頂く場合が多いと思います。また、逆に退職やプロジェクト離脱等により利用者が利用する必要性が無いにも関わらず、VPNサーバにアクセスできる環境を継続する事はセキュリテイリスクを存在させてしまいます。これらを回避する為に、CRLの更新を確実に行いVPN Serverへのアクセス権限を最適にコントロールする事が重要となります。本稿では、このCRLをAPIでアップデートする方法についてご紹介します。

# 本稿で利用する環境
クライアント端末を除く他の全ての機能をIBM Cloud上で構築します。これらの各コンポーネントの設定に関しては、Qiita上に多々存在する為、参考になる記事をご紹介しながら環境を準備します。
+ VPN Server（VPN通信を受信するサーバ）
+ Secrets Manager（シークレット情報の保管管理）
+ Trusted Profile（本機能の利用により、VPC内のサーバから簡易な認証でAPI機能を利用する）
+ Linuxサーバ（API アクセス用として利用）
+ VPNクライアント端末（OpenVPNクライアントソフトを利用

# Client VPN for VPC環境準備
[こちらの記事](https://qiita.com/takason/items/3d04e4e31daae4def1d7)を参考にClient VPN for VPC環境を構築し、お手元の端末にインストールしたOpenVPNクライアントソフトからVPN接続を実施します。
事前に作成したサーバ証明書や鍵ファイルは、Secrets Managerにて登録管理し、VPN Serverと連携します。
同じく作成したクライアント証明書と鍵ファイルは、VPNクライアント端末に保存して証明書ログイン認証に利用します。

# Trusted Profile環境準備
[こちらの記事](https://qiita.com/testnin2/items/860a3b00a2029e0a2594)を参考にTrusted Profile環境を準備します。通常API/CLI利用する際は、ID/PasswordやAPI Key等を用いた認証のやり取りを行いますが、本機能はセキュリティを維持した上で、これらの認証処理を簡略化します。VPC内の特定のサーバ間及びIBM Kuvernetes ServiceやRed Hat Openshift on IBM CloudのService AccountからTrusted Profile経由でアクセスする事で、認証のやり取りをせずにIBM CloudのIAM Tokenを取得します。

# CRLの作成
最初に、利用停止させたい端末の証明書のCRLを作成します。[こちらの記事](https://qiita.com/testnin2/items/946e8227486b470852e0)を参考に、CRL(crl.pem)を作成します。

最初に、利用停止対象証明書のSerial Numberを確認しておきます。
```:Serial Number確認
easyrsa3 % ./easyrsa show-cert client1 |grep -2 Serial
    Data:
        Version: 3 (0x2)
        Serial Number:
            fa:ab:bb:21:f1:e8:1f:a2:3b:d8:e3:ed:d5:00:96:d7
    Signature Algorithm: sha256WithRSAEncryption
```
以下のコマンドで、証明書の失効及びCRLの作成を実施します。
```:失効及びCRL作成
easyrsa3 % ./easyrsa revoke client1
easyrsa3 % ./easyrsa gen-crl
```
CRLファイル`crl.pem`に、失効したクライアントのSerial Numberが追加された事を確認します。
```:失効内容の確認
easyrsa3 % openssl crl -inform pem -in ./pki/crl.pem -text |grep -A2 Revoked
Revoked Certificates:
    Serial Number: FAABBB21F1E81FA23BD8E3EDD50096D7
        Revocation Date: Sep 22 02:32:56 2023 GMT
```
このpemファイルをAPIアクセス用のLinuxサーバに転送し、そこからVPN Server上のCRLファイルをTrusted Profileを活用してAPIで更新します。

# VPN Server APIによるCRLの更新
CRLファイルは、Secrets Managerでは無く、VPN ServerのAPIを利用してアップします。
VPN Server APIは[このIBM Cloud Doc](https://cloud.ibm.com/apidocs/vpc/latest#update-vpn-server)をご参照ください。`client_authentication`の中の`crl`にCRLをpem方式に変換しアップデートする事でCRLファイルの置き換えを行います。

`Update a VPN server`メソッドの中のRequest Bodyとして、`client_authentication`　 `VPNServerAuthenticationBYCertificatePrototype`を利用します。![スクリーンショット 2023-09-21 21.46.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354579/1ed7bb82-5e4b-cf45-11d0-bad9018d9c0b.png)

以下のコマンドでVPN SereverにCRLをアップロードします。
```:Curl
curl -H "If-Match:{etag}" -X PATCH "{base_url}/v1/vpn_servers/{vpn_server_id}?version=2023-09-12&generation=2" -H "Authorization: Bearer $iam_token" -d '{body}' 
```
:::note warn
Doc上ではIf-Match ヘッダーは必須になっておりませんが、指定をしないとエラーとなりました。重複更新を回避する為に上記の方式で既存のVPN ServerのETagを取得してIf-Matchに入れてPOSTしてください。
:::
{body}部分は以下となります。
```:body
{
	"client_authentication": [
		{
			"method": "certificate",
			"client_ca": "{client_ca_crn}",
			"crl": "{crl}"
		}
	]
}
```
`{base_url`は、[IBM Doc:Endopoint URLs](https://cloud.ibm.com/apidocs/vpc/latest#endpoint-url)から適切なものを選択します。
`{client_ca_crn}`や`{vpn_server_id}`は、以下　[List all VPN servers](https://cloud.ibm.com/apidocs/vpc/latest#list-vpn-servers)メソッドを利用してコマンド出力結果より確認します。
```:{client_ca_crn}
curl -X GET "{base_url}/v1/vpn_servers?version=2023-09-19&generation=2" -H "Authorization: Bearer $iam_token" |jq '.vpn_servers[]|.client_authentication'
```
```:{vpn_server_id}
curl -X GET "{base_url}/v1/vpn_servers?version=2023-09-19&generation=2" -H "Authorization: Bearer {iam_token}" |jq '.vpn_servers[]|.id'
```
また、`{vpn_server_id}`は、IBM Cloudコンソール上からも容易に確認する事ができます。![スクリーンショット 2023-09-21 22.00.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354579/45a2a9fd-d229-c1fa-ff8f-9a71117eee6a.png)

`{etag}`の取得方法は以下となります。
```:etag入手
curl -D - -X GET "{base_url}/v1/vpn_servers/{vpn_server_id}?version=2023-08-29&generation=2" -H "Authorization: Bearer {iam_token}" | grep etag
```


`{crl}`に関しては、先ほど作成した`crm.pem`がこのままでは使えないので改行`/n`が入った一行表示に以下のコマンドで変換します。
```:pem表現変換
awk 'NF {sub(/\r/, ""); printf "%s\\n",$0;}' crl.pem
```
:::note warn
上記`awk`コマンドで変換すると最後の`-----END X509 CRL-----\n`に`\n`が残ってしまいます。削除して、POSTしてください。
:::

私の環境では以下のCurlコマンドとなります。（iam_tokenはセキュリティ上そのままです）
```:投入したCurlコマンド
[root@sm-bastion ~]# curl -H "If-Match: W/c2717d16b0f2d5ce556eb891468a6921c01ab28d9ee8e16ec14e57b4d6c03f1a" -X PATCH "https://jp-osa.iaas.cloud.ibm.com/v1/vpn_servers/r034-6f888057-794f-4f46-8a14-ac8c4d05c179?version=2023-09-12&generation=2" -H "Authorization: Bearer $iam_token" -d '{"client_authentication":[{"method":"certificate","client_ca":{"crn":"crn:v1:bluemix:public:secrets-manager:jp-tok:a/cda7cf7172a34233a5edc160633ae793:3fb12463-4d6b-4029-8335-727bf02d0c8b:secret:069ce009-e5b8-8b47-1cd7-ab4bae912d0a"},"crl":"-----BEGIN X509 CRL-----\nMIIB0TCBugIBATANBgkqhkiG9w0BAQsFADAWMRQwEgYDVQQDDAtFYXN5LVJTQSBD\nQRcNMjMwOTI0MTQzODI3WhcNMjQwMzIyMTQzODI3WjAkMCICEQCgDx2+OuwjePfy\nN/nIv/XXFw0yMzA5MjQxNDM4MTRaoEowSDBGBgNVHSMEPzA9gBS7i1SS3/9Ee588\nMFNbSKkkCt9kraEapBgwFjEUMBIGA1UEAwwLRWFzeS1SU0EgQ0GCCQCThTSgDTs6\nTzANBgkqhkiG9w0BAQsFAAOCAQEANFjwOnIp97k+KLjAedr/ix8riT56pE1WRbL9\nYDuYbp2W3vX6qxRfBFY6+l1/uw4mSVirvQJ/UC3yM2fdZq3FS3+fuROYIaCwkX7E\nKY292mxDl3sdFPuJlGpOZwmjNmDMO2FEvlJwmCMVCERCZCz+HYmDrWKnoQUsOS/Q\nSj/4A9M5A/Jvwghc1Z/h4gs4yHtprAy6qUgw/rBut1VLqzlw0bgOVcjo+LXI/lj9\n/+TD4s1M4YK18dOUZg5Z4HIa3BeJLyhTXaYTVuKfNNqOlvcCfqdB09xBizCZ0nLi\npaOvbLILMHx3hhApezS48uYZDyfPTBAJagacvd1hTH/KocU4rA==\n-----END X509 CRL-----"}]}' |jq 
```
:::note warn
上記コマンド投入後"Please check whether the resource you are requesting exists."とエラーメッセージがでましたが、後述のように正常にファイルの更新、実際の端末の利用停止が確認出来ておりますので、表示上の不具合と考えられます
:::

# クライアント証明書廃止状況の確認
以下のコマンドで稼働しているVPN ServerからCRL内容を確認する事ができます。投入したCRLと同じである事が確認できます。
```:CRLの確認
[root@sm-bastion ~]# curl -X GET "https://jp-osa.iaas.cloud.ibm.com/v1/vpn_servers?version=2023-09-19&generation=2" -H "Authorization: Bearer $iam_token" |jq '.vpn_servers[]|.client_authentication'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  3517    0  3517    0     0   3314      0 --:--:--  0:00:01 --:--:--  3317
[
  {
    "client_ca": {
      "crn": "crn:v1:bluemix:public:secrets-manager:jp-tok:a/cda7cf7172a34233a5edc160633ae793:3fb12463-4d6b-4029-8335-727bf02d0c8b:secret:069ce009-e5b8-8b47-1cd7-ab4bae912d0a"
    },
    "crl": "-----BEGIN X509 CRL-----\nMIIB0TCBugIBATANBgkqhkiG9w0BAQsFADAWMRQwEgYDVQQDDAtFYXN5LVJTQSBD\nQRcNMjMwOTI0MTQzODI3WhcNMjQwMzIyMTQzODI3WjAkMCICEQCgDx2+OuwjePfy\nN/nIv/XXFw0yMzA5MjQxNDM4MTRaoEowSDBGBgNVHSMEPzA9gBS7i1SS3/9Ee588\nMFNbSKkkCt9kraEapBgwFjEUMBIGA1UEAwwLRWFzeS1SU0EgQ0GCCQCThTSgDTs6\nTzANBgkqhkiG9w0BAQsFAAOCAQEANFjwOnIp97k+KLjAedr/ix8riT56pE1WRbL9\nYDuYbp2W3vX6qxRfBFY6+l1/uw4mSVirvQJ/UC3yM2fdZq3FS3+fuROYIaCwkX7E\nKY292mxDl3sdFPuJlGpOZwmjNmDMO2FEvlJwmCMVCERCZCz+HYmDrWKnoQUsOS/Q\nSj/4A9M5A/Jvwghc1Z/h4gs4yHtprAy6qUgw/rBut1VLqzlw0bgOVcjo+LXI/lj9\n/+TD4s1M4YK18dOUZg5Z4HIa3BeJLyhTXaYTVuKfNNqOlvcCfqdB09xBizCZ0nLi\npaOvbLILMHx3hhApezS48uYZDyfPTBAJagacvd1hTH/KocU4rA==\n-----END X509 CRL-----",
    "method": "certificate"
  }
]
```
また、IBM Cloudコンソール上からVPN Server上のCRLファイルをダウンロードし、廃止対象のクライアントが登録されている事を確認する事ができます。
```:CRLの確認
easyrsa3 % cd ~/Downloads/                           
Downloads % openssl crl -inform pem -in sm-vpn-server_download.pem -text |grep -A4 Revoked 
Revoked Certificates:
    Serial Number: A00F1DBE3AEC2378F7F237F9C8BFF5D7
        Revocation Date: Sep 24 14:38:14 2023 GMT
    Signature Algorithm: sha256WithRSAEncryption
         34:58:f0:3a:72:29:f7:b9:3e:28:b8:c0:79:da:ff:8b:1f:2b:
```
念の為、失効対象のクライアント端末においてVPN接続ができない事も確認できました。

# まとめ
VPN Server上にCRLファイルをAPIで投稿、更新する方法をご紹介しました。ご紹介したAPIを自動化環境に組み込み運用負荷を軽減して頂ければと思います。ご紹介した[IBM Cloud Doc](https://cloud.ibm.com/apidocs/vpc/latest?code=java#update-vpn-server)には、他のAPIも紹介されてますので、ご自身の環境にあったものをご利用頂ければと思います。
他に、証明書を管理するSecrets ManagerをAPIで管理する[Client VPN for VPCにおけるAPI証明書管理 （Secrets Manager)](https://qiita.com/esakima/items/8bc43fe5b149a3d72e1c)編もご紹介してますので、ご参照頂ければ幸いです。

# 参考サイト
+ [IBM Cloud：Client to Site型VPNでVPC環境に接続する (Secrets Manager)](https://qiita.com/takason/items/3d04e4e31daae4def1d7)
+ [IBM Cloud:：Trusted Profileを使ったVSI for VPCからの安全なAPI/CLI呼び出し方法](https://qiita.com/testnin2/items/860a3b00a2029e0a2594)
+ [IBM Cloud：Client VPN for VPCにおいて特定ユーザーのクライアント証明書を失効させる方法](https://qiita.com/testnin2/items/946e8227486b470852e0)
+  [IBM Cloud Doc:VPN Server API](https://cloud.ibm.com/apidocs/vpc/latest#update-vpn-server)