Oracle Cloud LoadBalancer を Let's Encrypt で無料SSL化

# はじめに

Oracle Cloud Infrastructure には、Load Balancer サービスがあります。Load Balancerを使うことで、リクエストトラフィックを複数のサーバに負荷分散を行うことが出来、可用性やパフォーマンスの向上を期待することが出来ます。

今回は、無料SSL証明書発行サービスである、「[Let’s Encrypt](https://letsencrypt.org/)」 を使用して、Load Balancer で SSLオフロードを実施する手順を確認していきます。

なお、Let's Encrypt は、90日で expire されるため、定期的に証明書の更新を行う必要があります。
余談ですが、Oracle Cloud で提供予定の サーバレスサービスである Fn を使用すると、サーバレスで自動更新を行うことが出来るのではと考えております。(FnがGAされたらやりたい)



# 前提

お名前.com などで購入したドメインを OCI DNS で管理していること
https://qiita.com/sugimount/items/7d14ca7185d87c9763ff

OCI の LoadBalancer を構成していること
https://qiita.com/sugimount/items/6d060c03aa02837749c7



# Let's Encrypt によるSSL証明書発行方法について

Let's Encrypt で SSL証明書を発行するときに、ドメイン名を指定して発行しますが、指定したドメインを間違いなく管理していることを証明する必要があります。ドメインを管理していることを証明するための方法として、現在は以下の3パターンが存在しています。



- HTTP-01

  Let's Encryptの認証局からワンタイムトークンを発行してもらい、Webサーバに認証用ファイルを設置する。 認証局からHTTP(80番ポート)でアクセスしてもらい、ワンタイムトークンと認証用ファイルとの妥当性を検証する。

- TLS-SNI-01

  HTTP-01と同じ方法だが、HTTPS(443ポート)を使用する。

- DNS-01

  Let's Encryptの認証局から発行してもらったワンタイムトークンを対象ドメインのTXTレコードに登録することで検証する。



HTTP-01 や TLS-SNI-01は、SSL証明書を発行したいドメインに紐づくWebサーバをPublicで公開し、認証局からアクセスさせる必要があるため、サーバを管理する必要があるのが面倒です。今回は、DNS-01 の方式を使用して、SSL証明書を発行します。



# Let's EncryptでSSL証明書を入手

Let's Encrypt で推奨されている、[Certbot](https://certbot.eff.org/) と呼ばれている Client を使用して、SSL証明書を手に入れます。
certbot の [Document](https://certbot.eff.org/lets-encrypt/ubuntubionic-other) に記載されている通り、パッケージマネージャから certbot の Installをします。Ubuntu 18.04 を使用した手順のため、各環境に合わせて変更してください。

```
sudo apt-get update
sudo apt-get install software-properties-common -y
sudo add-apt-repository universe
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install certbot -y
```



certbot コマンドを使用して、SSL証明書を取得します

```
sudo certbot certonly \
  --manual \
  --domain test.sugi.tokyo \
  --email sugi.mount@gmail.com \
  --agree-tos \
  --manual-public-ip-logging-ok \
  --preferred-challenges dns
```



コマンドを実行すると、ワンタイムトークンが画面に出力されるため、これを確認します 
**まだ、Enterは押さずに保留しておくこと！**

```
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name
_acme-challenge.test.sugi.tokyo with the following value:

z1_sKShkULrVd_Y4CJZYkSCoKcpY_hH33oZAT8hIxnI

Before continuing, verify the record is deployed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue
```



OCI DNS 上で `_acme-challenge.test.sugi.tokyo` の txt レコードを作成し、かつ、値を `z1_sKShkULrVd_Y4CJZYkSCoKcpY_hH33oZAT8hIxnI` にして作成します。これによって、指定したドメインを正しく管理出来ることを Let's Encrypt 側へ証明できるということです。

oci cli で TXTレコードを作成します。そのためにJSONファイルでパラメータを生成します

```
string trim '
[
  {
    "domain": "_acme-challenge.test.sugi.tokyo",
    "is-protected": false,
    "rdata": "z1_sKShkULrVd_Y4CJZYkSCoKcpY_hH33oZAT8hIxnI",
    "rtype": "TXT",
    "ttl": 30
  }
]
' > ~/workdir/acme.test.sugi.tokyo.json
```



TXTレコードを作成します。

```
oci dns record domain patch --zone-name-or-id "sugi.tokyo" --domain "_acme-challenge.test.sugi.tokyo" --items file://~/workdir/acme.test.sugi.tokyo.json
```



certbot コマンドで保留にしていた Enter を押します。
以下実行例。 Confratulations! と表示されていればＯＫです。

```
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name
_acme-challenge.test.sugi.tokyo with the following value:

z1_sKShkULrVd_Y4CJZYkSCoKcpY_hH33oZAT8hIxnI

Before continuing, verify the record is deployed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue
Waiting for verification...
Cleaning up challenges

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:  <=========== Confratulations! と表示されていればＯＫ
   /etc/letsencrypt/live/test.sugi.tokyo/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/test.sugi.tokyo/privkey.pem
   Your cert will expire on 2019-05-10. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot
   again. To non-interactively renew *all* of your certificates, run
   "certbot renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le
          
```



以下のディレクトリに証明書が生成されています

```
# ls -la /etc/letsencrypt/archive/test.sugi.tokyo
total 16
drwxr-xr-x 1 root root  512 Feb 10 05:56 .
drwx------ 1 root root  512 Feb 10 05:56 ..
-rw-r--r-- 1 root root 1915 Feb 10 05:56 cert1.pem       # SSL/TLS サーバ証明書 (公開鍵を含む)
-rw-r--r-- 1 root root 1647 Feb 10 05:56 chain1.pem      # 中間証明書
-rw-r--r-- 1 root root 3562 Feb 10 05:56 fullchain1.pem  # サーバ証明書と中間証明書が結合されたもの
-rw-r--r-- 1 root root 1704 Feb 10 05:56 privkey1.pem    # 秘密鍵
```



しかし、上記のファイルに含まれてる数字の `1` は、証明書発行の度にカウントアップしていくため、自動化するときに不便です。
これに対応するために、以下のディレクトリを参照すると便利に扱うことが出来ます。
シンボリックリンクが張られているため、SSL証明書を更新してもファイル名を変更せずに扱うことが出来ます。

```
# ls -la /etc/letsencrypt/live/test.sugi.tokyo/
total 4
drwxr-xr-x 1 root root 512 Feb 10 05:56 .
drwx------ 1 root root 512 Feb 10 05:56 ..
-rw-r--r-- 1 root root 692 Feb 10 05:56 README
lrwxrwxrwx 1 root root  39 Feb 10 05:56 cert.pem -> ../../archive/test.sugi.tokyo/cert1.pem
lrwxrwxrwx 1 root root  40 Feb 10 05:56 chain.pem -> ../../archive/test.sugi.tokyo/chain1.pem
lrwxrwxrwx 1 root root  44 Feb 10 05:56 fullchain.pem -> ../../archive/test.sugi.tokyo/fullchain1.pem
lrwxrwxrwx 1 root root  42 Feb 10 05:56 privkey.pem -> ../../archive/test.sugi.tokyo/privkey1.pem
```



# OCI LoadBalancer に SSL証明書をアップロード

root 権限でしか触れないため、sugi ユーザの homedir に一時的にコピー

```
mkdir /home/sugi/ssl/
cp -p /etc/letsencrypt/live/test.sugi.tokyo/* /home/sugi/ssl/
```



Certificate を作成

```
set lb_ocid (oci lb load-balancer list --display-name "httplb1" | jq -r '.data[0].id')
oci lb certificate create --certificate-name "lets_encrypt" --load-balancer-id $lb_ocid --private-key-file /home/sugi/ssl/privkey.pem --public-certificate-file /home/sugi/ssl/cert.pem
```



LBのListerにHTTPSを追加

```
oci lb listener create --default-backend-set-name "httplb1_backend1" --port 443 --protocol "HTTP" --name "httplb1_listener1_https" --load-balancer-id $lb_ocid --ssl-certificate-name "lets_encrypt"
```



# アクセステスト

https://test.sugi.tokyo/

ブラウザでアクセスして、正常に確認することができました



# 参考URL

Oracle CloudのLBにSSL証明書を適用する
https://www.s-style.co.jp/blog/2019/02/3418/

Let's Encrypt
https://letsencrypt.org/

CertbotでDNSによる認証(DNS-01)で無料のSSL/TLS証明書を取得する
https://blog.jicoman.info/2017/04/certbot_dns_01/

Let'ss Encrypt CA証明書?
https://letsencrypt.org/certificates/