IBM Cloud Certificate Manager で Let's Encrypt 無料 SSL 証明書を取得する


# 概要
以下の3つのサービスを組み合わせることで Let's Encrypt 無料 SSL 証明書をシステマチックに取得・運用することができます。
その実際のやり方を書きます。

- IBM Cloud Certificate Manager
- IBM Cloud Functions
- IBM Cloud Internet Services

# 事前準備
## ドメイン準備

今回は `ibmjapan.com` を用意しました。

> [新規ドメインの登録 | IBM Cloud Docs](https://cloud.ibm.com/docs/dns?topic=dns-register-a-new-domain&locale=ja)

サブドメインとして `khayama.ibmjapan.com` を設定し、IBM Cloud Internet Services を名前解決に利用します。

>[IBM Cloud Internet Services (CIS) にサブドメインを登録する - Qiita](https://qiita.com/khayama/items/0d9e8d44a45d1f9a467e)

SSL 証明書を適用するためのサンプルウェブサイトとして、Cloud Foundry アプリ を使うために、カスタムドメインを Cloud Foundry 組織に登録しておきます。

![Kobito.9KOeja.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/aeda10c4-ba4d-a3f8-9c40-fa034575ebd1.png "Kobito.9KOeja.png")

## DNS レコードの登録
`khayama-letsencrypt` のホスト名でサンプルウェブサイトを立てられるように DNS レコードを登録します。
今回は `us-south` リージョンにサンプルウェブサイトを立てるので、以下のドキュメントにある `custom-domain.us-south.cf.cloud.ibm.com` を CNAME で登録します。

>[Adding and using a custom domain](https://cloud.ibm.com/docs/cloud-foundry-public?topic=cloud-foundry-public-custom-domains&locale=ja)

![Kobito.GEtXJS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/fdcc4bcd-fc7c-e5d2-d2e7-13284069ad71.png "Kobito.GEtXJS.png")

## サンプルウェブサイトの準備
以下の記事内容に沿って、サンプルウェブサイトを立てます。

>[IBM Cloud の Cloud Foundry を使って静的ウェブサイトをホスティングする - Qiita](https://qiita.com/khayama/items/c5ba86b8307e7813014a)

![Kobito.OiRsMa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/72c6c434-dc80-ff86-6709-608ad8ce2ed9.png "Kobito.OiRsMa.png")

これで http ベースでサンプルウェブサイトに名前解決してアクセスする、というところまで準備ができました。


# IBM Cloud Certificate Manager の作成
IBM Cloud のカタログから Certificate Manager を注文します。

![Kobito.ZSksAS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/b3b7b44b-4265-8927-0f57-239de2eb191b.png "Kobito.ZSksAS.png")
![Kobito.TA9Jb1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/cd47417a-1811-99e0-f678-be8a4bfeefcb.png "Kobito.TA9Jb1.png")

# Callback URL として IBM Cloud Functions を作成

Let's Encrypt のドメイン検証プロセスに関して応答するアクションを IBM Cloud Functions で実装します。
サンプルコードがあるので、その一部を改変して使います。

## サンプルコードのダウンロード
Github に公開されたファイルをダウンロードします。

```
git clone https://github.com/ibm-cloud-security/certificate-manager-domain-validation-cloud-function-sample.git
cd certificate-manager-domain-validation-cloud-function-sample
```

## IBM Cloud Internet Services の CRN を取得・置換
自アカウントにある IBM Cloud Internet Services のサービス名から検索して CLI で CRN を取得します。

```
export cisCrn=`ibmcloud resource service-instance -g Default CIS-Enterprise-Usage1 | grep crn | awk '{print $2}'`
echo $cisCrn
```

その後、さきほどダウンロードした IBM Cloud Functions 用のスクリプト内のコードを置換します。

```
sed -i -e "s|crn:v1:bluemix:public:internet-svcs:global:a/<YOUR_ACCOUNT_ID>:<YOUR_INSTANCE_ID>|$cisCrn|" main.js
```

さらに IBM Cloud Certificate Manager を作成したリージョン名について、スクリプト内のコードを置換します。
今回は東京リージョンに作成した IBM Cloud Certificate Manager を使うため、 `jp-tok` として置換します。

```
sed -i -e "s|<YOUR_INSTANCE_REGION>|jp-tok|" main.js
```

## IBM Cloud Functions で使用するパラメータの取得
IBM Cloud Functions に `iamApiKey` のパラメータを設定する必要がありますのでコマンドで作成します。 

```
ibmcloud iam api-key-create khayama-letsencrypt -d "for certification management" --file letsencryptKey.json
export $( echo $(cat letsencryptKey.json) | jq -r 'keys[] as $k | "export \($k)=\(.[$k])"')
export iamApiKey=$apikey
```

IBM Cloud Functions に `allowedCertificateManagerCRNs ` のパラメータを設定する必要がありますので、さきほど作成した IBM Cloud Certificate Manager のサービス名から検索して CLI で CRN を取得します。

```
allowedCertificateManagerCRN=`ibmcloud resource service-instance khayama-cm | grep crn | awk '{print $2}'`
export allowedCertificateManagerCRNs='{"'$allowedCertificateManagerCRN'":true}'
```

## IBM Cloud Functions アクションの作成
Github からダウンロードし、さきほど一部改変をおこなったスクリプトを元に IBM Cloud Functions アクションを作成します。

```
ibmcloud fn action create cert-mgr-khayama main.js --kind nodejs:10
ibmcloud fn action list
```

## IBM Cloud Functions で使用するパラメータの設定
さきほど変数として設定した `iamApiKey` , `allowedCertificateManagerCRNs` を IBM Cloud Functions アクションのパラメータとして設定します。

```
ibmcloud fn action update cert-mgr-khayama -p iamApiKey $iamApiKey -p allowedCertificateManagerCRNs $allowedCertificateManagerCRNs
ibmcloud fn action get cert-mgr-khayama parameters
```

## IBM Cloud Functions を Web アクションとして有効化
以下の画面にて「Web アクションとして有効化」にチェックを入れ、発行された URL をコピーします。

![Kobito.vjoKlH.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/bed66085-c289-9231-404d-163fb95d8e79.png "Kobito.vjoKlH.png")

# IBM Cloud Certificate Manager 通知チャネルの追加
証明書を注文する前に、通知チャネルを設定する必要があります。
さきほどコピーした IBM Cloud Functions の Web アクションの URL を「コールバック URL」として追加します。
「テスト接続」をおこない、正常に送信されることを確認します。

![Kobito.zMcJ7r.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/f94775cd-063e-3ec2-a6ea-f6604b1ba93a.png "Kobito.zMcJ7r.png")


# IBM Cloud Certificate Manager 証明書の注文
上記手順を踏んだあとは、以下の画面から「証明書の注文」がおこなえます。

![Kobito.cGobt5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/431d6b8b-a569-ab2e-604a-77f9648a5c66.png "Kobito.cGobt5.png")

「1次ドメイン・ネーム」は `*.khayama.ibmjapan.com` としてワイルドカード証明書を Let's Encrypt で取得する設定で注文します。

![Kobito.5dD9w5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/e81091df-70dc-c0eb-5084-ec17df530dee.png "Kobito.5dD9w5.png")

すると、一時的に「注文保留中」の画面になります。

![Kobito.Wm1oge.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/7870f42c-94d2-7406-b477-8ae1017daed4.png "Kobito.Wm1oge.png")

IBM Cloud Functions が正しく機能していれば、1分以内には注文が完了し、証明書が発行されたことがわかります。

![Kobito.NT12cn.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/0a33510d-898d-c65d-e4fb-6b760490af74.png "Kobito.NT12cn.png")

これで Let's Encrypt 無料 SSL 証明書の取得は完了です。


# 取得した SSL 証明書を Cloud Foundry 組織にアップロード
取得できた SSL 証明書をダウンロードし、 Cloud Foundry 組織に登録しておいたカスタムドメインに対して、アップロードします。

```
cd khayama-letsencrypt
ibmcloud account domain-cert-add khayama.ibmjapan.com -c khayama-letsencrypt.pem -i khayama-letsencrypt_intermediate.pem -k khayama-letsencrypt.key -o IBMCLOUDJPN -r us-south
```
![Kobito.W1apFg.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/151bc2d2-c2ba-43ae-12bc-c21ced168c54.png "Kobito.W1apFg.png")


# サンプルウェブサイトで https 暗号化通信を確認
SSL 証明書を適用するためのサンプルウェブサイトとして準備した Cloud Foundry アプリ の経路を確認すると、 SSL 証明書を利用した https 暗号化通信で保護されていることが確認できます。

![Kobito.EwSlBg.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/f4f376e3-13b2-5b29-ba4d-7d6f8b0c1fbc.png "Kobito.EwSlBg.png")

実際にアプリ URL にアクセスしてみても、ブラウザから Let's Encrypt の SSL 証明書が使われていることが確認できます。

![Kobito.1y7Aqi.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/0f005a5a-7dd7-650d-1d8b-30b92ec1af7b.png "Kobito.1y7Aqi.png")

# さいごに
IBM Cloud Certificate Manager を使って、Let's Encrypt 無料 SSL 証明書を取得できましたが、ドメイン検証プロセスの応答に必要な IBM Cloud Functions のエンドポイントを実装するところがミソでしたね。
IBM Cloud Internet Services の DNS 機能も組み合わせることで、証明書管理を自動化し、ウェブサイトをセキュアに運用し続けることができます。
ぜひ使ってみてください。

# 参考
- [Ordering certificates](https://cloud.ibm.com/docs/services/certificate-manager?topic=certificate-manager-ordering-certificates&locale=en)
- [Use IBM Cloud Certificate Manager to Obtain Let's Encrypt TLS Certificates for Your Public Domains | IBM](https://www.ibm.com/cloud/blog/use-ibm-cloud-certificate-manager-to-obtain-lets-encrypt-tls-certificates-for-your-public-domains)
- [GitHub - ibm-cloud-security/certificate-manager-domain-validation-cloud-function-sample](https://github.com/ibm-cloud-security/certificate-manager-domain-validation-cloud-function-sample)