DNS 認証を使用して Google マネージド証明書をデプロイするチュートリアルをやってみた

はじめに

Google Cloud の Certificate Manager を利用して、新たに機能追加された、SSL/TLS 証明書の設定方法を理解するため、以下のチュートリアルをやってみた。

チュートリアルを実施している様子を、YouTube にアップロードした。

DNS 認証は、証明書の承認を、ロードバランサの作成前に行うことができる。
「既存の証明書」と同様に、ロードバランサ作成後に証明書の認証を行えばよい場合、DNS 認証の作成は、不要となる。

現時点で、Certificate Manager の「新しい証明書」を利用する場合、Google Cloud コンソールでは、参照のみ可能で、作成・削除などは、gcloud コマンドで行う必要がある。

AWS などと比較すると、全体像を理解することが難しい。
導入されたばかりの機能なので、今後 Cloud コンソールなどで全ての作業が行えるようになれば、もう少し理解しやすくなるのかもしれない。

調べた範囲では、「新しい証明書」をロードバランサに適用する場合でも、「従来の証明書」が、必ず必要となるようだ。
ロードバランサに設定した「従来の証明書」は、「新しい証明書」を設定した時点で利用されなくなるが、「従来の証明書」を設定上は参照し続けるため、削除ができない。
よって、「従来の証明書」は、共用のダミー証明書として作成する。

「従来の証明書」と「新しい証明書」との優先順位は、Attach the certificate map to the target proxy に以下のような記載がある。
「プロキシに直接アタッチされた既存の TLS (SSL) 証明書がある場合、プロキシは、直接アタッチされた TLS (SSL) 証明書よりも、証明書マップによって参照される証明書を優先します。
(原文:If there are any existing TLS (SSL) certificates attached directly to the proxy, the proxy gives preference to the certificates referenced by the certificate map over the directly attached TLS (SSL) certificates.)」

実際に試したところ、「新しい証明書」に切り替わると、「従来の証明書」でのアクセスは、証明書が取得できず、エラーとなった。

利用 API

このチュートリアルでは、以下の API を利用する。
  • Compute Engine API
  • Cloud DNS API
  • Certificate Manager API

事前準備

Google Cloud プロジェクトは、作成済みとする。
ドメインを所有している前提とする。このチュートリアルでは、「test1.www.i-chi-li.info」とする。
gcloud コマンドが利用可能とする。ローカル環境でも Cloud Shell 環境でもよい。

チュートリアル実施


ロードバランサを準備する

元のチュートリアルには、ロードバランサを準備する手順は、含まれていない。

ロードバランサのバックエンドを作成する

Google Storage のバケットをバックエンドとして利用する。

バケットを作成する。

Cloud コンソールのナビゲーションメニューから、Cloud Storage →バケット→「作成」ボタンを押下する。
バケット名は、任意の名称で設定する。ここでは、「20221229-bucket」とする。
「続行」ボタンを押下する。
ロケーションタイプは、Multi-region の「us」とする。
「続行」ボタンを押下する。
データのストレージクラスは、デフォルトのクラスで「Standard」とする。
「続行」ボタンを押下する。
「このバケットに対する公開アクセス禁止を適用する」は、チェックを外す。
アクセス制御は、「均一」とする。
「続行」ボタンを押下する。
保護ツールは、「なし」とする。
「作成」ボタンを押下する。

公開設定をする。

バケットの詳細画面の権限タブを選択する。
「アクセス権を付与」をクリックする。
プリンシパルに、「allUsers」を設定する。
ロールに、Cloud Storage →「Storage オブジェクト閲覧者」を選択する。
「保存」ボタンを押下する。

index.html を作成する。

バケットに index.html ファイルを以下の内容で作成する。
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Hello world</title>
</head>
<body>
Hello World
</body>
</html>
gcloud でバケットにアップロードする場合、以下のようにコマンド実行する。
gcloud storage cp index.html gs://20221229-bucket

「従来の証明書」を作成する

