暗号化されたRDSスナップショットを別AWSアカウントで使えるようにするためのスクリプトかいた

# AWSの仕様

https://repost.aws/ja/knowledge-center/share-encrypted-rds-snapshot-kms-key

に記載の通りですね。

これを楽にするためのスクリプトをかきました。

KMSはTerraformで作成している前提になります。

## KMSの作成のTerraformコード

- modules/kms_rds_snapshot/main.tf

```hcl
provider "aws" {
  profile = var.delegator_alias
  alias   = "delegator"
  region  = "ap-northeast-1"

  default_tags {
    tags = {
      Environment  = var.env
      Owner        = var.owner
      BillingGroup = "${var.project}/${var.env}"
      IaC          = "Terraform"
    }
  }
}


# 共有先のAWSアカウント情報取得
data "aws_caller_identity" "target" {
  provider = aws.delegator
}

# 共有元のAWSアカウント情報取得
data "aws_caller_identity" "current" {}


# 暗号化RDS スナップショット共有のためKMSキーの権限付与
resource "aws_kms_key" "this" {
  description = "rds snapshot encryption key"
  policy = jsonencode({
    Id = "key-consolepolicy-3"
    Statement = [
      {
        "Sid" : "Enable IAM User Permissions",
        "Effect" : "Allow",
        "Principal" : {
          "AWS" : "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"
        },
        "Action" : "kms:*",
        "Resource" : "*"
      },
      {
        "Sid" : "Allow use of the key",
        "Effect" : "Allow",
        "Principal" : {
          "AWS" : "arn:aws:iam::${data.aws_caller_identity.target.account_id}:root"
        },
        "Action" : [
          "kms:Encrypt",
          "kms:Decrypt",
          "kms:ReEncrypt*",
          "kms:GenerateDataKey*",
          "kms:DescribeKey"
        ],
        "Resource" : "*"
      },
      {
        "Sid" : "Allow attachment of persistent resources",
        "Effect" : "Allow",
        "Principal" : {
          "AWS" : "arn:aws:iam::${data.aws_caller_identity.target.account_id}:root"
        },
        "Action" : [
          "kms:CreateGrant",
          "kms:ListGrants",
          "kms:RevokeGrant"
        ],
        "Resource" : "*",
        "Condition" : {
          "Bool" : {
            "kms:GrantIsForAWSResource" : "true"
          }
        }
      }
    ]
    Version = "2012-10-17"
  })

  multi_region             = false
  key_usage                = "ENCRYPT_DECRYPT"
  enable_key_rotation      = false
  customer_master_key_spec = "SYMMETRIC_DEFAULT"
}


resource "aws_kms_alias" "this" {
  name          = "alias/rds-snapshot-shared/${var.env}-key"
  target_key_id = aws_kms_key.this.key_id
}

```

- modules/kms_rds_snapshot/variables.tf

```hcl
# Variable
variable "project" {
}

variable "env" {
}

variable "owner" {
}

variable "default_config" {
}


variable "delegator_alias" {

}
```

- kms_rds_snapshot.tf

```hcl
module "kms_rds_snapshot" {
  source  = "../../modules/kms_rds_snapshot"
  env     = var.env
  project = var.project
  owner   = var.owner

  delegator_alias = var.targetprofile

  default_config = {}

}
```

- variables.tf

```hcl
# Variable
variable "project" {
  default = "testproject"
}

variable "env" {
  default = "develop"
}


variable "region" {
  default = "ap-northeast-1"
}

variable "owner" {
  default = "SRE" # 実行者のオーナー情報適宜変更
}

# 作成対象のProfile名
variable "targetprofile" {
  default = "sampleawsprofile"

}

```

- ファイルツリー

参考までに

```sh
├── environments
│   ├── developers_init
│   │   ├── README.md
│   │   ├── aws_info.txt
│   │   ├── backend.tf
│   │   ├── data.tf
│   │   ├── kms_rds_snapshot.tf
│   │   ├── main.tf
│   │   └── variables.tf
├── modules
│   ├── kms_rds_snapshot
│   │   ├── main.tf
│   │   └── variables.tf
└── README.md

```

## 別AWSアカウントにスナップショットをコピーするスクリプト

- copy_rds_snapshot.sh

```sh
#!/bin/bash

# エラーが発生した場合にスクリプトを終了させる
set -e

# ターゲットのDBクラスタ名を設定
_TARGETCLUSTER="コピー元のDBクラスタ名"

# 最新のDBクラスタスナップショットのARNを取得
_SNAPSHOTARN=$(aws rds describe-db-cluster-snapshots \
 --db-cluster-identifier "${_TARGETCLUSTER}" \
 --query 'sort_by(DBClusterSnapshots,&SnapshotCreateTime)[-1].[DBClusterSnapshotArn]' \
 --output text)

# KMSキーのARNを設定
_KMSARN="Terraformで作成したKMSのARNを指定"

# スナップショットのコピーを作成
_TARGETSNAPSHOTID="${_TARGETCLUSTER}$(date +%Y%m%d)snapshot"
aws rds copy-db-cluster-snapshot \
 --source-db-cluster-snapshot-identifier "${_SNAPSHOTARN}" \
 --target-db-cluster-snapshot-identifier "${_TARGETSNAPSHOTID}" \
 --kms-key-id "${_KMSARN}"
if [ $? -ne 0 ]; then
 echo "スナップショットのコピー中にエラーが発生しました。"
 exit 1
fi

# スナップショットが利用可能になるまで待機
echo "スナップショットのコピーが完了するまで待機中..."
aws rds wait db-cluster-snapshot-available \
 --db-cluster-snapshot-identifier "${_TARGETSNAPSHOTID}"
if [ $? -ne 0 ]; then
 echo "スナップショットが利用可能になるのを待つ中にエラーが発生しました。"
 exit 1
fi

# スナップショットの属性を変更
echo "スナップショットの属性を変更中..."
aws rds modify-db-cluster-snapshot-attribute \
 --db-cluster-snapshot-identifier "${_TARGETSNAPSHOTID}" \
 --attribute-name restore \
 --values-to-add '["コピーしたいAWSアカウントID"]' \
 --region ap-northeast-1
if [ $? -ne 0 ]; then
 echo "スナップショットの属性変更中にエラーが発生しました。"
 exit 1
fi

echo "スナップショットの属性変更が完了しました。"
```

### スクリプト修正

変更対象パラメータを環境に合わせて変更してください。

- コピー元のDBクラスタ名
- Terraformで作成したKMSのARNを指定
- コピーしたいAWSアカウントID

スナップショット作成が完了するまで
時間を要する関係上、それを待つための処理としてwaitを入れています。

### 実行方法

```sh
sh copy_rds_snapshot.sh
```

## まとめ

なぜかAuroraClusterのスナップショットコピーが
Terraformでは実行できないのでスクリプトで実行する方法の紹介でした。

地味に面倒な処理をスクリプト化して実行中は他の作業ができるので
実装して良かったですね。