🌊
サービスアカウント の account_id に UUID を指定したい
方針
諸事情でGCPのサービスアカウントのaccount_idにUUIDを指定したかったんですが、意外と苦労したので備忘録的に残します。
どうもサービスアカウントのaccount_idの命名規則は次のようになっているようです。
- 小文字の英数字とダッシュ(
-
)で構成される - 先頭は英字のみ
- 6文字以上30文字以内
UUIDは36桁で -
を除いても32文字あり、どう頑張ってもそのままでは使用できませんでした。仕方がないので、どうにか上記制約を満たす中での可逆圧縮を考えました。
よくあるのはbase64エンコードかと思いますが、小文字しか使えない上に、記号も -
しか使用できないので厳しいなと(ひょっとしたらいい感じに符号化することでいけるのかも?)
そこで今回はUUIDを32進数表記することで対応しました。UUIDは16進数32桁=128bitで構成されているので、これを32進数表記することで26文字まで圧縮することができます。また、32進数であれば 0-9
と a-v
までの英数字で表現できるので、冒頭の制約下で表現できます。これでUUIDを情報を失うことなく26文字まで圧縮することができるようになりました。最後に先頭文字は英字限定という条件を満たすために適当なprefixをつければ完成です。
Terraformによる実装
Terraformのmoduleで表現すると次のようになります。
# main.tf
locals {
# UUIDをバイナリに変換
bin_uuid = join("", [for c in split("", replace(var.uuid, "-", "")) : format("%04b", parseint(c, 16))])
# 先頭を0でパディングして、長さを130ビットに調整
padded_bin_uuid = format("%02s%s", "0", local.bin_uuid)
# 32進数に変換
base32_chars = "0123456789abcdefghijklmnopqrstuv"
compressed_uuid = join("", [for bin in regexall(".{5}", local.padded_bin_uuid) : substr(local.base32_chars, parseint(bin, 2), 1)])
}
# variables.tf
variable "uuid" {
type = string
description = "UUID"
}
# outputs.tf
output "result" {
value = local.compressed_uuid
}
知らなかったんですが、Terraformもテスト書けたんですね。
variables {
uuid = "f81d4fae-7dec-11d0-a765-00a0c91e6bf6"
}
run "compress_uuid" {
command = plan
assert {
condition = local.compressed_uuid == "7o3l7qsvfc278aep80k34hsqvm"
error_message = "invalid compressed_uuid"
}
}
Discussion
先頭を0パディングじゃなくて1パディングにすれば、32進数に変換したときに確定で先頭が英字になるので、変なprefixを付ける必要もないですね