共用のダミー証明書を事前に作成しておく。
Cloud コンソールのナビゲーションメニューから、セキュリティ→ Certificate Manager を選択する。
「従来の証明書」タブを選択する。
「SSL 証明書を作成」ボタンを押下する。
名前は、任意の名前を設定する。ここでは、「dummy-cert」とする。
作成モードは、「Google マネージドの証明書を作成する」を選択する。
ドメインは、任意のドメイン名を設定する。ここでは、「1.dummy.test1.www.i-chi-li.info」とする。
「作成」ボタンを押下する。
一覧に表示され、ステータスが「プロビジョニング」になるまで待つ。「更新」ボタンで反映されない場合は、ブラウザの再読み込みをすると表示される。

ロードバランサを作成する

Cloud コンソールのナビゲーションメニューから、ネットワーク サービス→ロード バランシングを選択する。
「ロードバランサを作成」をクリックする。
「HTTP(S) ロード バランシング」の「構成を開始」ボタンを押下する。
「インターネットから VM またはサーバーレス サービスへ」を選択する。
「グローバル HTTP(S) ロードバランサ」を選択する。
「続行」ボタンを押下する。

ロードバランサの名前(左上の入力欄)は、任意の名前を設定する。ここでは、「test1-lb」とする。

フロントエンドの構成の新しいフロントエンドの IP とポートは、以下のように設定する。
名前は、任意の名前を設定する。ここでは、「test1-lb-front」とする。
プロトコルは、「HTTPS」とする。
IP バージョンは、「IPv4」とする。
IP address は、「エフェメラル」とする。固定 IP にしてもよい。
ポートは、「443」とする。
証明書は、「dummy-cert」を選択する。
その他の証明書以降は、デフォルト値のままとする。

左側の「バックエンドの構成」を押下する。
バックエンドサービスとバックエンドバケットドロップダウンをクリックして、バックエンドバケットを作成を選択する。
バックエンドバケット名に任意の名前を設定する。ここでは、「test1-bucket-backend」とする。
Cloud Storage バケットは、「20221229-bucket」を選択する。
「Cloud CDN を有効にする」は、任意に設定する。ここでは、有効にしておく。
各設定値は、デフォルト値のままとする。
「作成」ボタンを押下する。
「test1-bucket-backend」が、チェックされていることを確認して、「OK」ボタンを押下する。

左側の「ルーティング ルール」を押下する。
任意にルールを設定する。ここでは、すべてデフォルト値のままとする。

左側の「確認と完了」を押下し、設定内容に問題がなければ、下側の「作成」ボタンを押下する。
しばらくすると、ロードバランサが作成される。

「従来の証明書」を承認する

承認をしなくても、設定を進められるが、実施しておく。
ロードバランサ一覧で、「test1-lb」をクリックする。
ロードバランサの詳細画面のフロントエンド一覧で、「HTTPS」の「IP:ポート」項目から、ロードバランサの IP アドレスをコピーしておく。

DNS の A レコードに、ホスト名および、ロードバランサの IP アドレスを TTL 60 秒で追加する。ここでは、ホスト名「1.dummy.test1.www.i-chi-li.info」とする。
「従来の証明書」が承認されるまで、しばらくかかる。5~10 分程度で有効化されたが、場合によっては、さらに時間が必要かもしれない。
承認されても更に数分間は、index.html へのアクセスで、証明書が取得できない。

「新しい証明書」を準備する

DNS 承認を作成する

「test1-auth」および、「--domain」オプションの値は、任意の値に設定する。
gcloud certificate-manager dns-authorizations create test1-auth --domain="test1.www.i-chi-li.info"

DNS に承認用のレコードを追加する

レコードに登録する設定値を確認する。
gcloud certificate-manager dns-authorizations describe test1-auth
以下のような内容が表示される。
createTime: '2022-12-25T05:06:36.335249482Z'
dnsResourceRecord:
  data: 0123aabb-0123-xxxx-0123-01234aabbcca.00.authorize.certificatemanager.goog.
  name: _acme-challenge.test1.www.i-chi-li.info.
  type: CNAME
domain: test1.www.i-chi-li.info
name: projects/YOUR_PROJECT_ID/locations/global/dnsAuthorizations/test1-auth
updateTime: '2022-12-25T05:06:36.713552419Z'
以下のように dnsResourceRecord の各値を DNS のレコードに追加する。

