iT邦幫忙

2021 iThome 鐵人賽

DAY 8
0
DevOps

關於我幫新公司建立整套部屬流程那檔事系列 第 8

EP08 - 用 Terraform 建置 AWS RDS 服務(以 Aurora Postgres 為例)

前幾天我們建立起 Gitlab,
並將它串接到 Jenkins,
今天將繼續部署基礎設施,
我們將使用 Terraform 建立 Amazon Relational Database Service(AWS RDS),
AWS 支援市面上大家常用的主流資料庫,
對於大部分的應用都可以符合需求。

挑戰至今,
我們仍未建立一個 Web 服務做部署,
未來的幾天,
預計會使用 Python Django 建立一個 Portal,
而後建立 EC2,
並為其配置 Server 環境,
先進行手動部署,
最後才會將最後一哩路,
自動部署做起來。

Terrform 配置資料庫

使用 KMS 將資訊加密

什麼是 KMS

AWS Key Management Service (KMS) 讓您輕鬆建立及管理加密金鑰
並控制多種 AWS 服務和應用程式的使用

AWS KMS 是安全的彈性服務
採用已通過 FIPS 140-2 驗證
或正在驗證中的硬體安全模組來保護您的金鑰

AWS KMS 還與 AWS CloudTrail 整合
提供您所有金鑰使用狀況的日誌
協助您滿足法規和合規要求

除了我們自建的服務
可以使用 AWS KMS 做加密解密以外
比較常用的還是 AWS 上的內部服務
例如:System Session Management(SSM),允許 AWS 使用者在沒有 Key 的情況下,SSH 進 EC2 並對 EC2 進行操作,設定這個操作的過程,也需要設定 KMS

Terraform 新增一個 KMS

在 maint.tf 中增加以下兩行
key_usage 和 customer_master_key_spec 都有固定的寫法
詳情可參考 Terraform AWS KMS Key

resource "aws_kms_key" "rds" {
    description              = "It is used to encrypt and decrypt for RDS"
    key_usage                = "ENCRYPT_DECRYPT"
    customer_master_key_spec = "SYMMETRIC_DEFAULT"
    deletion_window_in_days  = 10
}

resource "aws_kms_alias" "rds" {
    name          = "alias/rds"
    target_key_id = aws_kms_key.rds.key_id
}

回到 console 中執行配置

terraform apply

完成後我們就可在 aws 上看到我們建立的 KMS
記下「金鑰 ID」,等等會用到
https://ithelp.ithome.com.tw/upload/images/20210919/20141518Xx5tj7VEu2.png

將帳密儲存到檔案中

在建立 RDS(AWS 的資料庫) 時
我們就需要設定帳號密碼
如果我們直接用明碼寫進 terraform 中
就會進版控
在此之前我們需要下個指令先將它存到一個檔案中

基於安全性規則
記得把 admin 和 password 改掉
這裡並不是希望大家真的照打
而且我們等等要用到的資料庫是 postgres
admin

echo -n 'admin' > plaintext-username
echo -n 'password' > plaintext-password

將帳號和密碼檔案加密

前幾天我們建立好的 aws cli 終於要在今天派上用場
我們會透過 aws-cli 將檔案加密
此次實作參考自 stackoverflow 的討論

記得將加密過後的帳密複製出來
等等在新增 RDS 時會用到

aws kms encrypt --key-id ab123456-c012-4567-890a-deadbeef123 --plaintext fileb://plaintext-username --output text --query CiphertextBlob

aws kms encrypt --key-id ab123456-c012-4567-890a-deadbeef123 --plaintext fileb://plaintext-password --output text --query CiphertextBlob

https://ithelp.ithome.com.tw/upload/images/20210919/20141518vi1x4ugo8R.png

Terraform 新增 RDS

什麼是 RDS

Amazon Relational Database Service (Amazon RDS) 是 Amazon 提供的資料庫 PaaS 服務
讓使用者能夠在雲端中輕鬆設定、操作和擴展關聯式資料庫

它提供經濟實惠且可調整大小的容量
且可自動處理硬體佈建、資料庫設定、修補程式和備份等耗時的管理任務

這讓您有更多時間專注在應用程式,以提供其所需的快速效能、高可用性、安全性和相容性。

密碼解密

這裡需要把剛剛加密過後的 username 和 password 放進 payload 中
請 aws 幫忙解密

data "aws_kms_secrets" "portal" {
    secret {
        name    = "master_username"
        payload = ""
    }

    secret {
        name    = "master_password"
        payload = ""
    }
}

建立 Security group

RDS 提供多種資料庫可供選
其中也有 Amazon 自己做的 Amazon Aurora
Amazon Aurora 提供相容於 MySQL 的版本
以及相容於 Postgres 的版本
我們預計使用 Amazon Aurora 相容於 Postgres 的版本
所以 inbound/outbound 是設定 Postgres 使用的 port 5432

resource "aws_security_group" "rds_portal" {
    name        = "rds-portal"
    description = "It used for RDS."
    vpc_id      = data.aws_vpc.default.id
    tags        = { Name = "RDS Postgres" }
    revoke_rules_on_delete = null
}

