{
  "Parameters": {
    "AnomalyDetectionTagKey": {
      "Type": "String",
      "Description": "This is the tag key for your EBS volumes."
    },
    "AnomalyDetectionEmail": {
      "Type": "String",
      "Description": "The email address to use for alarm notifications."
    },
    "BackupAnomalyDetectionS3Bucket": {
      "Type": "String",
      "Description": "Location of S3 bucket which contains the Lambda code. This S3 bucket needs to exist in the same region as this deployment."
    },
    "BackupAnomalyDetectionS3Code": {
      "Type": "String",
      "Default": "anomaly-detection-lambda.zip",
      "Description": "Location of Lambda code within given S3 bucket (BackupAnomalyDetectionS3Bucket parameter)"
    }
  },
  "Resources": {
    "AnomalyDetectionAnomalyDetectionBackupPlan": {
      "Type": "AWS::Backup::BackupPlan",
      "Properties": {
        "BackupPlan": {
          "BackupPlanName": "AnomalyDetectionBackupPlan",
          "BackupPlanRule": [
            {
              "Lifecycle": {
                "DeleteAfterDays": 35
              },
              "RuleName": "Daily",
              "ScheduleExpression": "cron(0 5 * * ? *)",
              "TargetBackupVault": {
                "Fn::GetAtt": [
                  "AnomalyDetectionAnomalyDetectionBackupPlanVault",
                  "BackupVaultName"
                ]
              }
            },
            {
              "Lifecycle": {
                "DeleteAfterDays": 365,
                "MoveToColdStorageAfterDays": 30
              },
              "RuleName": "Monthly1Year",
              "ScheduleExpression": "cron(0 5 1 * ? *)",
              "TargetBackupVault": {
                "Fn::GetAtt": [
                  "AnomalyDetectionAnomalyDetectionBackupPlanVault",
                  "BackupVaultName"
                ]
              }
            }
          ]
        }
      }
    },
    "AnomalyDetectionAnomalyDetectionBackupPlanVault": {
      "Type": "AWS::Backup::BackupVault",
      "Properties": {
        "BackupVaultName": "AnomalyDetectionAnomalyDetectionBackupPlanVault"
      },
      "UpdateReplacePolicy": "Retain",
      "DeletionPolicy": "Retain"
    },
    "AnomalyDetectionAnomalyDetectionBackupPlanSelectionRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Statement": [
            {
              "Action": "sts:AssumeRole",
              "Effect": "Allow",
              "Principal": {
                "Service": "backup.amazonaws.com"
              }
            }
          ],
          "Version": "2012-10-17"
        },
        "ManagedPolicyArns": [
          {
            "Fn::Join": [
              "",
              [
                "arn:",
                {
                  "Ref": "AWS::Partition"
                },
                ":iam::aws:policy/service-role/AWSBackupServiceRolePolicyForBackup"
              ]
            ]
          }
        ]
      }
    },
    "AnomalyDetectionAnomalyDetectionBackupPlanSelection": {
      "Type": "AWS::Backup::BackupSelection",
      "Properties": {
        "BackupPlanId": {
          "Fn::GetAtt": [
            "AnomalyDetectionAnomalyDetectionBackupPlan",
            "BackupPlanId"
          ]
        },
        "BackupSelection": {
          "IamRoleArn": {
            "Fn::GetAtt": [
              "AnomalyDetectionAnomalyDetectionBackupPlanSelectionRole",
              "Arn"
            ]
          },
          "Conditions": {
            "StringLike": [
              {
                "ConditionKey": {
                  "Fn::Join": [
                    "",
                    [
                      "aws:ResourceTag/",
                      {
                        "Ref": "AnomalyDetectionTagKey"
                      }
                    ]
                  ]
                },
                "ConditionValue": "*"
              }
            ]
          },
          "Resources": [
            "arn:aws:ec2:*:*:volume/*"
          ],
          "SelectionName": "Selection"
        }
      }
    },
    "AnomalyDetectionAnomalyDetectionDB": {
      "Type": "AWS::DynamoDB::Table",
      "Properties": {
        "KeySchema": [
          {
            "AttributeName": "arn",
            "KeyType": "HASH"
          }
        ],
        "AttributeDefinitions": [
          {
            "AttributeName": "arn",
            "AttributeType": "S"
          }
        ],
        "ProvisionedThroughput": {
          "ReadCapacityUnits": 5,
          "WriteCapacityUnits": 5
        },
        "TableName": "anomaly-detection"
      },
      "UpdateReplacePolicy": "Delete",
      "DeletionPolicy": "Delete"
    },
    "AnomalyDetectionAnomalyDetectionTopic": {
      "Type": "AWS::SNS::Topic",
      "Properties": {
        "DisplayName": "AWS Backup AnomalyDetection Topic",
        "FifoTopic": false
      }
    },
    "AnomalyDetectionAnomalyDetectionTopicTokenSubscription": {
      "Type": "AWS::SNS::Subscription",
      "Properties": {
        "Protocol": "email",
        "TopicArn": {
          "Ref": "AnomalyDetectionAnomalyDetectionTopic"
        },
        "Endpoint": {
          "Ref": "AnomalyDetectionEmail"
        }
      }
    },
    "AnomalyDetectionServiceRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Statement": [
            {
              "Action": "sts:AssumeRole",
              "Effect": "Allow",
              "Principal": {
                "Service": "lambda.amazonaws.com"
              }
            }
          ],
          "Version": "2012-10-17"
        },
        "ManagedPolicyArns": [
          {
            "Fn::Join": [
              "",
              [
                "arn:",
                {
                  "Ref": "AWS::Partition"
                },
                ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
              ]
            ]
          }
        ]
      }
    },
    "AnomalyDetectionServiceRoleDefaultPolicy": {
      "Type": "AWS::IAM::Policy",
      "Properties": {
        "PolicyDocument": {
          "Statement": [
            {
              "Action": [
                "dynamodb:BatchGetItem",
                "dynamodb:GetRecords",
                "dynamodb:GetShardIterator",
                "dynamodb:Query",
                "dynamodb:GetItem",
                "dynamodb:Scan",
                "dynamodb:ConditionCheckItem",
                "dynamodb:BatchWriteItem",
                "dynamodb:PutItem",
                "dynamodb:UpdateItem",
                "dynamodb:DeleteItem",
                "dynamodb:DescribeTable"
              ],
              "Effect": "Allow",
              "Resource": [
                {
                  "Fn::GetAtt": [
                    "AnomalyDetectionAnomalyDetectionDB",
                    "Arn"
                  ]
                },
                {
                  "Ref": "AWS::NoValue"
                }
              ]
            },
            {
              "Action": "cloudwatch:PutMetricData",
              "Effect": "Allow",
              "Resource": "*"
            }
          ],
          "Version": "2012-10-17"
        },
        "PolicyName": "AnomalyDetectionServiceRoleDefaultPolicy",
        "Roles": [
          {
            "Ref": "AnomalyDetectionServiceRole"
          }
        ]
      }
    },
    "AnomalyDetection": {
      "Type": "AWS::Lambda::Function",
      "Properties": {
        "Code": {
          "S3Bucket": {
            "Ref": "BackupAnomalyDetectionS3Bucket"
          },
          "S3Key": {
            "Ref": "BackupAnomalyDetectionS3Code"
          }
        },
        "Role": {
          "Fn::GetAtt": [
            "AnomalyDetectionServiceRole",
            "Arn"
          ]
        },
        "Environment": {
          "Variables": {
            "TAG_KEY_EBS": {
              "Ref": "AnomalyDetectionTagKey"
            },
            "SNS_TOPIC_ARN": {
              "Ref": "AnomalyDetectionAnomalyDetectionTopic"
            }
          }
        },
        "Handler": "index.handler",
        "Runtime": "nodejs14.x"
      },
      "DependsOn": [
        "AnomalyDetectionServiceRoleDefaultPolicy",
        "AnomalyDetectionServiceRole"
      ]
    },
    "AnomalyDetectionAnomalyDetectionInlinePolicy": {
      "Type": "AWS::IAM::Policy",
      "Properties": {
        "PolicyDocument": {
          "Statement": [
            {
              "Action": "ebs:ListChangedBlocks",
              "Effect": "Allow",
              "Resource": "*"
            },
            {
              "Action": "ec2:DescribeVolumes",
              "Effect": "Allow",
              "Resource": "*"
            },
            {
              "Action": "cloudwatch:PutMetricAlarm",
              "Effect": "Allow",
              "Resource": "*"
            }
          ],
          "Version": "2012-10-17"
        },
        "PolicyName": "AnomalyDetectionAnomalyDetectionInlinePolicy",
        "Roles": [
          {
            "Ref": "AnomalyDetectionServiceRole"
          }
        ]
      }
    },
    "AnomalyDetectionAnomalyDetectionRule": {
      "Type": "AWS::Events::Rule",
      "Properties": {
        "EventPattern": {
          "source": [
            "aws.backup"
          ],
          "detail-type": [
            "Backup Job State Change"
          ],
          "detail": {
            "resourceType": [
              "EBS"
            ],
            "state": [
              "COMPLETED"
            ]
          }
        },
        "State": "ENABLED",
        "Targets": [
          {
            "Arn": {
              "Fn::GetAtt": [
                "AnomalyDetection",
                "Arn"
              ]
            },
            "Id": "Target0",
            "RetryPolicy": {
              "MaximumRetryAttempts": 2
            }
          }
        ]
      }
    },
    "AnomalyDetectionAnomalyDetectionRuleAllowEventRuleAnomalyDetectionStackAnomalyDetection": {
      "Type": "AWS::Lambda::Permission",
      "Properties": {
        "Action": "lambda:InvokeFunction",
        "FunctionName": {
          "Fn::GetAtt": [
            "AnomalyDetection",
            "Arn"
          ]
        },
        "Principal": "events.amazonaws.com",
        "SourceArn": {
          "Fn::GetAtt": [
            "AnomalyDetectionAnomalyDetectionRule",
            "Arn"
          ]
        }
      }
    }
  }
}