DNS 名は、name の値
リソースレコードのタイプは、type の値
正規名は、data の値(末尾のピリオドまで含む)

証明書を作成する

「--domains」オプションに、カンマ区切りでドメインを列挙する。ワイルドカードも指定出来る。
ここで設定するドメインは、証明書の Subject Alternative Name に設定する値となる。
gcloud certificate-manager certificates create test1-cert --domains="test1.www.i-chi-li.info,*.test1.www.i-chi-li.info" --dns-authorizations="test1-auth"

「新しい証明書」をロードバランサーに適用する

証明書マップを作成する

ざっくり説明すると、証明書マップは、ロードバランサに割り当てるためのもので、クライアントから要求されたホスト名に該当する証明書を判断するための設定となる。
詳細は、Certificate maps を参照。
gcloud certificate-manager maps create test1-cert-map

証明書マップに証明書マップエントリを追加する

「--hostname」オプションに設定する値は、クライアントから要求されたホスト名と比較して、どの証明書を返すかを判断する値となる。証明書の Subject Alternative Name などとは、比較しないので注意。
判定の優先順位などの詳細は、 Certificate selection logic を参照。
クライアントからホスト名を渡さない場合や、該当する証明書が無い場合に、デフォルトで返す証明書を設定することもできる。詳細は、Create a primary certificate map entry を参照。
gcloud certificate-manager maps entries create test1-cert-map-entry1 --map="test1-cert-map" --certificates="test1-cert" --hostname="test1.www.i-chi-li.info"
gcloud certificate-manager maps entries create test1-cert-map-entry2 --map="test1-cert-map" --certificates="test1-cert" --hostname="*.test1.www.i-chi-li.info"

ロードバランサのターゲット プロキシに証明書マップを割り当てる。

ロードバランサのターゲット プロキシ名を調べる。

Cloud コンソールのナビゲーションメニューから、ネットワーク サービス→ロード バランシングを選択する。
ロードバランサ一覧の下にある、文中の「ロード バランシング コンポーネントのビュー」リンクをクリックする。
ロード バランシングのコンポーネント画面の、ターゲット プロキシタブを選択する。
該当するターゲット プロキシ名(ここでは、 test1-lb-target-proxy)をコピーしておく。

ターゲット プロキシに証明書マップを割り当てる。

gcloud compute target-https-proxies update test1-lb-target-proxy --certificate-map="test1-cert-map"

DNS レコードに「新しい証明書」のドメインを追加する

DNS の A レコードを、ドメイン名(ここでは、test1.www.i-chi-li.info)および、ロードバランサの IP を追加する。 TTL は、60 秒とする。

動作確認

数分後に「新しい証明書」に切り替わる。
さらに数分後には、「既存の証明書」でのアクセスでエラーとなる。
不要となった「既存の証明書」の DNS レコードを削除する。ここでは、1.dummy.test1.www.i-chi-li.info.

後片付け

DNS のレコードを削除する。

「新しい証明書」用の DNS レコードを削除する。ここでは、test1.www.i-chi-li.info.
DNS 承認用の DNS レコードを削除する。ここでは、_acme-challenge.test1.www.i-chi-li.info.

「新しい証明書」を削除する。

gcloud compute target-https-proxies update test1-lb-target-proxy --clear-certificate-map
gcloud certificate-manager maps entries delete test1-cert-map-entry1 --map="test1-cert-map"
gcloud certificate-manager maps entries delete test1-cert-map-entry2 --map="test1-cert-map"
gcloud certificate-manager maps delete test1-cert-map
gcloud certificate-manager certificates delete test1-cert

ロードバランサを削除する。

Cloud コンソールのナビゲーションメニューから、ネットワーク サービス→ロード バランシングを選択する。
一覧にある該当するロードバランサ(ここでは、test1-lb)をチェックし、上部にある「削除」をクリックする。
ロードバランサの削除ダイアログで、「バックエンドバケット」および、「SSL 証明書」にチェックを入れて、「ロードバランサと選択したリソースを削除」をクリックする。

バケットを削除する。

Cloud コンソールのナビゲーションメニューから、Cloud Storage →バケットを選択する。
該当のバケット(ここでは、20221229-bucket)を削除する。

参考資料