2025年1月13日 星期一

Akamai CDN access logs to Datadog

目的: 把 blah.foobar.com 的 CDN access log 轉送到 datadog 備查

0. Datadog
  - 設定設定
    - https://docs.datadoghq.com/integrations/akamai_datastream_2/

1. COMMON SERVICES - DataStream
  - 點選 Create stream - Delivery Products
    - CONFIGURATION
      - Display Name: blah-foobar-com-logs-to-datadog
      - Group: Foobar-W-DEADBF
      - Include properties: 勾選 blah.foobar.com
    - DATA SETS
      - Log information
        - (include all)
      - Message exchange data
        - (include all)
      - Request header data
        - (include all)
      - Network performance data
        - (include all)
      - Cache data
        - (include all)
      - Geo data
        - (include all)
      - Web security
        - (include all)
      - EdgeWorkers
        - (include all)
      - Content protection
        - (include all)
      - Custom fields
        - (include all)
      - Log file
        - Log format: Json
    - DELIVERY
      - Destination
        - Destination: 選 Datadog
        - Display name: blah-foobar-com-logs-to-datadog
        - Endpoint: (datadog input endpoint)
          - https://http-intake.logs.datadoghq.com/v1/input
          - https://http-intake.logs.datadoghq.eu/v1/input
        - Tags: source:akamai.datastream
        - Source: akamai.datastream
        - Service:
        - API Key: (datadog api key)
        - Send compressed data: No
      - Delivery options
        - Push frequency: 60 Seconds
    - SUMMARY
  - 幾個步驟建立完之後, blah-foobar-com-logs-to-datadog 的 status 是 Activating - V1
    - 只能 View / History / Clone, 無法 Edit / Deactivate / Delete
    - V1 是指這個 Stream 設定是 version 1, 不是 DataStream 1 的意思

2. CDN - Properties
  - 選 blah.foobar.com 再點選版本, 點 Edit New Version
  - 左邊選 Default Rule, 右邊點 +Behavior 新增 DataStream
    - Stream version 只有選 DataStream 2 會過
      - DataStream 1 要被淘汰掉
      - 選 DataStream 1 會跳出警告訊息, 可以 Save 但無法 Activate
    - Stream names 選 blah-foobar-com-logs-to-datadog
    - Sample rate 預設 100
      - 通靈用的話一定要選 100, 要不然缺 log 會讓你通到屎
  - 最後 Save
  - 然後 Activate 這個新版本上線
    - 最久 10 分鐘才會完成

3. 回到 COMMON SERVICES - DataStream
  - blah-foobar-com-logs-to-datadog 的 status 在 Properties 上完之後變成 Active - V1
    - 第一次比較快
    - Active 狀態才可以 Edit / Deactivate
      - 要 Delete 的話, 要先 Deactivate 讓狀態變成 Deactived 才能 Delete
    - 無論是 Edit / Deactivate, 最久 60 分鐘才會生效

2025年1月9日 星期四

Akamai CDN access logs to S3 bucket

目的: 把 blah.foobar.com 的 CDN access log 轉送到 s3 bucket 備查

0. AWS S3
  - 開好 bucket
    - blah-foobar-com-logs @us-west-2
  - 建立完全存取這個 bucket 的 IAM User 
    - S3-blah-foobar-com-logs-ReadWrite
  - 在這個 IAM User 建立 access key pair

1. COMMON SERVICES - DataStream
  - 點選 Create stream - Delivery Products
    - CONFIGURATION
      - Display Name: blah-foobar-com-logs-to-s3
      - Group: Foobar-W-DEADBF
      - Include properties: 勾選 blah.foobar.com
    - DATA SETS
      - Log information
        - Request time
      - Message exchange data
        - Bytes
        - Client IP
        - HTTP status code
        - Protocol type
        - Request host
        - Request method
        - Request path
        - Request port
        - Response Content-Length
        - Response Content-Type
        - User-Agent
        - SSL overhead time
        - SSL version
        - Object size
        - Uncompressed size
        - Total bytes
        - Query string
      - Request header data
        - Cookie
        - Range
        - Referer
        - X-Forwarded-For
        - Max age
      - Network performance data
        - Error code
      - Cache data
        - (null)
      - Geo data
        - (null)
      - Web security
        - (null)
      - EdgeWorkers
        - (null)
      - Content protection
        - (null)
      - Custom fields
        - Custom field
      - Log file
        - Log format: Json
    - DELIVERY
      - Destination
        - Destination: 選 Amazon S3
        - Display name: blah-foobar-com-logs-to-s3
        - Bucket: blah-foobar-com-logs
        - Path: logs/{%Y}/{%m}/{%d}/{%H}
          - 檔案儲存結構用 年/月/日/小時 存放
          - 目前每小時約產生兩千多個小檔案, gzip -d 解開之後就是純文字檔案
        - Region: us-west-2
        - Access key ID: (bucket 的 IAM user 的 access key id)
        - Secret access key: (bucket 的 IAM user 的 secret access key)
      - Delivery options
        - Filename: ak -[random-string]-[epoch-timestamp]-[random-string]- ds
          - 中間這一段沒辦法改, 我比較想要 [epoch-timestamp] 在前面比較好用
        - Push frequency: 60 Seconds
    - SUMMARY
  - 幾個步驟建立完之後, blah-foobar-com-logs-to-s3 的 status 是 Activating - V1
    - 只能 View / History / Clone, 無法 Edit / Deactivate / Delete
    - V1 是指這個 Stream 設定是 version 1, 不是 DataStream 1 的意思

