2024年6月6日 星期四

Terraform - aws_rds_proxy 接 RDS PostgreSQL 的 init_query 指令

在 Terraform 的文件 db_proxy_default_target_group 只有提供 MySQL 的使用範例:
resource "aws_db_proxy" "example" { name = "example" debug_logging = false engine_family = "MYSQL" idle_client_timeout = 1800 require_tls = true role_arn = aws_iam_role.example.arn vpc_security_group_ids = [aws_security_group.example.id] vpc_subnet_ids = [aws_subnet.example.id] auth { auth_scheme = "SECRETS" description = "example" iam_auth = "DISABLED" secret_arn = aws_secretsmanager_secret.example.arn } tags = { Name = "example" Key = "value" } } resource "aws_db_proxy_default_target_group" "example" { db_proxy_name = aws_db_proxy.example.name connection_pool_config { connection_borrow_timeout = 120 init_query = "SET x=1, y=2" max_connections_percent = 100 max_idle_connections_percent = 50 session_pinning_filters = ["EXCLUDE_VARIABLE_SETS"] } }

這邊 init_query 是用 “SET x=1, y=2” 當作 proxy 連上 db 的測通指令, 但是 MySQL 的 SET 指令跟 PostgreSQL 的 SET 指令用法不同, 所以直接把這個範例給 PostgreSQL 用的時候會噴錯誤:

proxy log: - [INFO] [dbConnection=1140488035] The database connection closed. Reason: An internal error occurred. db log: - ERROR: syntax error at or near "=" at character 11 - STATEMENT: SET x=1, y=2
(以上來自 CloudWatch Logs, RDS 跟 RDS Proxy 都有設定送出 log 到這邊)
伸進去 PostgreSQL db 手動執行指令看看:
postgres=> SET x=1, y=2; ERROR: syntax error at or near "=" LINE 1: SET x=1, y=2; ^ postgres=> SET x=1; ERROR: unrecognized configuration parameter "x" postgres=>
確認是 SET 指令造成錯誤.

Google 查了幾下也是有一些回報同樣的問題, 解法幾乎都是把 init_query 拿掉, 但是這樣就少了一個 proxy 連入 db 測通 db 要有正常反應的機制.

所以找個指令替代 SET 就解決了:
init_query = "VALUES (1,2)"

AWS - IAM Role with Policy

AWS 的 IAM Role 跟 Policy 有兩種連接方式:
- Role 內嵌 Policy.
- Role 和 Policy 是各自建立, 然後再接起來(attach)用.

以 Policy 編修來說, 前者就只能在 portal 上面 CRUD, 後者在 Policy 本身的 portal 介面還可以看 permission 檢查, 歷次編修版本與控管, 相同的 Policy 還可以接到多個 Role 共用, 後來我也盡量都用後者.

不過後者在 Terraform 的寫作上有需要注意的地方, 一般寫法如下:
resource "aws_iam_policy" "this" {} resource "aws_iam_role" "this" {} resource "aws_iam_role_policy_attachment" "this" { depends_on = [ aws_iam_role.this, aws_iam_policy.this ] }

在 terraform apply 的時候不成問題, 但是在 terraform destroy 會發生 race condition: Policy 還沒從 Role 拆出來, 上面這個寫法會造成 aws_iam_policy 跟 aws_iam_role 同時進行 destroy, 在刪除 aws_iam_policy 就會噴錯誤訊息, 說 Policy 還接在 Role 上面所以不能被砍掉.

雖然再執行一次 terraform destroy 就過了(錯誤是在砍 aws_iam_policy 的時候噴的, 但同時砍 aws_iam_role 的動作是有被完成), 但是這樣對於砍站跑路就不夠徹底順暢.

簡單解決的方式就是在 aws_iam_role 裡面加一個 depends_on aws_iam_policy:
resource "aws_iam_role" "this" { ... depends_on = [ aws_iam_policy.this ] }

這樣子在 destroy 的時候, aws_iam_role 就會先被刪除(無論 Policy 拆出來了沒), 再刪除 aws_iam_policy 就不會卡住了.

然後第一個方式在 Terraform 有個地雷, Role 內嵌 Policy 大概是這樣寫:
resource "aws_iam_role" "this" { ... inline_policy { name = "Role-foobar-Policy" ... } }
當不要用 inline_pocily 的時候, 把這段刪除成這樣:
resource "aws_iam_role" "this" { ... }

然後 terraform apply 的時候, diff 並沒有出現 - 掉 inline_policy 這塊的訊息, 實際上 Terraform 真的沒做這個刪除, 在 portal 是還看得到 inline_policy 的存在, 得在這邊手動砍掉才算沒了.


AWS IAM 有好幾個拆連接的動作會產生 race condition, 表面上 API 回應 ok, 但是實際上裡面還在慢慢斷開, 沒那麼快拆完...