Terraform RDS SQLServer 編

  • Terraform
  • RDS
  • SQLServer
  • 前提

    Aurora PostgreSQL を構築する前に、ネットワーク環境(VPC,Subnet,Security Group)や、CloudWatch Logs にログを転送するための IAM Role などが必要です。

    Terraform でインフラ構築するときは、その一つ一つのコンポーネントを理解しておく必要があります。

    ただ、今回は RDS SQLServer 構築の話を中心に書きたいと思いますので、周辺の説明はサンプルコードの記載に留めて省略していきたいと思います。

    Aurora PostgreSQL に必要なもの

    RDS Oracle を構築するための resource は aws_db_instance です。

    そして、この aws_db_instance を実行するために必要な要素をがこちらです。

    • aws_db_subnet_group
    • aws_security_group
    • aws_iam_role
    • aws_db_parameter_group
    • aws_db_option_group

    AWS は親切なので default で "よろしく" やってくれるところがありますが、それでは現場で通用しませんので、1つ1つ設定していきたいと思います。

    準備

    aws_db_subnet_group

    db subnet を作成する前に、subnet を複数作成しておく必要がありますが、そこは省きたいと思います。

    # DB Subnet # https://www.terraform.io/docs/providers/aws/r/db_subnet_group.html resource "aws_db_subnet_group" "db_subnet" { name = "sample-db-subnet-gp" subnet_ids = [ aws_subnet.subnet_rds.0.id, # 作成済みの subnet id を参照 aws_subnet.subnet_rds.1.id, # 作成済みの subnet id を参照 aws_subnet.subnet_rds.2.id # 作成済みの subnet id を参照 ] tags = { Service = "sample" } }

    aws_security_group

    セキュリティ要件によってはアウトバウンド通信の制御も必要でしょう。今回はインバウンド通信だけ制限します。

    # Security Group # https://www.terraform.io/docs/providers/aws/r/security_group.html resource "aws_security_group" "rds_sg" { name = "sample-rds-sg" description = "sample rds security group" vpc_id = aws_vpc.vpc.id # 作成済みの vpc id を参照 # 許可するインバウンド通信を記載 ingress { description = "SQLServer" from_port = 1433 to_port = 1433 protocol = "tcp" security_groups = [ aws_security_group.public_sg.id # list 形式で記載, public subnet id を参照 ] } # 許可するアウトバウンド通信を記載 egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } tags = { Name = "sample-rds-sg" Service = "sample" } }

    aws_iam_role

    コンソールで RDS を作成した際には、ログを CloudWatch Logs に転送する設定を選択すると、専用のサービスロール(AmazonRDSEnhancedMonitoringRole )が自動的にセットされています。

    これも Terraform の管理対象に含めるために、以下のロールを作成します。

    # aws_iam_role # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role resource "aws_iam_role" "monitoring_role" { name = "sample-rds-monitoring-role" assume_role_policy = <<EOF { "Version": "2012-10-17", "Statement": [ { "Action": "sts:AssumeRole", "Principal": { "Service": "monitoring.rds.amazonaws.com" }, "Effect": "Allow" } ] } EOF tags = { Name = "sample-rds-monitoring-role" Service = "sample" } } # aws_iam_policy_attachment # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy_attachment resource "aws_iam_policy_attachment" "rds_monitoring_policy_attachment" { name = "rds_monitoring_policy_attachment" roles = [aws_iam_role.rds_monitoring_role.name] # list policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonRDSEnhancedMonitoringRole" }

    ポイントは、AssumeRole を "monitoring.rds.amazonaws.com" とすることです。 "rds.amazonaws.com" ではありません。

    今回は監査設定も入れますので S3 へ監査ログを転送するためのロールも作成します。

    # rds_role resource "aws_iam_role" "rds_role" { name = "rds-role" assume_role_policy = <<EOF { "Version": "2012-10-17", "Statement": [ { "Action": "sts:AssumeRole", "Principal": { "Service": "rds.amazonaws.com" }, "Effect": "Allow" } ] } EOF tags = { Name = "sample-rds-role" Service = "sample" } } resource "aws_iam_policy_attachment" "rds_policy_1_attachment" { name = "rds_policy_1_attachment" roles = [aws_iam_role.rds_role.name] policy_arn = aws_iam_policy.rds_policy_1.arn } # aws_iam_policy # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy # https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/Appendix.SQLServer.Options.Audit.html # https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/SQLServer.Procedural.Importing.html resource "aws_iam_policy" "rds_policy_1" { name = "rds_policy_1" path = "/" description = "rds_policy_1" policy = <<EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:ListAllMyBuckets", "s3:ListBucket", "s3:PutObject", "s3:GetObject", "S3:GetBucketAcl", "s3:GetBucketLocation", "s3:GetObjectMetaData", "s3:ListMultipartUploadParts", "s3:AbortMultipartUpload" ], "Resource": "*" } ] } EOF }

    aws_db_parameter_group

    SQLServer にはあまり詳しくないため、パラメータグループは特に設定はなしとしておきます。

    # aws_db_parameter_group # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/db_parameter_group resource "aws_db_parameter_group" "rds_sqlserver_pg" { name = "sample-rds-sqlserver-pg" family = "sqlserver-se-14.0" tags = { Service = "sample" } }

    aws_db_option_group

    3つのオプションを設定します。

    # aws_db_option_group # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/db_option_group resource "aws_db_option_group" "rds_sqlserver_opg" { name = "sample-rds-sqlserver-opg" engine_name = "sqlserver-se" major_engine_version = "14.00" option { option_name = "Timezone" option_settings { name = "TIME_ZONE" value = "Tokyo_Standard_Time" } } option { option_name = "SQLSERVER_BACKUP_RESTORE" option_settings { name = "IAM_ROLE_ARN" value = aws_iam_role.rds_role.arn } } option { option_name = "SQLSERVER_AUDIT" option_settings { name = "ENABLE_COMPRESSION" value = true } option_settings { name = "S3_BUCKET_ARN" value = "arn:aws:s3:::koizumi-logs" } option_settings { name = "IAM_ROLE_ARN" value = aws_iam_role.rds_role.arn } option_settings { name = "RETENTION_TIME" value = 0 } } tags = { Service = "sample" } }

    RDS SQLServer 構築

    aws_db_instance

    Terraform で迷うところが、エンジンバージョンなどの記載方法です。少しでも間違えると、そんなバージョンありません、というエラーが出てしまいます。

    なるべく全ての項目を指定する形で作成しました。

    # aws_db_instance # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/db_instance resource "aws_db_instance" "rds_sqlserver_instance" { identifier = "sample-sqlserver" instance_class = "db.r5.large" engine = "sqlserver-se" engine_version = "14.00.3281.6.v1" license_model = "license-included" multi_az = false # default false username = "xxxxx" password = "xxxxxxxxxx" # storage storage_type = "gp2" # The default is "io1", "gp2", "standard" (magnetic) allocated_storage = 20 # depends on storage_type max_allocated_storage = 1000 # Must be greater than or equal to allocated_storage or 0 to disable Storage Autoscaling. storage_encrypted = true # declare KMS key ARN if true, default false # kms_key_id = "" # set KMS ARN if storage_encrypted is true, default "aws/rds" # network db_subnet_group_name = aws_db_subnet_group.db_subnet.name vpc_security_group_ids = [aws_security_group.private_sg.id] port = 1433 # monitoring performance_insights_enabled = false # default false monitoring_interval = 60 # 0, 1, 5, 10, 15, 30, 60 (seconds). default 0 (off) monitoring_role_arn = aws_iam_role.monitoring_role.arn enabled_cloudwatch_logs_exports = ["agent", "error"] # backup snapshot backup_retention_period = 0 # default 7 (days). 0 = disabled. copy_tags_to_snapshot = true # default false delete_automated_backups = true # default true deletion_protection = false # default false skip_final_snapshot = true # default false final_snapshot_identifier = "sample-sqlserver-snapshot" # must be provided if skip_final_snapshot is set to false. # window time backup_window = "01:00-01:30" maintenance_window = "Mon:02:00-Mon:03:00" # options parameter_group_name = aws_db_parameter_group.rds_sqlserver_pg.name option_group_name = aws_db_option_group.rds_sqlserver_opg.name character_set_name = "Japanese_CI_AS" # Oracle and Microsoft SQL timezone = "Tokyo Standard Time" # only SQLServer auto_minor_version_upgrade = false # default true # tags tags = { Service = "sample" } }

    terraform apply

    実行してみます。

    PS C:\Users\...\terraform_aws> terraform apply Plan: 10 to add, 0 to change, 0 to destroy. Do you want to perform these actions? Terraform will perform the actions described above. Only 'yes' will be accepted to approve. Enter a value: yes Apply complete! Resources: 10 added, 0 changed, 0 destroyed.

    実行結果を確認

    実行結果をコンソールで確認してみます。

    aws_terraform_rds_sqlserver_1

    aws_terraform_rds_sqlserver_2

    aws_terraform_rds_sqlserver_3

    aws_terraform_rds_sqlserver_4

    aws_terraform_rds_sqlserver_5

    一通り確認することができました。

    以上です。

  • Terraform
  • RDS
  • SQLServer