Azure Application Gateway でクライアント証明書認証を行う (自己署名証明書、失効手順)

Azure Application Gateway v2 にて TLS 相互認証が GA しました。相互認証は TLS 証明書ベースで双方向認証を可能にするもので、クライアント、サーバーの双方を認証することができます。サーバー証明書はもともと既定で使われておりましたが、この機能追加により、リスナーごとのレベルでクライアント証明書による認証が可能となりました。

https://azure.microsoft.com/en-us/updates/general-availability-application-gateway-mutual-authentication/

以下に相互認証の設定手順はありますが、まずは自己署名証明書による簡易な検証を行いたいといった要望はあるかと思います。また、特定のクライアント証明書を失効させたいといった要望もあるかと思いましたので、それぞれの手順を以下に記載します。

https://docs.microsoft.com/ja-jp/azure/application-gateway/mutual-authentication-portal

## 前提

- Application Gateway v2 SKU (Standard/WAF どちらでも可) を作成済みであること
- バックエンド、HTTP 設定、HTTPS のリスナーを作成済みでアクセス可能となっていること

証明書の設定手順は以下にもまとめておりますのでご参照ください。

https://qiita.com/Isato-Hiyama/items/90bd4f33e42385a9db1e

## 1. クライアント証明書の作成 (自己署名証明書)

### Windows の手順 (Powershell)
Powershell にて以下を実施し、Application Gateway へアップロードする CA 証明書を作成します。 (クライアント CA [CER 形式])

"Subject" を CA の名前に変えれば他はそのままで問題ないです。この "Subject" 部分がクライアント証明書選択時に Issuer として表示されます。

```
$cert = New-SelfSignedCertificate -Type Custom -KeySpec Signature `
-Subject "CAName" -KeyExportPolicy Exportable `
-HashAlgorithm sha256 -KeyLength 2048 `
-TextExtension @("2.5.29.19={text}CA=true") `
-CertStoreLocation "Cert:\CurrentUser\My" -KeyUsageProperty Sign -KeyUsage CertSign
```

クライアントコンピューターにインストールする証明書の作成します。 (クライアント証明書 [PFX])
"Subject" の "CN" をホスト名、ユーザー名やアドレスなどに変更します。この "Subject" 部分がクライアント証明書選択時にクライアント名として表示されます。

```
New-SelfSignedCertificate -Type Custom -KeySpec Signature `
-Subject "CN=ClientName" -KeyExportPolicy Exportable `
-HashAlgorithm sha256 -KeyLength 2048 `
-CertStoreLocation "Cert:\CurrentUser\My" `
-Signer $cert -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.2")
```

Application Gateway にアップロードするための CA 証明書は Widows キー+R を押して、certmgr.msc を実行し、Personal > Certificates 内にある上記で作成した CA 証明書を右クリックして Export すると入手できます。ファイルの形式は **Base-64** を選択し、その他の設定は既定値とします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/9b2e15ce-9f04-3832-6261-c6d1345a1294.png)


### Linux の手順 (WSL でも問題なし)
openssl コマンドにて CA 証明書を作成します。
各属性は要件に応じて入れます。Common Name はクライアント証明書選択時に Issuer として表示されます。

```
openssl req -newkey rsa:4096 -keyform PEM -keyout clientca.key -x509 -days 3650 -outform PEM -out clientca.cer

例：
Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:CA test1
Email Address []:
```

クライアントの秘密鍵を作成します。
```
openssl genrsa -out client.key 4096
```

クライアントの CSR を作成します。
各属性は要件に応じて入れます。Common Name はクライアント証明書選択時にクライアント名として表示されます。
```
openssl req -new -key client.key -out client1.req

例：
Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:testuser1
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
```

CA 証明書にて署名します。
```
openssl x509 -req -in client1.req -CA clientca.cer -CAkey clientca.key -set_serial 101 -extensions client -days 365 -outform PEM -out client1.cer
```

Windows 端末に Import できるよう p12 形式に変換します。
```
openssl pkcs12 -export -inkey client.key -in client1.cer -out client1.p12
```

出来上がった p12 形式のファイルを Windows 端末でダブルクリックし、Import します。パスワード以外はすべて既定で問題ないです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/312da214-c21c-e753-0ab0-b99e9d27b662.png)

## 2. Application Gateway の設定

