AWS Backup EC2 を実運用へ導入したときのあれやこれや

# はじめに
* 2020年1月、ようやく EC2 の バックアップ/リストア を支援する [AWS Backup EC2 が リリース](https://aws.amazon.com/jp/about-aws/whats-new/2020/01/aws-backup-adds-support-amazon-elastic-cloud-compute-instance-backup/)された。

* AWS Backup を使った EC2 のバックアップは、スケジュールしたタイミングあるいは即座に、タグあるいはインスタンスIDで指定した EC2 の [AMI](Amazon マシンイメージ (AMI)
) を取得する。
取得した AMI をライフサイクル管理（期限が切れたAMIを削除、あるいはコールドストレージへ移行（費用削減のため））したり、DR用途で異なるリージョンへコピーしたりといったバックアップ管理をしてくれる。
 * スケジュールしたタイミングでバックアップ・・・バックアッププランを作成する
 * 即座にバックアップ・・・オンデマンドバックアップを作成する

* ただ、リストア機能はちょっと微妙（というか「復元」という定義は人それぞれ違うからそう思うのかな・・）。

* リストア機能はさておき、バックアップ機能はすばらしいので、AWS Backup EC2 がリリースされる前は自作したもの（[AMI を定期的に取得して世代管理する](https://qiita.com/tonishy/items/74e145f8c9cba031fa01)）を使っていたけど、すべて入れ替えた。

# 費用に関して(AWSサポート確認済み）

* AWS Backup では、その月に使用したバックアップストレージ量および復元したバックアップデータの量に対してのみ料金が発生する。最低料金および初期費用は発生しない。

* AWS Backup を利用して EC2をバックアップすると、AMIとEBSスナップショットが作成される。EBSスナップショットは、最初のバックアップとしてデータの完全コピーが保存され、その後は変更部分のみの増分バックアップとなる。毎回完全コピーが保存されるわけではない。そのため、課金対象のストレージ領域の量は次になる。
「最初に取得したEBSの実質容量＋２番目に取得したEBSの増分量」

* AWS Backup EC2 バックアップ・リストアで使われたバックアップストレージの料金は、リソースタイプが 「Amazon EBS ボリュームスナップショット」と同様になる。

|![20200225-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/2781ccc6-1fea-b261-7b5b-a4a03c67b663.png)|
|:-:|


* 参考
 * [AWS Backup の料金](https://aws.amazon.com/jp/backup/pricing/)
 * [バックアップ使用量の測定](https://docs.aws.amazon.com/ja_jp/aws-backup/latest/devguide/how-it-works.html#metering-and-billing )

# My 実運用設定

#### 運用ポリシー
* 毎朝６時（JST）に、次のタグが付いている EC2 の AMI を取得する。
 * EC2タグ
     - キー: AWSBackup
     - 値： EC2

* 有効期限は30日とし、30日後は破棄する。
* リージョンコピーはしない（大阪リージョンが開通したら大阪にコピーしようかな・・）

#### AWS Backup EC2 は次の順に作成・設定する

##### (1) バックアップボールト
* *バックアップボールト名*： 「EC2」という名前で作成する
* *KMS 暗号化マスターキー*： デフォルトの「aws/backup」を使う

##### (2) バックアッププラン
* *バックアッププラン名*： 「EC2」という名前で作成する
* *バックアップルール*：
 * *ルール名*：「EC2」
 * *頻度*：カスタム cron 式: cron(0 21 * * ? *) ← 日本時間で 毎朝6時
 * *次の時間以内に開始*：1時間
 * *ライフサイクル*：コールドストレージに移行しない、１ヶ月後に失効（削除）
 * *バックアップボールト*：「EC2」
 * *送信先リージョン*： なし
* *リソースの割り当て*：
 * *リソース割り当て名*： 「Tag-AWSBackup-EC2」
 * *IAM ロール*： AWS管理ポリシー「AWSBackupServiceRolePolicyForBackup」をアタッチしたもの
 * *割り当て単位*： タグ
     - キー： AWSBackup
     - 値： EC2

##### (3) バックアップ対象の EC2 にタグを付加する
* 付加するEC２がたくさんあったので、タグエディターで一括設定

* EC2タグ
 * キー: AWSBackup
 * 値： EC2

# My 実運用設定を Terraform で作成

* 構成

```
anyservice/
└── anyenv
    ├── backup
    │   ├── backend.tf
    │   ├── ec2.tf
    │   ├── provider.tf -> ../../../provider.tf
    │   └── terraform_remote_state.tf -> ../../../terraform_remote_state.tf
    └── iam
        ├── backend.tf
        ├── role_aws-backup-ec2.tf
        └── terraform_remote_state.tf -> ../../../terraform_remote_state.tf

```

* AWS Backup EC2

※現時点で aws_backup_plan にはリージョンコピーの設定項目がない

```ec2.tf
resource "aws_backup_vault" "EC2" {
  name = "EC2"
}
resource "aws_backup_plan" "EC2" {
  name = "EC2"
  rule {
    rule_name         = "EC2"
    target_vault_name = aws_backup_vault.EC2.name
    schedule          = "cron(0 21 * * ? *)"
    lifecycle {
      delete_after = 30
    }
  }
}
resource "aws_backup_selection" "EC2" {
  iam_role_arn = data.terraform_remote_state.IAM.outputs.role_AWSBackupServiceEC2Role_arn
  name         = "Tag-AWSBackup-EC2"
  plan_id      = aws_backup_plan.EC2.id
  selection_tag {
    type  = "STRINGEQUALS"
    key   = "AWSBackup"
    value = "EC2"
  }
}
```

* aws_backup_selection の iam_role_arn は Required なので、iam role も terraform で作成する。。

```role_aws-backup-ec2.tf
data "aws_iam_policy_document" "AWSBackupServiceEC2Role" {
  version = "2012-10-17"
  statement {
    sid    = ""
    effect = "Allow"
    principals {
      type        = "Service"
      identifiers = ["backup.amazonaws.com"]
    }
    actions = [
      "sts:AssumeRole"
    ]
  }
}
resource "aws_iam_role" "AWSBackupServiceEC2Role" {
  name               = "AWSBackupServiceEC2Role"
  path               = "/service-role/"
  assume_role_policy = data.aws_iam_policy_document.AWSBackupServiceEC2Role.json
  tags = {
    Name        = "AWSBackupServiceEC2Role"
    ManagedBy   = "Terraform"
    Environment = "anyenv"
  }
}
data "aws_iam_policy_document" "AWSBackupServiceRolePolicyForEC2Restores" {
  version = "2012-10-17"
  statement {
    sid    = ""
    effect = "Allow"
    actions = [
      "iam:PassRole"
    ]
    resources = [
      "*"
    ]
  }
}
data "aws_iam_policy_document" "ec2DescribeFastSnapshotRestores" {
  version = "2012-10-17"
  statement {
    sid    = ""
    effect = "Allow"
    actions = [
      "ec2:DescribeFastSnapshotRestores"
    ]
    resources = [
      "*"
    ]
  }
}
resource "aws_iam_policy" "AWSBackupServiceRolePolicyForEC2Restores" {
  name   = "AWSBackupServiceRolePolicyForEC2Restores"
  policy = data.aws_iam_policy_document.AWSBackupServiceRolePolicyForEC2Restores.json
}
resource "aws_iam_role_policy_attachment" "AWSBackupServiceRolePolicyForEC2Restores" {
  role       = aws_iam_role.AWSBackupServiceEC2Role.name
  policy_arn = aws_iam_policy.AWSBackupServiceRolePolicyForEC2Restores.arn
}
resource "aws_iam_policy" "ec2DescribeFastSnapshotRestores" {
  name   = "ec2DescribeFastSnapshotRestores"
  policy = data.aws_iam_policy_document.ec2DescribeFastSnapshotRestores.json
}
resource "aws_iam_role_policy_attachment" "ec2DescribeFastSnapshotRestores" {
  role       = aws_iam_role.AWSBackupServiceEC2Role.name
  policy_arn = aws_iam_policy.ec2DescribeFastSnapshotRestores.arn
}
resource "aws_iam_role_policy_attachment" "AWSBackupServiceRolePolicyForBackup" {
  role       = aws_iam_role.AWSBackupServiceEC2Role.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForBackup"
}
resource "aws_iam_role_policy_attachment" "AWSBackupServiceRolePolicyForRestores" {
  role       = aws_iam_role.AWSBackupServiceEC2Role.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForRestores"
}
output "role_AWSBackupServiceEC2Role_arn" {
  value = aws_iam_role.AWSBackupServiceEC2Role.arn
}
```



# バックアップ確認

#### バックアップジョブ
AWS Backup のダッシュボードから確認する

|![20200225-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/cec98c8b-5850-3d4e-4f91-775127cc0a7e.png)|
|:-:|

バックアップジョブの詳細
↓

|![20200225-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/d3ce40d3-5c6b-6b93-a600-f5c82238fd01.png)|
|:-:|

* リソースIDは、取得したEC2のインスタンスID
* 作成時間は、06:14 になっている
 * バックアップルールのcron式で毎朝6時に指定しているけど、6時ちょうどに取得するわけではない。 
 * 6時から7時（＝「次の時間以内に開始：1時間」）までの間のどこかで取得する。


#### バックアップボールト

|![20200225-05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/d130b61b-ae65-aae4-fe35-cbdb7bb5fb3b.png)|
|:-:|

* AWS Backup では、取得した AMI を 「復旧ポイントID」 と言うらしい。

#### バックアップされたAMI

|![20200225-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/5918cc42-91e7-76ce-291c-911184d93fa4.png)|
|:-:|

* Nameは、バックアップ元の EC2 の Nameタグの値が付く
* AMI名は、次の命名規則になる
 * AWSBackup_インスタンスID_バックアップジョブID
* 作成日は、バックアップジョブの作成時間(06:14)ではなく、AMI作成時間(6:23)になっている
* AMIの削除（登録解除）は、「バックアップボールト」ページの「復旧ポイントID」の削除で行う。

# リストアについて

### 復元時に使う IAM Role について
* EC2 を他のAWSサービスと連携させるなどで、何かしらのIAMロールを割り当てている。
* 何かしらのIAMロールが割り当てられたEC2を AWS Backup EC２ でバックアップして作成された AMI(復旧ポイントID)を復元する場合、デフォルトの IAMロール（AWS管理ポリシー「AWSBackupServiceRolePolicyForRestores」）を使うとエラーが出る。
* なので、次のポリシーを追加する必要がある。IAMの基本方針としてインラインポリシーは使わないのがベストなので、次のポリシーを作成して、デフォルトの IAM ロールにアタッチさせる。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": "iam:PassRole",
            "Resource": "*"
        }
    ]
}
```

* リストア用の IAMロールを Terraform で作成する

```role_aws-backup-ec2-restor.tf
data "aws_iam_policy_document" "AWSBackupServiceRolePolicyForEC2Restore" {
  version = "2012-10-17"
  statement {
    sid       = ""
    effect    = "Allow"
    actions   = ["iam:PassRole"]
    resources = ["*"]
  }
}
resource "aws_iam_policy" "AWSBackupServiceRolePolicyForEC2Restore" {
  name   = "AWSBackupServiceRolePolicyForEC2Restore"
  policy = data.aws_iam_policy_document.AWSBackupServiceRolePolicyForEC2Restore.json
}

data "aws_iam_policy_document" "backup-assume-role-policy" {
  statement {
    actions = ["sts:AssumeRole"]
    principals {
      type        = "Service"
      identifiers = ["backup.amazonaws.com"]
    }
  }
}
resource "aws_iam_role" "AWSBackupServiceEC2Restore" {
  name               = "AWSBackupServiceEC2Restore"
  path               = "/service-role/"
  assume_role_policy = data.aws_iam_policy_document.backup-assume-role-policy.json
  tags = {
    Name        = "AWSBackupServiceEC2Restore"
    ManagedBy   = "Terraform"
    Environment = "anyenv"
  }
}

resource "aws_iam_role_policy_attachment" "AWSBackupServiceRolePolicyForEC2Restore" {
  role       = aws_iam_role.AWSBackupServiceEC2Restore.name
  policy_arn = aws_iam_policy.AWSBackupServiceRolePolicyForEC2Restore.arn
}
resource "aws_iam_role_policy_attachment" "AWSBackupServiceRolePolicyForRestores" {
  role       = aws_iam_role.AWSBackupServiceEC2Restore.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForRestores"
}
output "role_AWSBackupServiceEC2Role_arn" {
  value = aws_iam_role.AWSBackupServiceEC2Restore.arn
}
```

* 参考
 * [EC2インスタンスに対応したAWS Backupを試してみた](https://dev.classmethod.jp/cloud/aws/aws-backup-ec2-instances/)


### 復元したEC2に割り当てられるキーペアについて（AWSサポート確認済み）
* 現時点では、AWS Backup EC2 の復元時に キーペアを指定することはできない。
* EC2のダッシュボード上ではキーペアが表示されないが、キーペア自体は元のインスタンスに指定されたものと同様のものがインスタンス内部では保持されているので、そのキーを使えばSSH 接続が可能。

### パブリックIPアドレスについて（AWSサポート確認済み）
* バックアップを復元するサブネットで「パブリック IPv4 アドレスの自動割り当て」が「いいえ」と設定されている場合は、復元されたEC2にパブリックIPアドレスは付加されない。