ACMのPrivate CAを利用した場合のAmazon API GatewayのmTLS構成を試してみた。

#はじめに

先週、こちらのふたつの記事でAmazon API GatewayのmTLS認証について検証・検討しました。

- [Amazon API GatewayでmTLSを試してみた。(1/2)](https://qiita.com/horit0123/items/8eb45bfcef6b848971a4)
- [Amazon API GatewayでmTLSを試してみた。(2/2)](https://qiita.com/horit0123/items/d37cb939c7dc31f3c2fa)

前回、記事が長くなってに分割しましたが、その中でも確認したいことが書けなかったので、その後続の記事として **ACM(AWS Certificate Manager)のPrivate CA( Certificate Authority:認証局）** を利用したAmazon API GatewayのmTLS構成について書きたいと思います。なお、興味本位でAWS ACM Private CAを今回は利用していますが、opensslコマンドを利用して以下を実施いただいても同じ内容かと思います。  

- 仮想のルートCAの秘密鍵、自己証明書(ルートCA証明書）
- 仮想の中間CAの秘密鍵、中間CA証明書（ルートCAによる署名）
- クライアントの秘密鍵、クライアント証明書（中間CAによる署名）

#サマリ
- 中間認証局がクライアント証明書発行している場合は、ルート認証局までのチェーンをトラストストアに登録する必要がある（各CAの公開鍵証明書）
- 複数の認証局をサポートしたい場合はその認証局とそのチェーン（ルート認証局までに登場する中間認証局）をトラストストアに登録すればよい
- トラストストア内は重複した認証局の証明書の登録はできないので、既に登録されている認証局の証明書は登録時にエラーとなる。



#AWS Certificate ManagerのPrivate CAとは
ACM Private CA は、オンプレミスCA の運用にかかる投資コストや保守コストなしに、ルート CA や下位 CA を含むプライベート認証機関 (CA) 階層を作成できます。リリース当初はルートCAのサポートがありませんでしたが、可能になっています。Private CAを利用するとX.509 証明書を発行できます。
X.509 証明書を発行およびデプロイする AWS サービスは 二つあります。

-ACM Private CA 
-AWS Certificate Manager 

どちらを利用するかは、利用ニーズによります。
## ACM Private CA
組織内でのプライベートな使用を目的として証明書を利用する場合にACM Private CA を使用すると、独自の認証局、および、その 階層を作成できます。独自の認証局をマネージドで構築することで、運用の負荷を軽減でき、かつ、社内・組織内で利用可能な独自の証明書の発行が可能とンります。この証明を、Public、つまり、インターネット等で利用してもルート認証局が公開され、かつ、認められた認証局ではないため信頼はされない証明書となります。

- 任意のサブジェクト名で証明書を作成可能
- 任意の有効期限で証明書を作成可能
- サポートされている任意のプライベートキーアルゴリズムとキー長を使用可能
- サポートされている任意の署名アルゴリズムを使用可能


## AWS Certificate Manager
ACMで発行する証明書は、AWS Elastic Load Balancing、Amazon CloudFront、Amazon API Gateway、およびその他の 統合サービスにデプロイできます。ACM が提供するパブリック証明書 または ACM にインポートされた証明書を上記の統合サービスに適用でき、証明書に指定されたドメイン名でTLS通信を可能にします。


#当記事で利用する証明書は3種類
当記事では以下の3州類の証明書を作成・利用します。

- （Private)ACM Private CAで発行するルート認証局ならびに中間認証局の証明書。クライアント証明書の署名検証用
- （Private)ACM Private CAでで発行した中間認証局の証明書で証明されたクライアント証明書。mTLS用
- （Public)ACMで発行されたサーバ証明書。TSL通信用




#A.一つ目の中間認証局の環境構築

環境構築は以下の順序で実施します。

1. ルート認証局の作成(ACMPrivate CA)
2. 中間認証局の作成(ACM Private CA)
3. APIの作成
4. カスタムドメインの有効化(ACM)
5. mTLSの有効化
6. クライアント証明書の作成(ACM Private CA)
7. 接続
 
## 1. ACMのPrivate CAを利用したルート認証局の構築

### ルート認証局の作成
ACMを利用することで僅か数分でルート認証局(中間認証局も）が構築可能です。今回は以下の設定でAWS マネジメントコンソールから構築しました。
※ルート認証局を当文書内ではルートCA/中間認証局を中間CAと表記することもあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535037/d3f46034-9727-846e-4976-bd795f74c4b6.png)

### ルート認証局に証明書のインストール
前回の記事ではopensslコマンドで

- 秘密キーの作成
- （CSR作成は省略して証明書作成時に入力）
- 自己署名証明書の作成

を実施しましたが今回はAWS マネジメントコンソールから証明書の生成& ルート認証局へのインポートを実施しました。（前回の記事では、自己署名の証明書をつくっただけで、認証局を運用したわけではありません）
個別に秘密鍵の生成、CSRの作成は必要なく、CSRに入力する情報を画面から入力する形でした。有効期限は1か月にしておきました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535037/0b5df1c6-b277-9ed8-ff18-a0284a423b3f.png)