Application Gateway の画面から "SSL 設定 > SSL プロファイル" をクリックし、SSL プロファイル名を入力して、"新しい証明書のアップロード" をクリックします。**ポータルにプレビューの記載がありますが表記の更新が遅れているだけです (2022/03/14)**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/d6eae875-c9eb-395c-2f4b-03c7dd277f9f.png)

証明書名を入力し、ファイルの選択から先ほど作成した CA 証明書を選択し、"OK" をクリックして、SSL プロファイルを保存します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/d63cd456-47ce-a694-9701-aac329b4c750.png)

Application Gateway のリスナーの画面からクライアント証明書認証を設定するリスナーを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/bdea3333-7277-983f-c504-46111b5b9a04.png)

リスナーの画面から "SSL プロファイルを有効にす" にチェックを入れて、先ほど作成した SSL プロファイルを選択して、保存します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/97c977d0-e9b7-30bd-6bd7-4879f432a3d7.png)


## 3. アクセス確認

Application Gateway 用の URL にアクセスすると以下の様に証明書の選択画面が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/42bdd553-1d41-3642-d0c0-84d9fb0384ac.png)

証明書を選択して OK をクリックすると Web ページが表示されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/a812ec39-5dc3-6363-3c91-14a78b0d450f.png)

キャンセルを押した場合は、以下の様に Bad Request となりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/0c37a89e-899a-38c5-64b5-70dd8085db01.png)

## 4. クライアント証明書の失効
クライアント証明書の一般的な管理方法としては、以下の 2 つがあります。
1. ルート証明書 (CA) を使用してチームまたは組織レベルでアクセスを管理する
2. クライアント証明書の拇印等のユニークな属性を使用して、個々のユーザー単位で細かいアクセス制御を行う

OCSP を使用して失効する機能が追加されています。(20240409 追記)

https://learn.microsoft.com/ja-jp/azure/application-gateway/mutual-authentication-overview?tabs=powershell#certificate-revocation

### 4-1. ルート証明書 (CA) の削除

1.2 と同じ手順を実施して、CA 証明書とクライアント証明書の組み合わせをもう 1 セットつくり、Application Gateway にアップロードします。クライアント証明書もクライアントに Import します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/4e4e8c55-6680-d16f-bebf-c90181b1a774.png)

ブラウザを一度閉じて Application Gateway にアクセスすると、追加したクライアント証明書が表示 [CA test2/testuser3] されることを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/db527c9c-2758-8937-63e8-5c0549bac31d.png)

追加したクライアント証明書により Web ページにアクセスできることを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/8df36dd7-51d8-cd36-f628-a611dd103ccd.png)

Application Gateway の SSL プロファイルから追加した CA 証明書 [cacert2] を削除し、保存します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/3fe9568b-fcb8-102d-6cb2-a29f64296cc5.png)

ブラウザを一度閉じて再度アクセスすると、[CA test2/testuser3] がなくなっていることが確認できます。
以下の画面では他の有効なクライアント証明書があるため、画面に表示されておりますが、通常、有効なクライアント証明書がない場合、Bad Request (Status 400) となります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/14a637a8-275a-7155-07c6-e7508a098cf5.png)


### 4-2. WAF の利用 (拇印の指定)

Application Gateway の相互認証では以下のようなサーバー変数が利用可能です。

https://docs.microsoft.com/ja-jp/azure/application-gateway/rewrite-http-headers-url#mutual-authentication-server-variables

|変数名|説明|
|:---|:--|
|client_certificate|確立された SSL 接続用のクライアント証明書 (PEM 形式)。|
|client_certificate_end_date	|クライアント証明書の終了日。|
|client_certificate_fingerprint	|確立された SSL 接続用のクライアント証明書の SHA1 フィンガープリント。|
|client_certificate_issuer	|確立された SSL 接続用のクライアント証明書の "発行者の DN" 文字列。|
|client_certificate_serial	|確立された SSL 接続用のクライアント証明書のシリアル番号。|
|client_certificate_start_date	|クライアント証明書の開始日。|
|client_certificate_subject	|確立された SSL 接続のクライアント証明書の "サブジェクトの DN" 文字列。|
|client_certificate_verification	|クライアント証明書検証の結果: SUCCESS、FAILED:reason、証明書が存在しない場合は NONE。|

client_certificate_fingerprint は証明書のフィンガープリント (拇印) となるので、この値をヘッダーとして書き換えることで Web Application Firewall にて特定のクライアント証明書からのアクセスを評価して、拒否することができます。