2. CDN - Properties
  - 選 blah.foobar.com 再點選版本, 點 Edit New Version
  - 左邊選 Default Rule, 右邊點 +Behavior 新增 DataStream
    - Stream version 只有選 DataStream 2 會過
      - DataStream 1 要被淘汰掉
      - 選 DataStream 1 會跳出警告訊息, 可以 Save 但無法 Activate
    - Stream names 選 blah-foobar-com-logs-to-s3
    - Sample rate 預設 100
      - 通靈用的話一定要選 100, 要不然缺 log 會讓你通到屎
  - 最後 Save
  - 然後 Activate 這個新版本上線
    - 最久 10 分鐘才會完成

3. 回到 COMMON SERVICES - DataStream
  - blah-foobar-com-logs-to-s3 的 status 在 Properties 上完之後變成 Active - V1
    - 第一次比較快
    - Active 狀態才可以 Edit / Deactivate
      - 要 Delete 的話, 要先 Deactivate 讓狀態變成 Deactived 才能 Delete
    - 無論是 Edit / Deactivate, 最久 60 分鐘才會生效

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, 但是實際上裡面還在慢慢斷開, 沒那麼快拆完...

2022年11月30日 星期三

GCP - copy IAM custom role R from project A to project B

Role ID: projects/A/roles/R

0. gcloud auth login (with enough permission)

1. gcloud iam roles describe R --project=A > R.txt

2. gcloud iam roles create R --project=B --file=R.txt

2022年5月8日 星期日

random password generator - use jot + rs

適用於 BSD OS 與 Mac 環境

jot -r -c 160 / z | \
  grep -e '[a-z]' -e '[A-Z]' -e '[0-9]' | \
  rs -g0 0 64

以上會產生出 160 個 ascii / 到 z 的字元, 只擷取 a-z A-Z 0-9 來用, 集結成每行長度 64 的字串.

如果要放行一些符號的話, 像是底線(_)也在 / 到 z 的範圍內, 就可以在 grep 指令加上 -e _ 擷取來用.


Ascii table (credit: https://c-for-dummies.com/blog/?p=4895)

2022年4月27日 星期三

Terraform - google_redis_instance with auth_enabled is true

google_redis_instance 裡面是這樣寫的:

auth_enabled - (Optional) Optional. Indicates whether OSS Redis AUTH is enabled for the instance. If set to "true" AUTH is enabled on the instance. Default value is "false" meaning AUTH is disabled.

auth_string - (Optional) AUTH String set on the instance. This field will only be populated if auth_enabled is true.

redis 還是打開 auth 才安全, 所以當然就這樣設定:
resource "google_redis_instance" "this" { ... auth_enabled = true auth_string = "023dbce5e060641d09218027704ca4b3" ... }
接著 terraform apply 下去打開 auth...
Error: Value for unconfigurable attribute with module.redis.module.redis-general.google_redis_instance.this, on modules/redis/main.tf line 24, in resource "google_redis_instance" "this": 24: auth_string = "023dbce5e060641d09218027704ca4b3" Can't configure a value for "auth_string": its value will be decided automatically based on the result of applying this configuration.

所以是會自動生成的意思? 那拿掉 auth_string 的設定, 先 terraform apply 上去之後, 再 terraform show 出來看 auth_string 的內容...

# module.redis.module.redis-general.google_redis_instance.this: resource "google_redis_instance" "this" { alternative_location_id = "us-west1-c" auth_enabled = true auth_string = (sensitive value) ...
竟然看不到... oroz

查了一下, 得用 terraform show -json 才看得到, 執行下去會得到一行很長很長的 json, 那就多用 jq 轉一下: terraform show -json | jq .

"resources": [ { "address": "module.redis.module.redis-general.google_redis_instance.this", "mode": "managed", "type": "google_redis_instance", "name": "this", "provider_name": "registry.terraform.io/hashicorp/google", "schema_version": 0, "values": { "alternative_location_id": "us-west1-c", "auth_enabled": true, "auth_string": "ded6f8e9-5c32-4ebb-b0fb-086a444baa7f", ...
終於看到啦~