以上で、Private CAのルート認証局が立ち上がりました。Private CAで構築したルート認証局とAPI Gatewayの組み合わせで設定を確認するだけであれば、ここまでで十分です。ただ、今回は中間認証局（証明書のチェーン）も合わせて試したかったので先ほど構築したルート認証局をルートとした中間認証局も構築します

## 2. ACMのPrivate CAを利用した中間認証局の構築
### 中間認証局の作成

こちらは、ルート認証局を構築した手順とほぼ同様の手順ですが、CA TypeがSubordinate（下位）となっている点が違いです。添付の画像を確認してみてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535037/a81051c5-00ad-0e7f-0cac-6a2bffbc7e7f.png)

続いて、中間認証局の証明書の作成とインポートです。こちらの証明書は先ほどのルート認証局用の証明書とは異なります。どこが異なるかというと、自己署名、つまり自分自身の秘密鍵を使って署名をするのではなく、ルート認証局の秘密鍵を使って証明書に署名する部分がルート認証局の署名時と異なる部分です。つまり、ルート認証局の証明書・秘密鍵が必要になるため、ルートを指定します。以下の画像でParent private CAでルート認証局のIDを選択していることを確認してください。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535037/beda1abb-ec33-8222-66d4-1451c123a797.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535037/84057689-18ec-4aab-6221-1b4f3ce29c68.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535037/9c3d83e1-bfa3-340f-b193-7f5f43d54aff.png)

今までの手順で作成した認証局です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535037/e87de3fc-3856-be87-5ba9-69d4ddaa1692.png)



なお、上位の認証局（今回の場合、ルート認証局）のIDが分からない場合は、以下の画像にある通り、対象の認証局をACMの一覧から表示してStatusをご確認ください。ARN(Amazon Resource Names)の中にIDがあります。


### 中間認証局の作成2
さて、本来であれば、ここまででクライアント証明書の作成に進むわけですが、ここで気になったのが、中間認証局を複数立ち上げた場合、つまり、クライアント証明書を複数の業者に依頼して発行した場合等はどういう構成になるのか？ということで、別のCAを構築することにしました。こちらのCAの階層としてはという階層構成で、先ほど作った認証局とは、ルート認証局のみが共通しているものとなります

ルート認証局-＞中間認証局->中間認証局
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535037/fd67108a-4f41-4c86-f0ba-92cc4d3003a2.png)


## 3.APIの作成 & 4. カスタムドメインの有効化(ACM)
APIの作成および、カスタムドメインの有効化設定は先日ご紹介した[Amazon API GatewayでmTLSを試してみた。(1/2)](https://qiita.com/horit0123/items/8eb45bfcef6b848971a4)の記事の通りです。今回は省略します。前回、無意識のうちにRoute 53へのレコード登録をしていたようですが、今回確認した結果、やはり、カスタムドメインの有効化(ACMでのPublicな証明書の作成&API Gatewayのカスタムドメイン登録）に加えRoute53のレコード登録が必要でした。

## 5.mTLSの有効化
さて、カスタムドメインの登録まで実施し、https://カスタムドメイン名/ で接続できたことを確認した後で、mTLSの有効化設定をAPI Gatewayのカスタムドメインの設定の中で実施します。

### CA証明書の入手
　mTLSの登録に必要なものは、認証局の公開鍵証明書です。今回は、ACM Private CAで認証局の証明書を作成したため、ACM Private CAから証明書をダウンロードし登録します。

CA証明書はAWSマネジメントコンソールまたはCLIで抽出可能です。今回はコンソールからリンクをクリックしてbodyおよびchainの**両方**を取得しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535037/d4f40b75-b4ba-e0a1-fa2a-c08f30fb751f.png)

### CA証明書の登録
入手した中間認証局のCA証明書をS3バケットに格納し、API Gatewayのカスタムドメイン設定を更新しました。すると以下のエラーメッセージが設定後、数分で表示されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535037/448e26ab-e8a7-a234-016b-8438cff812c9.png)

詳細なエラーは次の通りです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535037/f4c80d93-598d-23da-13ea-a22ccba0fbb3.png)

原因は、中間認証局の証明書のみを登録したからです。

では、中間認証局のCA証明書と、そのチェーンを連結した証明書を登録したいと思います。参考になる方法としては[こちらの手順9](https://aws.amazon.com/jp/blogs/compute/introducing-mutual-tls-authentication-for-amazon-api-gateway/)をご確認下さい。
ルート認証局までのチェーンを登録することで、以下の画像の通り、正常にMutualTLSが有効化されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535037/b583fb4a-275e-e335-96e6-18c40ba81ecd.png)