resource "aws_security_group_rule" "rds_portal_igress_5432" {
    type              = "ingress"
    from_port         = 5432
    to_port           = 5432
    cidr_blocks       = [var.personal_cidr,]
    protocol          = "tcp"
    security_group_id = aws_security_group.rds_portal.id
}

resource "aws_security_group_rule" "rds_portal_egress_22" {
    type              = "egress"
    from_port         = 5432
    to_port           = 5432
    cidr_blocks       = [var.personal_cidr,]
    protocol          = "tcp"
    security_group_id = aws_security_group.rds_portal.id
}

建立資料庫子網路群組

啥?子網路群組?
沒錯,無論是預設的網段
還是未來我們打算自己建立 VPC 並規劃網段
我們都可以指定資料庫都只在哪個網段
而不是所有網段都套用

會有這設定
是因為我們可以透過路由規則的設計
讓有些網段可以公開對外
而有些網段無法直接對外連接
資料庫通常來說就蠻需要此設計
透過路由規則的設計
讓他只存在於不能對外的 subnet
不過這部分如果我鐵人賽有繼續寫
再看看有沒有機會把這個坑補完

resource "aws_db_subnet_group" "rds_subnet_group" {
    name       = "database_subnet_group"
    subnet_ids = sort(data.aws_subnet_ids.subnet_ids.ids)

    tags = {
        "Name" = "Database subnet group"
    }
}

建立參數組

因為 RDS 皆為 PaaS 服務
我們無法直接接觸作業系統層級的設定
過去有實際建立資料庫的夥伴
或多或少也曾經調整過資料庫的參數
RDS 特別針對不同的資料庫以及各版本做出參數組供參考
在建立資料庫前
我們需要特別建立參數組
並在建立資料庫時指令參數組
未來如果需要調整資料庫設定
則直接調整參數組的數值即可

我們使用的 resource 是 aws_rds_cluster_parameter_group
而不是 aws_db_parameter_group 喔

resource "aws_rds_cluster_parameter_group" "cluster_aurora_postgres_13" {
    name        = "aurora-db-postgres13-cluster-parameter-group"
    family      = "aurora-postgresql13"
    description = "aurora-db-postgres13-cluster-parameter-group"
}

建立資料庫

定義好參數
設定好帳密和 inbound/outbound
終於我們要來建立資料庫了

其實 aws rds 有兩種形式
一種是單純建立 instance
可以理解成幫你建立一個 EC2 並裝好資料庫的 Server

另一種則是建立叢集
叢集內可建立多個 instance
aws 會透過內部機制幫你對多個叢集做讀寫/同步
我們是使用 Aurora
因此不得不建立 Cluster
並在 Cluster 裡面再另外建立 instance
AWS API 文件中也寫得很明確

Not applicable. Aurora cluster volumes automatically grow as the amount of data in your database increases, though you are only charged for the space that you use in an Aurora cluster volume.

如果你直接用建立 instance 的語法
而不是建立 cluster 的方式
會出 allocated storage 相關的錯誤
這個雷我已經幫大家踩過了
希望大家不用再踩一次了

resource "aws_rds_cluster" "ithome_ironman_cluster" {
    cluster_identifier              = "ithome-ironman-cluster"
    engine                          = "aurora-postgresql"
    engine_version                  = "13.3"
    availability_zones              = ["ap-northeast-1a", "ap-northeast-1c", "ap-northeast-1d"]
    db_subnet_group_name            = aws_db_subnet_group.rds_subnet_group.name
    db_cluster_parameter_group_name = aws_rds_cluster_parameter_group.cluster_aurora_postgres_13.name
    database_name                   = "ironman2021" 
    master_username                 = data.aws_kms_secrets.portal.plaintext["master_username"]
    master_password                 = data.aws_kms_secrets.portal.plaintext["master_password"]
    skip_final_snapshot             = true
    vpc_security_group_ids          = [aws_security_group.rds_portal.id]
    tags                            = {}
}

resource "aws_rds_cluster_instance" "ithome_ironman_rds_instance" {
    count              = 1
    identifier         = "aurora-portal-cluster-${count.index}"
    cluster_identifier = aws_rds_cluster.ithome_ironman_cluster.id
    instance_class     = "db.t3.medium"
    engine             = aws_rds_cluster.ithome_ironman_cluster.engine
}

執行配置

cluster 與資料庫的建置需要七、八分鐘的時間
可以喝個水或上個廁所休息一下再回來

terraform apply

建立完後
就可以在 aws console 看到結果
https://ithelp.ithome.com.tw/upload/images/20210920/20141518jr14dAUSpS.png

提醒

在 checkin code 的時候
不要不小心將產生的 plaintext-username 和 plaintext-password 進版控了

參考資料:

  1. Amazon KMS
  2. Terraform AWS KMS Key
  3. AWS: Using a KMS-encrypted master password to create a RDS instance
  4. Amazon RDS
  5. AWS API CreateDBInstance
  6. storage type error with terraform and aurora postgresql

上一篇
EP07 - Jenkins Pipeline 整合 Gitlab 使用 Webhook
下一篇
EP09 - 建立 Django 專案和 EC2 環境 並手動部署到 EC2
系列文
關於我幫新公司建立整套部屬流程那檔事30

尚未有邦友留言

立即登入留言