diff --git a/codegen/src/iam.ts b/codegen/src/iam.ts index 6f882ad..911bb82 100644 --- a/codegen/src/iam.ts +++ b/codegen/src/iam.ts @@ -38,17 +38,16 @@ type Principal = }; type Action = - | "cloudformation:*" + | `${string}:*` + | `${iam.AwsBackupActions}` | `${iam.AwsCloudformationActions}` - | "logs:*" - | `${iam.AwsLogsActions}` - | "iam:*" + | `${iam.AwsEbsActions}` + | `${iam.AwsEc2Actions}` | `${iam.AwsIamActions}` - | "lambda:*" + | `${iam.AwsKmsActions}` | `${iam.AwsLambdaActions}` - | "s3:*" + | `${iam.AwsLogsActions}` | `${iam.AwsS3Actions}` - | "ssm:*" | `${iam.AwsSsmActions}`; type KnownTag = @@ -65,7 +64,11 @@ type KnownTag = | "elastio:authorize" // Set on every resource deployed by Elastio - | "elastio:resource"; + | "elastio:resource" + + // Set by AWS Backup on resources created as part of AWS Backup restore testing. + // The value of this tag is the ID of the AWS Backup restore job. + | "awsbackup-restore-test"; export function hasResourceTag(tag: KnownTag) { return hasTags("aws:ResourceTag", tag); diff --git a/codegen/src/policies/ElastioAwsBackupEc2Scan.ts b/codegen/src/policies/ElastioAwsBackupEc2Scan.ts new file mode 100644 index 0000000..af8fa08 --- /dev/null +++ b/codegen/src/policies/ElastioAwsBackupEc2Scan.ts @@ -0,0 +1,114 @@ +import * as iam from "../iam"; + +export default { + description: "Allows Elastio to scan AWS Backup recovery points.", + + statements: [ + { + Sid: "ReadBackupInventory", + Action: [ + // Vaults + "backup:ListBackupVaults", + "backup:DescribeBackupVault", + + // Recovery points + "backup:ListRecoveryPointsByResource", + "backup:DescribeRecoveryPoint", + "backup:ListRecoveryPointsByBackupVault", + "backup:GetRecoveryPointRestoreMetadata", + + // Common for all resources + "backup:ListTags", + + // Misc. + "backup:ListProtectedResources", + "backup:ListProtectedResourcesByBackupVault", + ], + Resource: "*", + }, + + { + Sid: "ReadEbsInventory", + Action: [ + // Volumes + "ec2:DescribeVolumeStatus", + "ec2:DescribeVolumes", + + // Snapshots + "ec2:DescribeSnapshots", + "ec2:DescribeSnapshotAttribute", + + // Common for all resources + "ec2:DescribeTags", + + // Used for cost estimation + "ebs:ListSnapshotBlocks", + "ebs:ListChangedBlocks", + ], + Resource: "*", + }, + + { + Sid: "ReadEbsSnapshotsData", + Action: ["ebs:GetSnapshotBlock"], + Resource: "*", + }, + + { + Sid: "ReadEc2Inventory", + Action: [ + "ec2:DescribeInstances", + "ec2:DescribeImages", + "ec2:DescribeHosts", + "ssm:DescribeInstanceInformation", + ], + Resource: "*", + }, + + { + Sid: "ShareEbsSnapshot", + Action: ["ec2:ModifySnapshotAttribute"], + Resource: "*", + Condition: { + // Needed to add createVolumePermission for the sharing the snapshot + // with the connector account. + StringLike: { + "ec2:Add/userId": "*", + }, + }, + }, + + { + Sid: "KmsAccess", + + // Users need to put a special tag on their KMS keys to allow Elastio + // use them for decrypting their data. It must be documented in public + // Elastio documentation. + Condition: iam.hasResourceTag("elastio:authorize"), + + Action: [ + // These actions are needed to reencrypt the volumes that were encrypted + // by the KMS key. + "kms:ReEncryptFrom", + "kms:ReEncryptTo", + "kms:CreateGrant", + "kms:Encrypt", + + // Needed only for some cases. For example, when we want to snapshot an EBS + // volume that was created from a snapshot of the root volume of an EC2 instance. + // These calls are made by the ebs.amazonaws.com and not by our code. + "kms:DescribeKey", + + // GenerateDataKeyWithoutPlaintext in particular is required in case when + // we create a volume from an unencrypted snapshot but there is a default + // KMS encryption key set in EBS for the volume. + "kms:GenerateDataKey", + "kms:GenerateDataKeyWithoutPlaintext", + + // This is required when reading S3 buckets encrypted with a KMS key + "kms:Decrypt", + ], + Resource: "*", + }, + ], +} satisfies iam.Policy; diff --git a/iam-policies/terraform/README.md b/iam-policies/terraform/README.md index 0942133..e6f7954 100644 --- a/iam-policies/terraform/README.md +++ b/iam-policies/terraform/README.md @@ -30,8 +30,10 @@ See the basic [usage example](./examples/basic/main.tf). | Policy | Description | | ------------------------------------------------------------ | -------------------------------------------------------------- | | [`ElastioAssetAccountDeployer`][ElastioAssetAccountDeployer] | Permissions required to deploy the Elastio Asset Account stack | +| [`ElastioAwsBackupEc2Scan`][ElastioAwsBackupEc2Scan] | Allows Elastio to scan AWS Backup recovery points. | [ElastioAssetAccountDeployer]: ../../codegen/src/policies/ElastioAssetAccountDeployer.ts +[ElastioAwsBackupEc2Scan]: ../../codegen/src/policies/ElastioAwsBackupEc2Scan.ts diff --git a/iam-policies/terraform/policies/ElastioAwsBackupEc2Scan.json b/iam-policies/terraform/policies/ElastioAwsBackupEc2Scan.json new file mode 100644 index 0000000..dc8cf7c --- /dev/null +++ b/iam-policies/terraform/policies/ElastioAwsBackupEc2Scan.json @@ -0,0 +1,86 @@ +{ + "Description": "Allows Elastio to scan AWS Backup recovery points.", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "ReadBackupInventory", + "Action": [ + "backup:ListBackupVaults", + "backup:DescribeBackupVault", + "backup:ListRecoveryPointsByResource", + "backup:DescribeRecoveryPoint", + "backup:ListRecoveryPointsByBackupVault", + "backup:GetRecoveryPointRestoreMetadata", + "backup:ListTags", + "backup:ListProtectedResources", + "backup:ListProtectedResourcesByBackupVault" + ], + "Resource": "*", + "Effect": "Allow" + }, + { + "Sid": "ReadEbsInventory", + "Action": [ + "ec2:DescribeVolumeStatus", + "ec2:DescribeVolumes", + "ec2:DescribeSnapshots", + "ec2:DescribeSnapshotAttribute", + "ec2:DescribeTags", + "ebs:ListSnapshotBlocks", + "ebs:ListChangedBlocks" + ], + "Resource": "*", + "Effect": "Allow" + }, + { + "Sid": "ReadEbsSnapshotsData", + "Action": ["ebs:GetSnapshotBlock"], + "Resource": "*", + "Effect": "Allow" + }, + { + "Sid": "ReadEc2Inventory", + "Action": [ + "ec2:DescribeInstances", + "ec2:DescribeImages", + "ec2:DescribeHosts", + "ssm:DescribeInstanceInformation" + ], + "Resource": "*", + "Effect": "Allow" + }, + { + "Sid": "ShareEbsSnapshot", + "Action": ["ec2:ModifySnapshotAttribute"], + "Resource": "*", + "Condition": { + "StringLike": { + "ec2:Add/userId": "*" + } + }, + "Effect": "Allow" + }, + { + "Sid": "KmsAccess", + "Condition": { + "StringLike": { + "aws:ResourceTag/elastio:authorize": "*" + } + }, + "Action": [ + "kms:ReEncryptFrom", + "kms:ReEncryptTo", + "kms:CreateGrant", + "kms:Encrypt", + "kms:DescribeKey", + "kms:GenerateDataKey", + "kms:GenerateDataKeyWithoutPlaintext", + "kms:Decrypt" + ], + "Resource": "*", + "Effect": "Allow" + } + ] + } +}