TerraformでOCIポスグレを起動&パラメータをVaultシークレットに保存

## 概要
Terraformを使用してOCIのPostgreSQLデータベースを構築し、そのコンフィグ情報をOCI Vaultのシークレットに自動で保存する手順を説明します。
これにより、セキュリティを保つたまま自動化された構成を実現できます。


## Terraformの流れ
一度に下記を実行します。

* TerraformでOCI Database with PostgreSQLを構築
* データベースサービスのパラメータ情報をTerraformで取得
* TerraformでVaultシークレットにパラメータ情報を自動追加


## 事前準備
事前に作成必要です。
* VCN(プライベートサブネット)
* Vault
* VaultのAESのマスター暗号化キー

Terraformの実行はOCIコンソール画面右上のコードエディタからが便利です。
デフォルトでterraformが使えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2846649/05b3ea09-23a5-758a-9cf4-4f369125cd4e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2846649/573710a5-94fa-812e-339e-a08057d8f5eb.png)



## Terraformスクリプト

まず以下のファイルを作っていきます。
```terraform: provider.tf
provider "oci" {
  tenancy_ocid     = var.tenancy_ocid
  user_ocid        = var.user_ocid
  fingerprint      = var.fingerprint
  private_key_path = var.private_key_path
  region           = var.region
}
```

```terraform: variables.tf
variable "compartment_id" {
  description = "The OCID of the compartment in which to create resources."
  type        = string
}

variable "tenancy_ocid" {
  description = "The OCID of the tenancy."
  type        = string
}

variable "user_ocid" {
  description = "The OCID of the user."
  type        = string
}

variable "fingerprint" {
  description = "The fingerprint of the API key used for authentication."
  type        = string
}

variable "private_key_path" {
  description = "The path to the private API key file."
  type        = string
}

variable "region" {
  description = "The OCI region in which to create resources (e.g., 'us-phoenix-1')."
  type        = string
}

variable "secret_name" {
  description = "The name of the secret in the Vault."
  type        = string
}

variable "key_id" {
  description = "The OCID of the key to encrypt or decrypt data in the Vault."
  type        = string
}

variable "vault_id" {
  description = "The OCID of the Vault used for managing secrets and keys."
  type        = string
}

variable "secret_content_name" {
  description = "The name of the content stored in the secret."
  type        = string
}

variable "secret_content_type" {
  description = "The content type of the secret (e.g., 'PLAIN_TEXT' or 'APPLICATION_JSON')."
  type        = string
}

variable "db_system_credentials_username" {
  description = "The username for the database administrator (e.g., 'admin')."
  type        = string
}

variable "db_system_credentials_password_details_password_type" {
  description = "The type of password for the database (e.g., 'PLAIN_TEXT')."
  type        = string
  default     = "PLAIN_TEXT"
}

variable "db_system_credentials_password_details_password" {
  description = "The password for the database administrator."
  type        = string
  sensitive   = true
}

variable "db_system_db_version" {
  description = "The version of the database to deploy"
  type        = string
}

variable "db_system_display_name" {
  description = "The display name of the database system."
  type        = string
}

variable "db_system_network_details_subnet_id" {
  description = "The OCID of the subnet in which to create the database system."
  type        = string
}

variable "db_system_shape" {
  description = "The shape of the database system."
  type        = string
}

variable "db_system_storage_details_is_regionally_durable" {
  description = "Whether the database system storage is regionally durable."
  type        = bool
  default     = true
}

variable "db_system_storage_details_system_type" {
  description = "The storage system type for the database."
  type        = string
}

variable "db_system_source_source_type" {
  description = "The source type for the database system."
  type        = string
}
```


```terraform: terraform.tfvars
tenancy_ocid = "(your_tenancy_ocid)"
user_ocid = "(your_user_ocid)"
fingerprint = "(your_fingerprint)"
private_key_path = "~/.oci/oci_api_key.pem"
region = "us-ashburn-1"
compartment_id = "(your_compartment_id)"

db_system_credentials_password_details_password = "YourSecurePassword123"
db_system_credentials_username = "admin"
db_system_db_version = "15"
db_system_display_name = "example-db-system"
db_system_network_details_subnet_id = "(ポスグレを配置するプライベートサブネットOCID)"
db_system_shape = "PostgreSQL.VM.Standard.E4.Flex.2.32GB"
db_system_storage_details_is_regionally_durable = true
db_system_storage_details_system_type = "OCI_OPTIMIZED_STORAGE"
db_system_source_source_type = "NONE"

key_id= "(vaultのマスター暗号化キーOCID)"
vault_id = "(vaultのOCID)"
secret_name = "tfmake"
secret_content_name = "tfmake_content"
secret_content_type = "BASE64"
```

```terraform: main.tf
# 1. DBシステムの作成
resource "oci_psql_db_system" "test_db_system" {
  compartment_id = var.compartment_id

  credentials {
    password_details {
      password_type = var.db_system_credentials_password_details_password_type
      password      = var.db_system_credentials_password_details_password
    }
    username = var.db_system_credentials_username
  }

  db_version   = var.db_system_db_version
  display_name = var.db_system_display_name

  network_details {
    subnet_id = var.db_system_network_details_subnet_id
  }

  shape = var.db_system_shape

  storage_details {
    is_regionally_durable = var.db_system_storage_details_is_regionally_durable
    system_type           = var.db_system_storage_details_system_type
  }

  source {
    source_type = var.db_system_source_source_type
  }
}

# 2. DBシステムの接続詳細を取得
data "oci_psql_db_system_connection_detail" "test_db_system_connection_detail" {
  db_system_id = oci_psql_db_system.test_db_system.id
}

# 3. Vaultシークレットに接続情報を登録
resource "oci_vault_secret" "test_secret" {
  compartment_id = var.compartment_id
  key_id         = var.key_id
  secret_content {
    content_type = var.secret_content_type
    content = base64encode(
      jsonencode({
        fqdn       = data.oci_psql_db_system_connection_detail.test_db_system_connection_detail.primary_db_endpoint[0].fqdn
        ip_address = data.oci_psql_db_system_connection_detail.test_db_system_connection_detail.primary_db_endpoint[0].ip_address
        port       = data.oci_psql_db_system_connection_detail.test_db_system_connection_detail.primary_db_endpoint[0].port
      })
    )
    name = var.secret_content_name
  }
  secret_name = var.secret_name
  vault_id    = var.vault_id
}

```

## Terraform実行
あとは下記を実行していくのみです。
* terraform init
* terraform plan
* terraform apply

## 実行結果

ポスグレDBが作成され、かつシークレットも作成されました。
シークレット中身を見ていくと、作成されたポスグレDBのエンドポイント情報がシークレットに保存できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2846649/980e9da3-2285-8d21-4542-eea7e2cfb6ba.png)





## 参考リンク

* Terraform
    * [OCIポスグレマネージド](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/psql_db_system)
    * [OCIポスグレの起動パラメータ取得](https://registry.terraform.io/providers/oracle/oci/latest/docs/data-sources/psql_db_system_connection_detail)
    * [Vaultシークレット](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/vault_secret)
* Vault
    * [OCI Valutシークレットを使ってセキュアにキーを保存](https://qiita.com/maishikawa/items/904577a753d8a849b5a7)