マルチクラウド環境におけるサーバ証明書の運用　Let's Encrypt/AWS/Azure

# はじめに
本記事は、マルチクラウド環境におけるサーバ証明書の運用についての記事になります。

マルチクラウド環境でサーバ証明書を使用している場合は、環境によって対応手順が異なります。また、ワイルドカードでサーバ証明書を取得していている場合は、留意事項があるケースが多いので注意が必要です。

本記事では実際に運用での経験を踏まえて、サーバ証明書の運用時のポイント等について簡潔にまとめています。

## サーバ証明書の選び方
### Let's Encrypt
Let's Encryptを使用する場合のメリットとデメリットは以下になります。

- メリット
 - サーバ証明書の費用がかからない

- デメリット
 - サポートなし
 - 無料で取得できるためフィッシングサイトなどの悪用が多い
 - 90日に1回手動更新が必要（更新切れのリスクや保守コスト） 

**Let's Encryptを選択する場合は、用途に合わせて使用しましょう。**

### 有料のサーバ証明書を安く購入する方法
有料のサーバ証明書を購入するにあたり、安く購入したいときは入手先によって直販より代理店で購入した方が安い場合があります。

なお、その情報は直販に聞いても知らないこともあるため、自分で代理店を調べる必要があります。探し方としては、直販のWebサイトによっては代理店の確認ができます。

### ワイルドカードを要件とするサーバ証明書の選び方
ワイルドカードを要件としてサーバ証明書を購入する際は注意が必要です。
例えば、レンタルサーバのサービスでサーバ証明書を発行する場合は、サービスによっては単一ドメインのみの対応で、ワイルドカードに対応していない場合があります。

**つまり、ワイルドカードに対応していないサービスでサーバ証明書を購入する場合、単一ドメインで発行するサーバ証明書の必要分の代金が発生します。**

ワイルドカードを要件とする場合は、ワイルドカードに対応していることを確認しましょう。

また、ワイルドカードでサーバ証明書を発行するにあたり、CSR作成時は注意しましょう。
例えば、ジオトラストでは以下の**注意事項**を公開しています。

>ワイルドカードの証明書はサブドメインの異なるコモンネームでも利用できる証明書です。
>ドメインの前へ「*」アスタリスクを指定したコモンネームでCSRを生成してください。

>例：*.geotrust.co.jp

