Managed SSLからCertificate Managerに移行する
はじめに
実務で Managed SSL から Certificate Manager に乗り換える機会がありました。その時に Terraform の予期しないエラーで苦労したので Managed SSL から Certificate Manager への移行手順をまとめてみました。example.com
とabc.example.net
の2つのドメイン証明書を移行する例を使って説明していきます。
[Step0]移行前の状態
はじめにStep0として移行前の状態を確認します。
example.com
とabc.example.net
の2つのドメインの証明書が Managed SSL に管理されていて、それら証明書がロードバランサと関連付けられています。
# Managed SSLで管理している証明書
resource "google_compute_managed_ssl_certificate" "domains" {
name = "ssl-cert"
managed {
domains = [
"example.com",
"abc.example.net",
]
}
}
# ロードバランサ
resource "google_compute_target_https_proxy" "lb" {
name = "https-proxy"
url_map = google_compute_url_map.lb.id
ssl_policy = google_compute_ssl_policy.policy.name
# Managed SSLとの関連づけ
ssl_certificates = [
google_compute_managed_ssl_certificate.domains
]
}
resource "google_compute_url_map" "lb" {
...省略
}
# SSLポリシー
resource "google_compute_ssl_policy" "policy" {
name = "ssl-policy"
profile = "MODERN"
min_tls_version = "TLS_1_2"
}
[Step1]新しい証明書とCertificate Mapをデプロイする
こちらの記事を参考に以下4つのリソースをデプロイします。
- google_certificate_manager_dns_authorization
- google_certificate_manager_certificate
- google_certificate_manager_certificate_map
- google_certificate_manager_certificate_map_entry
追加する Terraform のコードは以下です。
locals {
domains = [
"example.com",
"abc.example.net",
]
}
# DNS認証
resource "google_certificate_manager_dns_authorization" "authorizations" {
for_each = toset(local.domains)
name = "dns-authz-${replace(each.key, ".", "-")}"
domain = each.key
}
# 証明書
resource "google_certificate_manager_certificate" "certificates" {
for_each = toset(local.domains)
name = "cert-manager-${replace(each.key, ".", "-")}"
managed {
domains = [
each.key
]
dns_authorizations = [
google_certificate_manager_dns_authorization.authorizations[each.key].id
]
}
}
# Certificate Map
resource "google_certificate_manager_certificate_map" "map" {
name = "cert-map"
}
# マップエントリー
resource "google_certificate_manager_certificate_map_entry" "map_entries" {
for_each = toset(local.domains)
name = "map-entry-${replace(each.key, ".", "-")}"
map = google_certificate_manager_certificate_map.map.name
hostname = each.key
certificates = [
google_certificate_manager_certificate.certificates[each.key].id
]
}
上記コードを追加したらterraform apply
をします。applyが終わったら DNS に CNAME のレコードを追加して証明書を有効化してください。
[Step2]ロードバランサとCertificate Mapを関連づける
DNS 設定が終わって Certificate Manager の証明書がアクティベートされたのが確認できたらロードバランサと Certificate Map を関連付けます。
# Certificate Map(Step1で追加されたリソース)
resource "google_certificate_manager_certificate_map" "map" {
name = "cert-map"
}
# ロードバランサ(修正する)
resource "google_compute_target_https_proxy" "lb" {
name = "https-proxy"
url_map = google_compute_url_map.lb.id
ssl_policy = google_compute_ssl_policy.lb.name
# 削除予定(一旦残す)
ssl_certificates = [
google_compute_managed_ssl_certificate.domains
]
# Certificate Mapとロードバランサの関連付け(追加)
certificate_map = "//certificatemanager.googleapis.com/${google_certificate_manager_certificate_map.map.id}"
}
ssl_certificates の設定を残して certificate_map を追加するのがポイントです。この状態でterraform apply
を実行します。一時的にロードバランサに Managed SSL と Certificate Manager の両方の証明書が関連付けられます(両方の証明書を関連付けないとデプロイ時に conditionNotMet エラーが発生します)。
[Step3]ロードバランサからManaged SSLの参照を外す
Step2までデプロイができたらgoogle_compute_target_https_proxy
から ssl_certificates を削除して Managed SSL の参照を外します。
resource "google_compute_target_https_proxy" "lb" {
name = "https-proxy"
url_map = google_compute_url_map.lb.id
ssl_policy = google_compute_ssl_policy.lb.name
# 削除
#ssl_certificates = [
# google_compute_managed_ssl_certificate.domains
#]
# Certificate Mapとロードバランサの関連付け
certificate_map = "//certificatemanager.googleapis.com/${google_certificate_manager_certificate_map.map.id}"
}
この状態でterraform apply
を実行します。これでロードバランサと Managed SSL の関連が外れます。
[Step4]Managed SSLを削除する
ここまでできたらあとは使わなくなった Managed SSL 関連のリソースを削除して終わりです。google_compute_managed_ssl_certificate
のコードを削除してterraform apply
します。
# 削除
#resource "google_compute_managed_ssl_certificate" "domains" {
# name = "ssl-cert"
# managed {
# domains = [
# "example.com",
# "abc.example.net",
# ]
# }
#}
以上で Managed SSL から Certificate Manager への移行は完了です。
補足: 移行時に発生したエラー
なにも考えずに以下のようにgoogle_compute_target_https_proxy
から ssl_certificates を削除して certificate_map を追加すると
resource "google_compute_target_https_proxy" "lb" {
name = "https-proxy"
url_map = google_compute_url_map.lb.id
ssl_policy = google_compute_ssl_policy.lb.name
# Managed SSLとの関連を削除する
#ssl_certificates = [
# google_compute_managed_ssl_certificate.domains
#]
# Certificate Mapとロードバランサの関連付け(追加)
certificate_map = "//certificatemanager.googleapis.com/${google_certificate_manager_certificate_map.map.id}"
}
terraform apply 時に以下のようなエラーが発生します。
Error updating TargetHttpsProxy "projects/{プロジェクト名}/global/targetHttpsProxies/{リソース名}":
googleapi:
Error 412: Certificate Map or at least 1 SSL certificate must be specified for setting SSL certificates in TargetHttpsProxy.,
conditionNotMet
ちゃんと証明書を設定してるのになんで?という内容のエラーメッセージです。上記エラーについて Issue が上がっていて、そこを読むと
一旦両方の証明書をロードバランサに紐づけてデプロイしたあとに、古い方の証明書の紐付けを削除して再度デプロイしろとありました(証明書の安全な移行を考えれば当然なのかもしれませんがTerraformのエラーメッセージは不親切に感じました)。というわけで conditionNotMet エラーを回避して証明書の移行をするには今回紹介した手順にそって段階的にデプロイをする必要があるということでした。
Discussion