🤦‍♂️

TerraformとGoogle Cloudでやらかした話

2023/12/28に公開

はじめに

やあみんな、技術の食いつき虫Reiだよ:v:!

  • Microsoft Learn Student Ambassador
  • GiTHub Campus Expert
  • Google Developer Student Club Nagoya Lead
  • 普段はSREとインフラとセキュリティをやってるよ(開発できるけどね)
  • コミュニティ運営してるよ!(ぜひGDSCNagoyaやGitHub Student Communityに入ってね!)
    ぜひフォローしてね
    https://linktr.ee/Rei_suzuki

きっかけ

インターン先で検証してた際にはまったことがあったので、メモがてら残しておきます。

この記事の対象者

  • terraformを使ってる方
  • Google Cloudを使っている方
  • 細かい仕様が好きな人

本題

結論

Terraformを使ってIaC(Infrastructure as Code)をする際に、対象のクラウドの仕様の細かい仕様を公式ドキュメントでしっかりと見ようねという話です

実際にやったこと

環境

  • terraform 1.6.1
  • terraform-provider-google 5.2.0

やりたかったこと

アーキテクチャの図

上記の図のようにCertificate Managerにあるセルフマネージド証明書をロードバランサーにアタッチしようとTerraformのコードを書こうとしてた。

なぜか?
  • 元々Certificate Managerを使わない従来の方法で今まで行っていた
    • Certificate Managerに移行する検討をしたい
  • terraform-provider-google 5.2.0にて、何やらそれについて追加があったぽいぞ(後述)
詳しい変更点

5.2.0
...
BUG FIXES:
...
compute: added certificate_manager_certificates field to google_compute_target_https_proxy resource (#16179)
...

リリースノートにはこう記載されてました

詳しいPull Request

terraform-provider-googleのドキュメントを見に行きます

おお!確かにある!

resource "google_compute_target_https_proxy" "default" {
  name                             = "target-http-proxy"
  url_map                          = google_compute_url_map.default.id
  certificate_manager_certificates =  ["//certificatemanager.googleapis.com/${google_certificate_manager_certificate.default.id}"] # [google_certificate_manager_certificate.default.id] is also acceptable
}

certificate_manager_certificatesの詳しい説明を見ると

英語の説明

(Optional) URLs to certificate manager certificate resources that are used to authenticate connections between users and the load balancer. Currently, you may specify up to 15 certificates. Certificate manager certificates do not apply when the load balancing scheme is set to INTERNAL_SELF_MANAGED. sslCertificates and certificateManagerCertificates fields can not be defined together. Accepted format is //certificatemanager.googleapis.com/projects/{project}/locations/{location}/certificates/{resourceName} or just the self_link projects/{project}/locations/{location}/certificates/{resourceName}

簡単に日本語で言うと


そもそもどうなっていたの?

resource "google_compute_target_https_proxy" "default" {
  name             = "test-proxy"
  url_map          = google_compute_url_map.default.id
  ssl_certificates = [google_compute_ssl_certificate.default.id]
}

resource "google_compute_ssl_certificate" "default" {
  name        = "my-certificate"
  private_key = file("path/to/private.key")
  certificate = file("path/to/certificate.crt")
}

このような感じで、セルフマネージド証明書を証明書リソースとしてアップロードしてから、グローバル外部アプリケーション ロードバランサーにアタッチしてました。

詳しいドキュメント

なので、書き直すとしたら

resource "google_compute_target_https_proxy" "default" {
  name                             = "target-http-proxy"
  url_map                          = google_compute_url_map.default.id
  certificate_manager_certificates =  ["//certificatemanager.googleapis.com/${google_certificate_manager_certificate.default.id}"] 
}

resource "google_certificate_manager_certificate" "default" {
  name              = "my-certificate"
  scope             = "ALL_REGIONS"
  self_managed {
    pem_certificate = file("test-fixtures/cert.pem")
    pem_private_key = file("test-fixtures/private-key.pem")                                                                                                                
  }
}

の公式ドキュメントに書いてある通りに記述すればよいと思ってました(これが一番の間違い)

terraform plan が問題なかったが、terraform applyを実行した際、エラー が起きました!

Error creating TargetHttpsProxy:googleapi:
Error 400: Invalid value for field 'resource.sslCertificates[0]':
Cloud certificate reference is not supported for TargetHttpsProxy creation.,Invalid

Details: | 
  [|
    { |
      "@type":"type.googleapis.com/google.rpc.BadRequest",|
      "fieldViolations":[|
        {|
          "description":"certificate \"projects/11111/locations/global/certificates/sample-cert\" has invalid scope ",|
          "field":"certificates"|
      }
    ]
  }
]  

どんな解決を試みたか

  • 上記のドキュメントで関連するしっかりとリファレンスを見る
  • 実際のGitHubのリポジトリを見に行き、齟齬がないか見てみる
  • リリースされてから2週間ばかりだったので、同じようなエラーをissuesで探す
  • terraform のデバッグログをみる
  • Google Cloudで関連するドキュメントを見る(APIの仕様まで)
  • terraform のバージョンアップをする

しかしながら,解決に至らず…

そこで、実際にドキュメントにあるコードをCloud Shellで動きを確認することにしました。

ドキュメントにあるコードは動いたので、差分に注目しました。

というのも、気になってた部分がありました。

自分の環境だと、ロードバランサーのスキームが EXTERNAL_MANAGED だけど、ドキュメントにある例には、INTERNAL_MANAGED

ロードバランサーのスキームについて

ここに注目しました

https://cloud.google.com/certificate-manager/docs/deploy?hl=ja

自分の環境だと

  • 証明書マップを作成
  • 証明書マップエントリを追加
  • ロードバランサーにアタッチ

ドキュメントにあるのは、

  • セルフマネージド証明書をアップロードして、ロードバランサーに直接添付する

待てよ,terraform-provider-googleのほうには、

  • ロードバランサーのスキームが INTERNAL_SELF_MANAGEDの場合は、適用されないよ

と書いてあったはず(これが罠)

ということは、certificate_manager_certificatesは、グローバル外部アプリケーション ロードバランサでは使えない??

実際には、

  • グローバル外部アプリケーション ロードバランサ(EXTERNAL_MANAGED)
  • 従来のアプリケーション ロードバランサ(EXTERNAL)
  • グローバル外部プロキシ ネットワーク ロードバランサ(EXTERNAL)

はだめで、

  • クロスリージョンの内部アプリケーション ロードバランサ(INTERNAL_MANAGED)
  • リージョン外部アプリケーション ロードバランサ(EXTERNAL_MANAGED)
  • リージョン内部アプリケーション ロードバランサ(INTERNAL_MANAGED)

は大丈夫

ややこしい

やらかしポイント

  • Certificate Manager をロードバランサーにアタッチのところの理解があいまいだった
  • プロバイダーのドキュメントを信用しすぎた(純粋)
    • 間違っているわけではない
  • ドキュメントしっかりと読む

まとめ

SREっぽいことをやっていて、クラウド業務に携わっていると、
サードパーティーツールとクラウドのドキュメントが違うことが結構あったりするので、退屈しないですね(検証のしがいがある)

また深夜テンションのまま書いているので、誤字脱字、また認識の違いがあれば、ぜひご連絡ください!

GitHubで編集を提案

Discussion