- [ワイルドカード証明書の申請時の注意はありますか](https://knowledge.digicert.com/ja/jp/solution/SO23010.html)

### サーバ証明書購入時に確認すべきこと
サーバ証明書発行業者に、**有効期間内の発行済み証明書について再発行できること**を可能かどうか事前に確認しておくとよいです。

例えば、2014年4月7日に発表されたOpenSSL暗号ソフトウェアライブラリにおける深刻な脆弱性「Heartbleed Bug」の様な場合は、OpenSSLのバージョンを最新のバージョンまでアップグレードし、新しいCSRでSSLサーバ証明書を再発行する必要があります。

## サーバ証明書の発行
### Let's Encrypt 
Let's Encryptでサーバ証明書を発行する場合は、certbotをインストールして発行します。Standaloneプラグインを使用する際は、以下のコマンドを実行します。Webサーバーを停止させずにサーバ証明書を取得したい場合は、Webrootプラグインを使用します。

`# certbot certonly -a standalone -d ＜URL＞ --email ＜メールアドレス＞`

ワイルドカードの場合は、以下のコマンドを実行します。

`# certbot certonly --manual -d ‘*.＜URL＞’ -d ＜URL＞ -m ‘＜メールアドレス＞’ --agree-tos --preferred-challenges dns-01 --server https://acme-v02.api.letsencrypt.org/directory`

また、ワイルドカードで発行する際はDNS-01 チャレンジによる認証が必要になるため、_acme-challenge.<YOUR_DOMAIN>の値としてTXTレコードを設定します。

**AWSのAmazon Route 53などでTXTレコードを更新する際は、反映されるまでラグがあるので、TXTレコード設定後続けてcertbotの処理を行うと、認証に失敗する場合があります。**

- [チャレンジのタイプ](https://letsencrypt.org/ja/docs/challenge-types/)

### AWS
AWSはACM（AWS Certificate Manager）でサーバ証明書の発行ができます。料金は無料です。

ACMで取得したサーバ証明書の有効期限は、発行日から**13か月後**になり、有効期限の60日前に更新プロセスが開始されます。

**ACM使用時の留意事項としてワイルドカードの場合は、手動更新が必要になります。自動更新されないため、注意が必要です。**

- [AWS Certificate Manager のよくある質問](https://aws.amazon.com/jp/certificate-manager/faqs/)
- [ACM 証明書の自動更新が失敗するのはなぜですか ?](https://aws.amazon.com/jp/premiumsupport/knowledge-center/certificate-fails-to-auto-renew/)
- [ワイルドカードとサブドメインを使用する E メール検証の証明書の場合、ACM が管理する更新プロセスはどのように行われますか?](https://aws.amazon.com/jp/premiumsupport/knowledge-center/acm-certificate-renewal/)

### Microsoft Azure
Microsoft Azureは、APP Service 証明書を使用してアプリケーションのHTTPS化を行うことができます。

- [App Service の価格](https://azure.microsoft.com/ja-jp/pricing/details/app-service/linux/)

Microsoft Azure PortalでAPP Service証明書の自動更新が「オン」になっている場合は、自動的に更新が行われます。

**APP Service証明書の自動更新が「オン」の場合は、基本的に対応不要ですが、使用しない場合は無駄に課金されるので注意が必要です。**

### レンタルサーバのサーバ証明書
お名前.comなどのレンタルサーバによっては、自動的にサーバ証明書を更新してくれるサービスもあります。自動的に更新されるため、対応は不要です。料金も無料だったりします。仕様が不明な場合はレンタルサーバのサポートに確認すれば教えてくれます。

**レンタルサーバでサーバ証明書を利用する場合は導入時にきちんと確認しましょう。**

## サーバ証明書の運用
### サーバ証明書の更新切れ対策
サーバ証明書の更新切れを防ぐために、メールの通知設定はきちんと行いましょう。

例えば、AWSなどアカウント登録時に普段使用しないメールアドレスを指定すると、更新切れに気づくことができません。

その様な状況を考慮し、AWSの場合は代替のメールアドレスで宛先を追加して対策ができます。また、メールアドレスは個人の担当者のメールアドレスではなく、メーリングリストなどにしておくと良いでしょう。

<img width="982" alt="スクリーンショット 2019-10-31 23.26.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/88c1bd48-9d06-8259-33eb-b519c55a49bc.png">

- [AWS アカウントの管理](https://docs.aws.amazon.com/ja_jp/awsaccountbilling/latest/aboutv2/manage-account-payment.html#account-contacts)

更に念を入れる場合は、サーバ証明書の期限をチェックし、期限が近くなったら通知する仕組みを作るのも有効な一手です。AWSの場合CLIのコマンドを使用すれば実現できます。

### サーバ証明書更新時の確認
サーバ証明書更新後は、Webサイトにアクセスしてサーバ証明書の有効期限が更新されたことだではなく、サーバ証明書の検証エラーが出てないことも確認することをお勧めします。

例として、WebサービスとiPhoneアプリ及びAndroidアプリを提供するサービスにおいて、サーバ証明書更新時に中間証明書の登録漏れなどの不備があった場合、WebブラウザやiPhoneアプリはアクセスできるけど、Androidアプリのみアククセスできないという事象が発生します。

実際に経験しましたが当事象が発生すると、Androidアプリが真っ白になり、何も操作ができなくなりました。デバッグについてもWebブラウザやiPhoneアプリからはアクセスができ、Androidのみ当事象が発生している状況だったので調査にも少し時間を要しました。これについてはAndroid DevelopersのDocsより、[HTTPS と SSL を使用したセキュリティ](https://developer.android.com/training/articles/security-ssl?hl=ja)が参考になります。以下はドキュメントからの引用です。

>興味深い点として、パソコン用ブラウザでこのサーバーにアクセスしても、ほとんどの場合、「未知の CA」や「自己署名サーバー証明書」の場合に発生するようなエラーは発生しません。エラーが発生しないのは、パソコン用ブラウザの多くが、信頼できる中間 CA を時間をかけてキャッシュしているためです。ブラウザがあるサイトにアクセスして中間 CA に関する情報を得ると、次回からは証明書チェーン内にその中間 CA が存在していなくてもエラーにはなりません。

**よって、サーバ証明書更新後はサーバ証明書が適切に更新されたことを確認しましょう。**

簡単にできるサーバ証明書の確認方法について以下に記載します。
opensslコマンドと[SSL Server Test](https://www.ssllabs.com/ssltest/)による二つの方法があります。

- opensslコマンド  
`# openssl s_client -connect ＜URL＞:443`

上記opensslコマンドを実行し、出力結果に**verify error**が出力される場合は、サーバ証明書の検証に失敗しているため、エラーが発生しています。また、出力結果がdepth=0となっているため、中間証明書がないことが分かります。以下はサーバ証明書に中間証明書が登録されていないときの出力例になります。サーバ証明書はLet's Encryptを使用しています。

```console
CONNECTED(00000005)
depth=0 CN = *.test.com
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 CN = *.test.com
verify error:num=21:unable to verify the first certificate
verify return:1
---
Certificate chain
 0 s:/CN=*.test.com
   i:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
---

```

サーバ証明書に不備がない場合は以下の様に出力されます。

```console
CONNECTED(00000005)
depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
verify return:1
depth=0 CN = *.test.com
verify return:1
---
Certificate chain
 0 s:/CN=*.test.com
   i:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
 1 s:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
   i:/O=Digital Signature Trust Co./CN=DST Root CA X3
---
Server certificate
```

- SSL Server Test

上記と同じく、サーバ証明書に中間証明書が登録されていないときに、SSL Server Testで検証すると、以下の様に**Chain issues**に**incomplete**と出力されます。

<img width="1135" alt="スクリーンショット 2019-10-31 19.52.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/f603e85f-4280-7058-79b7-f701198ed8f0.png">


サーバ証明書に不備がない場合は以下の様に**Chain issues**に**None**と出力されます。

<img width="1131" alt="スクリーンショット 2019-10-31 23.10.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/9152acfe-d6da-b6a4-df9b-1452a7ff0445.png">

なお、中間証明書とルート証明書を合わせて登録した場合は、以下のよう**Chain issues**に**Contains anchor**と出力されます。エラーではないのでopensslコマンドでは検知できないため、SSL Server Testで見おとさないように注意しましょう。

<img width="1124" alt="スクリーンショット 2019-11-13 17.23.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/a11d1905-1e01-ea8c-71dc-79d6b9fb1220.png">

## その他
クラウド環境のロードバランサーを使用し、ロードバランサーにサーバ証明書を登録して、クライアントとロードバランサー間でHTTPS通信を行っている場合の話です。

HTTPとHTTPSのリスナーが存在し、基本的にはHTTPSで通信を行うが、HTTPのリクエスト時にリダイレクトしたいというケースもあると思います。

Webサーバだけの話なら、Webサーバの機能でリダイレクトで処理を行うことができますが、クラウド環境のロードバランサーの仕様によっては対応してないこともあります。

その様な場合は、Webサーバの機能でリダイレクトを行うか、ロードバランサーのHTTPリスナーを削除するなどの対応が必要です。

本記事では、ロードバランサー配下にWebサーバを配置し、Webサーバの機能でリダイレクトを行う場合の方法について記載します。WebサーバはNginxを使用します。

### Nginxのリダイレクト設定
例として、Oracle Cloudの場合はロードバランサーのリダイレクトに対応していないため、Webサーバの機能でリダイレクトする必要があります。クライアントからのHTTP通信をリダイレクトするためには、nginxの設定ファイル（serverディレクティブ）に以下の記述を行うことで実現できます。

```conf
 if ($http_x_forwarded_proto != https) {
          rewrite ^(.*)$ https://＜URL＞$1 permanent;
        }
```

**以下リダイレクト設定の考慮点です。**

- X-Forwarded-Proto リクエストヘッダー 
X-Forwarded-Proto リクエストヘッダーを使用することで、クライアントがロードバランサーへの接続に使用したプロトコル (HTTP または HTTPS) を識別し、リダイレクトループを防ぎます。X-Forwarded-Proto リクエストヘッダーを付けない場合はリダイレクトループが発生します。

- ロードバランサーのヘルスチェック
Oracle Cloudのヘルスチェック設定（デフォルト）は、HTTPプロトコルになっています。よって、リダイレクト設定を行うと、ステータスコード301を返すため、ヘルスチェックに失敗しロードバランサーから切り離されます。そのため、ヘルスチェックの設定をTCPプロトコルに変更します。

### 2020年TLS1.2問題
2020年に主要ブラウザのEdge及びInternet Explorer（IE）11、Safari、Firefox、ChromeでTLS1.0及び1.1のプロトコルがデフォルトで無効化されます。

つまり、2020年にブラウザからHTTPS通信でWebサイトにアクセスが行われると、Webサイト側でTLS1.2以上に対応していない場合は、Webサイトにアクセスした際に警告が表示されアクセスがブロックされます。何も知らないユーザからすると正常にアクセスできなくなるため、ユーザ影響がかなり大きことが想定されます。詳細は[Google Security Blog](https://security.googleblog.com/2019/10/chrome-ui-for-deprecating-legacy-tls.html)より確認できます。

**よって、Webサイトを提供する場合は、TLS1.2以上に対応していることを確認しましょう。**

# おわりに
サーバ証明書の更新切れに注意し、これからもHTTPSと上手に付き合っていきましょう。