CIS(IBM Cloud Internet Service)でmTLSを構成する(3) - クライアント証明書情報をHTTPヘッダに含める

#1. はじめに
この記事は、以下の記事の続編です。

- [CIS(IBM Cloud Internet Service)でmTLSを構成する(1) - 基本設定編](https://qiita.com/testnin2/items/f83b09c3404810b9bb27)
- [CIS(IBM Cloud Internet Service)でmTLSを構成する(2) - クライアント証明書をブラウザに設定](https://qiita.com/testnin2/items/07b0966485b4622d4140)

mTLSを単純に構成しただけではクライアント情報はOrigin Serverには含まれていないため、クライアント証明書の情報をCIS Edge Functions(Cloudflare Workers相当）を使って、クライアント証明書情報を付与する。

#2. mTLS構成直後のHTTPリクエストヘッダー一覧

[Apache+CGIで全てのHTTPリクエストヘッダを出力する](https://qiita.com/testnin2/items/480f395ca8ebbb4b71f8)を構成して、まずどのようなHTTPヘッダがOriginサーバーに渡ってきているかを確認してみる。
実質上、クライアントを判別する情報は、`CF_CONNECTING_IP`や`X_FORWARDED_FOR`に含まれるクライアントのIPアドレスぐらいしかない。
<img width="1279" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/bfe8089b-df72-37a4-bcbc-dfab3f733472.png">

#3. CIS Edge Functionsを使ってクラアイント証明書をHTTPヘッダに付与する。


##3-1. Actionの追加
<img width="1279" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/f751f943-669f-a6b3-9137-944084750890.png">
Action nameは任意。コードは、[こちら](https://developers.cloudflare.com/access/service-auth/mtls-headers/)のサンプルコードがそのまま動くので、そのまま貼り付ける。

```javascript:サンプルスコード
addEventListener("fetch", event => {
    event.respondWith(handleRequest(event.request));
});

function getHeaders(headers) {
    let heads = {};
    for (let h of headers.entries()) {
        heads[h[0]] = h[1];
    }
    return heads;
}

function handleRequest(request) {
    let headers = {};
    if (request.cf && request.cf.tlsClientAuth.certPresented) {
        const tlsHeaders = {
            'X-CERT-ISSUER-DN': request.cf.tlsClientAuth.certIssuerDN,
            'X-CERT-SUBJECT-DN': request.cf.tlsClientAuth.certSubjectDN,
            'X-CERT-ISSUER-DN-L': request.cf.tlsClientAuth.certIssuerDNLegacy,
            'X-CERT-SUBJECT-DN-L': request.cf.tlsClientAuth.certSubjectDNLegacy,
            'X-CERT-SERIAL': request.cf.tlsClientAuth.certSerial,
            'X-CERT-FINGER': request.cf.tlsClientAuth.certFingerprintSHA1,
            'X-CERT-VERIFY': request.cf.tlsClientAuth.certVerified,
            'X-CERT-NOTBE': request.cf.tlsClientAuth.certNotBefore,
            'X-CERT-NOTAF': request.cf.tlsClientAuth.certNotAfter
        };
        Object.assign(headers, tlsHeaders);
    }
    Object.assign(headers, getHeaders(request.headers));
    return fetch(request, {
        headers: new Headers(headers)
    });
}
```

<img width="1279" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/d305449b-2ac2-b475-c917-ab58763172ad.png">

##3-2 Triggerの追加
<img width="1279" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/51bb499c-ebfc-8c35-0623-eca20d9a3bbc.png">
<img width="615" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/1b6afb88-5559-7153-01de-477f0b78c3af.png">

#4. テスト

CA証明書およびクライアント証明書の情報がHTTPリクエストヘッダに登録されてOriginサーバーに渡ってきていることがわかる。
<img width="1279" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/e445138d-a647-0d2a-a9bf-3a3022beb28c.png">

参考までに、CA証明書とクライアント証明書作成時のCSR情報を再掲する。

```json:ca-csr.json
{
  "CN": "Access Testing CA",
  "key": {
    "algo": "rsa",
    "size": 4096
  },
  "names": [
    {
      "C": "US",
      "L": "Austin",
      "O": "Access Testing",
      "OU": "TX",
      "ST": "Texas"
    }
  ]
}
```
```json:client-csr.json
{
  "CN": "James Royal",
  "hosts": [""],
  "key": {
    "algo": "rsa",
    "size": 4096
  },
  "names": [
    {
      "C": "US",
      "L": "Austin",
      "O": "Access",
      "OU": "Access Admins",
      "ST": "Texas"
    }
  ]
}
```