クライアント証明書の拇印は Widows キー+R を押して、certmgr.msc を実行し、Personal > Certificates 内の証明書をダブルクリックすると確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/39243c05-55e2-22a0-5411-2ec69266fa07.png)


Application Gateway にて書き換えセットの追加をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/662ea254-bf49-4dd5-6e64-61c7bd0b247c.png)

書き換えセットの名前を入力し、紐づけるルーティング規則にチェックをいれて、次へをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/447ae774-df1f-edf5-855a-184633ecf026.png)

Application Gateway にて、以下のようにカスタムの要求ヘッダー [fingerprint] に、サーバー変数 [client_certificate_fingerprint] を設定し、OK をクリックして、ルールを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/cab13e56-6288-dcb0-56e4-e80320a2c8cf.png)

WAF ポリシーを作成して、Application Gateway に関連付けを行います。

https://docs.microsoft.com/ja-jp/azure/web-application-firewall/ag/create-waf-policy-ag

モードは防止モードにします。ログ出力だけで問題ない場合、検出モードを利用します。WAF ポリシーの以下の画面で切り替え& 確認可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/0f1e2c2d-c2c2-0ad9-ea96-c94a18ed39a1.png)

WAF ポリシーの画面にて、カスタムルールの追加をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/b217e9b1-8e0a-dc76-368b-8f902f173d3d.png)

カスタムルール名、優先度を設定し、一致変数 [RequestHeaders]、ヘッダー名 [fingerprint]、一致する値 [クライアント証明書の拇印]、結果 [トラフィックを拒否する] を設定し、ルールを追加して保存します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/db844337-ec23-0724-22ba-4cdb62e4364f.png)

ブラウザを一度閉じて Application Gateway にアクセスし、失効させたクライアント証明書を指定て、OK をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/5ae1be79-6752-93d6-ac7b-f1b0575c6f89.png)

Status 403 となり、アクセスが拒否されたことを確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/8d9bf9a6-ffb6-a1f1-cf4f-fcc0d7860b47.png)


### 4-3. 書き換え規則の利用 (拇印の指定)
4-2 と同じような手順ですが、こちらの手順では WAF は利用せず、書き換え規則にて無効なパスに書き換え、Not Found (Status 404) とするような手順にしています。
WAF の場合は Application Gateway の方で拒否でき、かつ管理も容易となりますが、何らかの理由で WAF が利用できない場合は、この手順でも要件を満たせる可能性はあるかと思います。
 
書き換え規則にて条件つを追加し、サーバー変数 [client_certificate_fingerprint] 、演算子 [等しい (=)]、一致させるパターン [クライアント証明書の拇印]、書き換えの種類 [URL]、アクションタイプ [設定]、URL パスの値 [任意の無効なパス] を設定し、OK をクリックして、ルールセットを更新 (または作成) します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/905c2511-e3c9-534d-af97-0e5bdb19e66c.png)

ブラウザを一度閉じて Application Gateway にアクセスし、失効させたクライアント証明書を指定て、OK をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/5ae1be79-6752-93d6-ac7b-f1b0575c6f89.png)

無効なパスに書き換えが行われ、Not Found (Status 404) となることが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/2e0dcd7c-f5e6-8dff-ac31-4785da095422.png)

## 5. 不要となった CA 証明書の削除
ポータルからゴミ箱マークで CA 証明書を削除した場合、SSL プロファイルとの関連付けは外れますが、Application Gateway 内には CA 証明書が残っている状態となります。
本番環境では誤操作等を防ぐためにも不要な証明書は削除することが望ましいです。

ポータルから証明書の削除はできませんので、以下の Powershell で削除する必要があります。

Powershell を管理者権限で起動し、以下のコマンドでログインします。
```
Connect-AzAccount

複数サブスクリプションがある場合、サブスクリプションを指定します。
Set-AzContext -SubscriptionId <サブスクリプション ID>
```

Application Gateway の情報を変数に格納します。
```
$appgw = Get-AzApplicationGateway -Name "アプリケーションゲートウェイ名" -ResourceGroupName "リソースグループ名"
```

CA 証明書を削除します。
```
Remove-AzApplicationGatewayTrustedClientCertificate -Name "CA 証明書名" -ApplicationGateway $appgw
```

設定を反映します。
```
Set-AzApplicationGateway -ApplicationGateway $appgw  
```