## 6. クライアント証明書の作成(ACM Private CA)
サーバサイドの準備が整ったところで、クライアント証明書と秘密鍵を入手したいと思います。
今回は、中間認証局をACM Private CAで構築したので、その中間認証局に証明書の作成を依頼し、そこから、秘密鍵を取り出したいと思います。

### ACMによるPrivte Certificateの作成
Private Certificateなので、インターネットで正規の証明書として利用することはできないということを改めて述べつつ、解説します。

まずは、ACMの画面から証明書発行のリクエストを行います。そこでは、Private CAを構築していると、以下の画面にあるようにRequest a private certificateを選択することができます。Private certificateを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535037/b3b53210-76ba-79ba-0b9c-8084a6f896fa.png)

その後、認証局を選択します。今回は中間認証局を利用してクライアント証明書を作るので、以下の画像にある通り、Typeはsubordinateとなっておりルート認証局を選択していないことが分かります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535037/3ada04c1-fe07-07b8-f5e8-08120521152a.png)

そして、適当にドメイン名を設定することで証明書の作成要求ができます。ACMで証明書発行する場合、ここはドメイン形式で入れる必要があります。任意のフォーマットは使えません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535037/959145b2-ece6-624c-b5fe-9c7cc94c3fc7.png)

そして、作成完了。

### ACMからクライアント証明書と秘密鍵をExport

ACM上で証明書を作成したら、AWS CLIまたは、AWSマネジメントコンソールを利用してクライアント証明書、その秘密鍵、チェーンをExportすることが可能です。Exportする際には秘密鍵を暗号化するためのパスフレーズの入力が求められます。パスフレーズを入力しExportを実行すると以下のような形で証明書、チェーン、秘密鍵（暗号化されたもの）が表示されますので、保存してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535037/81afb73d-b25a-ecbb-117b-84836d8cf767.png)


## 7. 接続
接続には前回と同様にcurlコマンドを利用します。以下のような形で --passを指定してあげることで、暗号化された秘密鍵も利用可能です。パスワードは証明書Export時にしていしたものを指定してください。

```
curl -v --key  client1.key --cert client1.pem --pass password  https://api.xxx.xxx/hoge/auth
```




#B.二つ目の中間認証局の環境構築
ここまでは、単体の中間認証局に対する検証でした。
ここからは**複数の認証局**をサポートするか試したいと思います。ケースとしては、クライアント証明書の発行を複数の認証局が担当するケースを想像してみました。
## 今回の認証局の構成イメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535037/d696bc01-9983-55aa-4192-460eba278444.png)

先ほどまでは、この図で言うところのintermediateCA **0** が発行したクライアント証明書を利用して接続しました。その際には、intermediateCA **0** とrootCAの証明書をtruststore(S3のオブジェクト）に格納しました。API GatewayのトラストストアはAmazon S3の1つのオブジェクトを指定（オプションでVersionも指定可能）する形です。今回はintermeidiateCA **0**をすでに登録してあるので、IntermediateCA **2** が発行したクライアント証明書**も**利用できるように構成したいと思います。

ちなみにintermediateCA **2** （3階層目）は上図にあるとおりrootCA->intermediateCA **1** ->IintermediateCA **2**というチェーンになっています。

Private CAの構築は先ほど構築した手順の繰り返しとなりますので省略します。ここでは、API Gatewayへの登録方法についてご説明します。

## 二つ目の中間認証局によるクライアント証明書の発行と接続
この場合に必要な手順は次の通りです。
### 1. 未登録のCA証明書を入手しAPI Gatewayのトラストストアに登録
トラストストアに未登録のintermediateCA1とintermediateCA2の証明書を入手します。今回は、中間認証局intermediateCA2がクライアント証明書を発行するため、intermediateCA2の証明書に加えて、その上位の認証局であるintermediateCA1の証明書が必要となります。さらに上位のrootCAの証明書も本来は必要ですが既にトラストストア内に登録済みのため今回は不要です。入手方法は先ほど「mTLSの有効化手順で記載したCA証明書の入手」をご確認ください。


この時、私は最初、intermediateCA2のチェーン（ルート認証局までのすべてのチェーン）を登録したのですが、**エラーメッセージが登録時に表示** され登録できませんでした。重複したCA認証局の証明書は登録できないようです。したがって、rootCAの証明書は今回はすでに追加されているので追加しませんでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535037/4f825ff6-8eb8-5103-018a-f8646746e8b5.png)

### 2. API Gatewayのトラストストア設定を更新
S3のVersioning機能を有効化している場合に上記1で上書きした場合は、そのバージョンIDをAPI Gatewayのカスタムドメイン内のmTLSの設定で指定して更新します。また、別名のオブジェクトをS3バケットに格納した場合はパスを変更して登録してください。

上記を実施することでintermediateCA *2* が発行したクライアント証明書による接続が可能となります。