Let's Encrypt でワイルドカード証明書発行をテストしてみる

## はじめに

Let's Encrypt では、ワイルドカード証明書の発行が計画されおり、2018年 1月現在、ステージングサーバー上で ACME v2 によるワイルドカード証明書の発行がテストされています。

そこで、Go 言語で、ACME v2 クライアントツールを作成し、ワイルドカード証明書の発行をテストしてみます。

プロダクション環境への展開は、2018年 2月 終りごろが予定されている模様です。


### 2/22 追記

Let's Encrypt による ACME v2 のリリースは、延期の見込みとのことです。

https://community.letsencrypt.org/t/acmev2-and-wildcard-launch-delay/53654

プロダクションへのローンチ後、ワイルドカード証明書の実用発行の運用についての記事をアップする予定です。

### 3/14 追記

ACME v2 リリースされました。

https://qiita.com/noumia/items/64d8bb59e35151fc4fd6


## 必要なもの

* TXT レコードを設定できるドメイン

* Go 言語コンパイラー (v1.9.3)

* openssl コマンド (Windows では、Git for Windows に付属)


本稿でのワークステーションの環境は、Windows 10 です。

以下、ドメイン名として example.jp と例示しますが、実際には、ご自分のドメイン名に読み替えてください。


## ツールのビルド

```
> go get -u github.com/noumia/acme/cmd/wild-le
```

%GOPATH%\bin へ、実行ファイルが作成されるので、パスを通しておきます。


## アカウントの作成

```
> openssl genrsa -out account.key 4096

> wild-le account -c acme@example.jp --agree-tos
```

メールアドレスの登録は任意ですが、利用規約には同意する必要があります。


## 証明書の発行リクエスト

サーバー秘密鍵を作成します。アカウント用の鍵と共用することはできません。

```
> openssl genrsa -out server.key 2048
```

### 証明書の発行

```
> wild-le renew -d *.example.jp server.crt
DNSSetup TXT: _acme-challenge.example.jp 8ZkX2so-Beyzq2RWmntJ_dsR_-W1B_j5X-7OXNNoPiI
Continue?
```

-d オプションで、'*.' から始まるドメイン名を指定すると、ワイルドカード証明書となります。通常のドメイン名を指定することもできます。

表示されたドメイン (_acme-challenge.example.jp) の TXT レコードへ、表示された認証用のテキスト (8ZkX2...) を設定してください。

設定できたら、y [Enter] とタイプすることで、処理が続行されます。(レコードの設定反映を確認するため、数分程度の時間を要することがあります。)

エラーが起きなければ、server.crt へ証明書が出力されます。


## 動作確認

caddy サーバーを使用して、動作確認します。

www.example.jp としてアクセスできるサーバーに、Caddyfile, server.crt, server.key を配置します。

### Caddyfile
```
https://www.example.jp {
  tls server.crt server.key
}
```

### サーバーの起動
```
> caddy
Activating privacy features... done.
https://www.example.jp
```

### クライアント側のテスト

ステージングサーバーでは、正規の証明書ではなく、テスト用証明書の発行なので、テスト用ルート証明書をダウンロードします。

```
> curl http://cert.stg-root-x1.letsencrypt.org/ | openssl x509 -inform der -outform pem -out stg-root-x1.pem
```

```
> curl -v --cacert stg-root-x1.pem https://www.example.jp
* Rebuilt URL to: https://www.example.jp/
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to www.example.jp (127.0.0.1) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: stg-root-x1.pem
  CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server accepted to use h2
* Server certificate:
*  subject: CN=*.example.jp
*  start date: Jan 26 08:16:33 2018 GMT
*  expire date: Apr 26 08:16:33 2018 GMT
*  subjectAltName: host "www.example.jp" matched cert's "*.example.jp"
*  issuer: CN=Fake LE Intermediate X1
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x1e1406f40e0)
> GET / HTTP/2
> Host: www.example.jp
> User-Agent: curl/7.58.0
> Accept: */*
>
* Connection state changed (MAX_CONCURRENT_STREAMS updated)!
< HTTP/2 404
< content-type: text/plain; charset=utf-8
< server: Caddy
< x-content-type-options: nosniff
< content-length: 14
< date: Fri, 26 Jan 2018 09:30:40 GMT
<
404 Not Found
* Connection #0 to host www.example.jp left intact
```

証明書エラーが発生しなければ、成功です。