diff --git a/.github/workflows/tfsec.yml b/.github/workflows/tfsec.yml index 04e50cd..9106928 100644 --- a/.github/workflows/tfsec.yml +++ b/.github/workflows/tfsec.yml @@ -9,7 +9,7 @@ on: push: branches: [ "main" ] pull_request: - branches: [ "main" ] + branches: [ "main" ] schedule: - cron: '45 0 * * 3' @@ -29,10 +29,10 @@ jobs: - name: Run tfsec uses: aquasecurity/tfsec-sarif-action@9a83b5c3524f825c020e356335855741fd02745f with: - sarif_file: tfsec.sarif + sarif_file: tfsec.sarif - name: Upload SARIF file uses: github/codeql-action/upload-sarif@v2 with: # Path to SARIF file relative to the root of the repository - sarif_file: tfsec.sarif + sarif_file: tfsec.sarif diff --git a/README-PORTABLE.md b/README-PORTABLE.md index 81cb5b1..4405a00 100644 --- a/README-PORTABLE.md +++ b/README-PORTABLE.md @@ -178,6 +178,9 @@ This set of modules supports creating the AMS KMS key along with key resource po - [Amazon Kinesis](https://docs.aws.amazon.com/streams/latest/dev/server-side-encryption.html) - [AWS Glue](https://docs.aws.amazon.com/glue/latest/dg/encryption-at-rest.html) - [AWS ACM](https://docs.aws.amazon.com/acm/latest/userguide/data-protection.html) +- [Amazon MWAA](https://docs.aws.amazon.com/mwaa/latest/userguide/encryption-at-rest.html) +- [Amazon ECR](https://docs.aws.amazon.com/AmazonECR/latest/userguide/encryption-at-rest.html) +- [Amazon EKS](https://docs.aws.amazon.com/eks/latest/userguide/enable-kms.html) ## Future Enhancements diff --git a/README-PORTABLE.pdf b/README-PORTABLE.pdf index c8549f1..8ee8ed3 100644 Binary files a/README-PORTABLE.pdf and b/README-PORTABLE.pdf differ diff --git a/README.md b/README.md index ff95a25..bfb9b5c 100644 --- a/README.md +++ b/README.md @@ -178,6 +178,9 @@ This set of modules supports creating the AMS KMS key along with key resource po - [Amazon Kinesis](https://docs.aws.amazon.com/streams/latest/dev/server-side-encryption.html) - [AWS Glue](https://docs.aws.amazon.com/glue/latest/dg/encryption-at-rest.html) - [AWS ACM](https://docs.aws.amazon.com/acm/latest/userguide/data-protection.html) +- [Amazon MWAA](https://docs.aws.amazon.com/mwaa/latest/userguide/encryption-at-rest.html) +- [Amazon ECR](https://docs.aws.amazon.com/AmazonECR/latest/userguide/encryption-at-rest.html) +- [Amazon EKS](https://docs.aws.amazon.com/eks/latest/userguide/enable-kms.html) ## Future Enhancements diff --git a/examples/kms/scenario1/main.tf b/examples/kms/scenario1/main.tf index e35b498..b4eff31 100644 --- a/examples/kms/scenario1/main.tf +++ b/examples/kms/scenario1/main.tf @@ -25,4 +25,7 @@ module "kms_keys" { enable_kms_kinesis = true enable_kms_glue = true enable_kms_acm = true + enable_kms_mwaa = true + enable_kms_ecr = true + enable_kms_eks = true } diff --git a/examples/kms/scenario3/main.tf b/examples/kms/scenario3/main.tf index 16d0b33..6e451af 100644 --- a/examples/kms/scenario3/main.tf +++ b/examples/kms/scenario3/main.tf @@ -26,8 +26,10 @@ module "kms_keys" { # enable_kms_ssm = true enable_kms_secretsmanager = true enable_kms_session = true - # enable_kms_kinesis = true - # enable_kms_glue = true - # enable_kms_acm = true - + # enable_kms_kinesis = true + # enable_kms_glue = true + # enable_kms_acm = true + # enable_kms_mwaa = true + # enable_kms_ecr = true + # enable_kms_eks = true } diff --git a/modules/aws/kms/README.md b/modules/aws/kms/README.md index 8087e45..e2ff9a6 100644 --- a/modules/aws/kms/README.md +++ b/modules/aws/kms/README.md @@ -36,11 +36,14 @@ No modules. | [enable\_key\_rotation\_backup](#input\_enable\_key\_rotation\_backup) | Enable key rotation for AWS Backup CMK | `bool` | `true` | no | | [enable\_key\_rotation\_dynamodb](#input\_enable\_key\_rotation\_dynamodb) | Enable key rotation for Amazon DynamoDB CMK | `bool` | `true` | no | | [enable\_key\_rotation\_ebs](#input\_enable\_key\_rotation\_ebs) | Enable key rotation for Amazon EBS CMK | `bool` | `true` | no | +| [enable\_key\_rotation\_ecr](#input\_enable\_key\_rotation\_ecr) | Enable key rotation for Amazon ECR CMK | `bool` | `true` | no | | [enable\_key\_rotation\_efs](#input\_enable\_key\_rotation\_efs) | Enable key rotation for Amazon EFS CMK | `bool` | `true` | no | +| [enable\_key\_rotation\_eks](#input\_enable\_key\_rotation\_eks) | Enable key rotation for Amazon EKS CMK | `bool` | `true` | no | | [enable\_key\_rotation\_glue](#input\_enable\_key\_rotation\_glue) | Enable key rotation for AWS Glue CMK | `bool` | `true` | no | | [enable\_key\_rotation\_kinesis](#input\_enable\_key\_rotation\_kinesis) | Enable key rotation for Amazon Kinesis CMK | `bool` | `true` | no | | [enable\_key\_rotation\_lambda](#input\_enable\_key\_rotation\_lambda) | Enable key rotation for AWS Lambda CMK | `bool` | `true` | no | | [enable\_key\_rotation\_logs](#input\_enable\_key\_rotation\_logs) | Enable key rotation for Amazon CloudWatch Log CMK | `bool` | `true` | no | +| [enable\_key\_rotation\_mwaa](#input\_enable\_key\_rotation\_mwaa) | Enable key rotation for Amazon MWAA CMK | `bool` | `true` | no | | [enable\_key\_rotation\_rds](#input\_enable\_key\_rotation\_rds) | Enable key rotation for Amazon RDS CMK | `bool` | `true` | no | | [enable\_key\_rotation\_s3](#input\_enable\_key\_rotation\_s3) | Enable key rotation for Amazon S3 CMK | `bool` | `true` | no | | [enable\_key\_rotation\_secretsmanager](#input\_enable\_key\_rotation\_secretsmanager) | Enable key rotation for AWS Secrets Manager CMK | `bool` | `true` | no | @@ -52,11 +55,14 @@ No modules. | [enable\_kms\_backup](#input\_enable\_kms\_backup) | Enable customer managed key that can be used to encrypt/decrypt AWS Backup | `bool` | `false` | no | | [enable\_kms\_dynamodb](#input\_enable\_kms\_dynamodb) | Enable customer managed key that can be used to encrypt/decrypt Amazon DynamoDB | `bool` | `false` | no | | [enable\_kms\_ebs](#input\_enable\_kms\_ebs) | Enable customer managed key that can be used to encrypt/decrypt Amazon EBS | `bool` | `false` | no | +| [enable\_kms\_ecr](#input\_enable\_kms\_ecr) | Enable customer managed key that can be used to encrypt/decrypt Amazon ECR | `bool` | `false` | no | | [enable\_kms\_efs](#input\_enable\_kms\_efs) | Enable customer managed key that can be used to encrypt/decrypt Amazon EFS | `bool` | `false` | no | +| [enable\_kms\_eks](#input\_enable\_kms\_eks) | Enable customer managed key that can be used to encrypt/decrypt Amazon EKS | `bool` | `false` | no | | [enable\_kms\_glue](#input\_enable\_kms\_glue) | Enable customer managed key that can be used to encrypt/decrypt AWS Glue | `bool` | `false` | no | | [enable\_kms\_kinesis](#input\_enable\_kms\_kinesis) | Enable customer managed key that can be used to encrypt/decrypt Amazon Kinesis | `bool` | `false` | no | | [enable\_kms\_lambda](#input\_enable\_kms\_lambda) | Enable customer managed key that can be used to encrypt/decrypt AWS Lambda | `bool` | `false` | no | | [enable\_kms\_logs](#input\_enable\_kms\_logs) | Enable customer managed key that can be used to encrypt/decrypt Amazon CloudWatch Log | `bool` | `false` | no | +| [enable\_kms\_mwaa](#input\_enable\_kms\_mwaa) | Enable customer managed key that can be used to encrypt/decrypt Amazon MWAA | `bool` | `false` | no | | [enable\_kms\_rds](#input\_enable\_kms\_rds) | Enable customer managed key that can be used to encrypt/decrypt Amazon RDS | `bool` | `false` | no | | [enable\_kms\_s3](#input\_enable\_kms\_s3) | Enable customer managed key that can be used to encrypt/decrypt Amazon S3 | `bool` | `false` | no | | [enable\_kms\_secretsmanager](#input\_enable\_kms\_secretsmanager) | Enable customer managed key that can be used to encrypt/decrypt AWS Secrets Manager | `bool` | `false` | no | @@ -68,11 +74,14 @@ No modules. | [enable\_multi\_region\_backup](#input\_enable\_multi\_region\_backup) | Enable multi-region for AWS Backup CMK | `bool` | `false` | no | | [enable\_multi\_region\_dynamodb](#input\_enable\_multi\_region\_dynamodb) | Enable multi-region for Amazon DynamoDB CMK | `bool` | `false` | no | | [enable\_multi\_region\_ebs](#input\_enable\_multi\_region\_ebs) | Enable multi-region for Amazon EBS CMK | `bool` | `false` | no | +| [enable\_multi\_region\_ecr](#input\_enable\_multi\_region\_ecr) | Enable multi-region for Amazon ECR CMK | `bool` | `false` | no | | [enable\_multi\_region\_efs](#input\_enable\_multi\_region\_efs) | Enable multi-region for Amazon EFS CMK | `bool` | `false` | no | +| [enable\_multi\_region\_eks](#input\_enable\_multi\_region\_eks) | Enable multi-region for Amazon EKS CMK | `bool` | `false` | no | | [enable\_multi\_region\_glue](#input\_enable\_multi\_region\_glue) | Enable multi-region for AWS Glues CMK | `bool` | `false` | no | | [enable\_multi\_region\_kinesis](#input\_enable\_multi\_region\_kinesis) | Enable multi-region for Amazon Kinesis CMK | `bool` | `false` | no | | [enable\_multi\_region\_lambda](#input\_enable\_multi\_region\_lambda) | Enable multi-region for AWS Lambda CMK | `bool` | `false` | no | | [enable\_multi\_region\_logs](#input\_enable\_multi\_region\_logs) | Enable multi-region for Amazon CloudWatch Log CMK | `bool` | `false` | no | +| [enable\_multi\_region\_mwaa](#input\_enable\_multi\_region\_mwaa) | Enable multi-region for Amazon MWAA CMK | `bool` | `false` | no | | [enable\_multi\_region\_rds](#input\_enable\_multi\_region\_rds) | Enable multi-region for Amazon RDS CMK | `bool` | `false` | no | | [enable\_multi\_region\_s3](#input\_enable\_multi\_region\_s3) | Enable multi-region for Amazon S3 CMK | `bool` | `false` | no | | [enable\_multi\_region\_secretsmanager](#input\_enable\_multi\_region\_secretsmanager) | Enable multi-region for AWS Secrets Manager CMK | `bool` | `false` | no | @@ -87,11 +96,14 @@ No modules. | [override\_policy\_backup](#input\_override\_policy\_backup) | A valid KMS key policy JSON document. If not specified, a canonical key policy will be used. | `string` | `null` | no | | [override\_policy\_dynamodb](#input\_override\_policy\_dynamodb) | A valid KMS key policy JSON document. If not specified, a canonical key policy will be used. | `string` | `null` | no | | [override\_policy\_ebs](#input\_override\_policy\_ebs) | A valid KMS key policy JSON document. If not specified, a canonical key policy will be used. | `string` | `null` | no | +| [override\_policy\_ecr](#input\_override\_policy\_ecr) | A valid KMS key policy JSON document. If not specified, a canonical key policy will be used. | `string` | `null` | no | | [override\_policy\_efs](#input\_override\_policy\_efs) | A valid KMS key policy JSON document. If not specified, a canonical key policy will be used. | `string` | `null` | no | +| [override\_policy\_eks](#input\_override\_policy\_eks) | A valid KMS key policy JSON document. If not specified, a canonical key policy will be used. | `string` | `null` | no | | [override\_policy\_glue](#input\_override\_policy\_glue) | A valid KMS key policy JSON document. If not specified, a canonical key policy will be used. | `string` | `null` | no | | [override\_policy\_kinesis](#input\_override\_policy\_kinesis) | A valid KMS key policy JSON document. If not specified, a canonical key policy will be used. | `string` | `null` | no | | [override\_policy\_lambda](#input\_override\_policy\_lambda) | A valid KMS key policy JSON document. If not specified, a canonical key policy will be used. | `string` | `null` | no | | [override\_policy\_logs](#input\_override\_policy\_logs) | A valid KMS key policy JSON document. If not specified, a canonical key policy will be used. | `string` | `null` | no | +| [override\_policy\_mwaa](#input\_override\_policy\_mwaa) | A valid KMS key policy JSON document. If not specified, a canonical key policy will be used. | `string` | `null` | no | | [override\_policy\_rds](#input\_override\_policy\_rds) | A valid KMS key policy JSON document. If not specified, a canonical key policy will be used. | `string` | `null` | no | | [override\_policy\_s3](#input\_override\_policy\_s3) | A valid KMS key policy JSON document. If not specified, a canonical key policy will be used. | `string` | `null` | no | | [override\_policy\_secretsmanager](#input\_override\_policy\_secretsmanager) | A valid KMS key policy JSON document. If not specified, a canonical key policy will be used. | `string` | `null` | no | diff --git a/modules/aws/kms/ecr.tf b/modules/aws/kms/ecr.tf new file mode 100644 index 0000000..b2ed76c --- /dev/null +++ b/modules/aws/kms/ecr.tf @@ -0,0 +1,63 @@ +# tflint-ignore: terraform_standard_module_structure +variable "enable_kms_ecr" { + description = "Enable customer managed key that can be used to encrypt/decrypt Amazon ECR" + type = bool + default = false +} + +# tflint-ignore: terraform_standard_module_structure +variable "enable_key_rotation_ecr" { + description = "Enable key rotation for Amazon ECR CMK" + type = bool + default = true +} + +# tflint-ignore: terraform_standard_module_structure +variable "enable_multi_region_ecr" { + description = "Enable multi-region for Amazon ECR CMK" + type = bool + default = false +} + +# tflint-ignore: terraform_standard_module_structure +variable "override_policy_ecr" { + description = "A valid KMS key policy JSON document. If not specified, a canonical key policy will be used." + type = string + default = null +} + +data "aws_iam_policy_document" "ecr" { + # checkov:skip=CKV_AWS_109: Not applicable, using condition + # checkov:skip=CKV_AWS_111: Not applicable, using condition + source_policy_documents = [data.aws_iam_policy_document.admin_kms_policy.json] + + statement { + sid = "Allow access through Amazon ECR for all principals in the account that are authorized to use Amazon ECR" + principals { + type = "AWS" + identifiers = ["*"] + } + actions = [ + "kms:Encrypt", + "kms:Decrypt", + "kms:ReEncrypt*", + "kms:GenerateDataKey*", + "kms:DescribeKey", + "kms:CreateGrant", + "kms:RetireGrant" + ] + resources = ["*"] + condition { + test = "StringEquals" + variable = "kms:ViaService" + values = [ + "ecr.${var.region}.amazonaws.com" + ] + } + condition { + test = "StringEquals" + variable = "kms:CallerAccount" + values = local.allowed_accounts_via_service + } + } +} diff --git a/modules/aws/kms/eks.tf b/modules/aws/kms/eks.tf new file mode 100644 index 0000000..11fd4f1 --- /dev/null +++ b/modules/aws/kms/eks.tf @@ -0,0 +1,61 @@ +# tflint-ignore: terraform_standard_module_structure +variable "enable_kms_eks" { + description = "Enable customer managed key that can be used to encrypt/decrypt Amazon EKS" + type = bool + default = false +} + +# tflint-ignore: terraform_standard_module_structure +variable "enable_key_rotation_eks" { + description = "Enable key rotation for Amazon EKS CMK" + type = bool + default = true +} + +# tflint-ignore: terraform_standard_module_structure +variable "enable_multi_region_eks" { + description = "Enable multi-region for Amazon EKS CMK" + type = bool + default = false +} + +# tflint-ignore: terraform_standard_module_structure +variable "override_policy_eks" { + description = "A valid KMS key policy JSON document. If not specified, a canonical key policy will be used." + type = string + default = null +} + +data "aws_iam_policy_document" "eks" { + # checkov:skip=CKV_AWS_109: Not applicable, using condition + # checkov:skip=CKV_AWS_111: Not applicable, using condition + source_policy_documents = [data.aws_iam_policy_document.admin_kms_policy.json] + + statement { + sid = "Allow access through Amazon EKS for all principals in the account that are authorized to use Amazon EKS" + principals { + type = "AWS" + identifiers = ["*"] + } + actions = [ + "kms:Encrypt", + "kms:Decrypt", + "kms:ReEncrypt*", + "kms:GenerateDataKey*", + "kms:DescribeKey" + ] + resources = ["*"] + condition { + test = "StringEquals" + variable = "kms:ViaService" + values = [ + "eks.${var.region}.amazonaws.com" + ] + } + condition { + test = "StringEquals" + variable = "kms:CallerAccount" + values = local.allowed_accounts_via_service + } + } +} diff --git a/modules/aws/kms/locals.tf b/modules/aws/kms/locals.tf index 8c30746..350481d 100644 --- a/modules/aws/kms/locals.tf +++ b/modules/aws/kms/locals.tf @@ -24,6 +24,9 @@ locals { kinesis = try(length(var.override_policy_kinesis), 0) == 0 ? data.aws_iam_policy_document.kinesis.json : var.override_policy_kinesis glue = try(length(var.override_policy_glue), 0) == 0 ? data.aws_iam_policy_document.glue.json : var.override_policy_glue acm = try(length(var.override_policy_acm), 0) == 0 ? data.aws_iam_policy_document.acm.json : var.override_policy_acm + mwaa = try(length(var.override_policy_mwaa), 0) == 0 ? data.aws_iam_policy_document.mwaa.json : var.override_policy_mwaa + ecr = try(length(var.override_policy_ecr), 0) == 0 ? data.aws_iam_policy_document.ecr.json : var.override_policy_ecr + eks = try(length(var.override_policy_eks), 0) == 0 ? data.aws_iam_policy_document.eks.json : var.override_policy_eks } enable_key_rotation = { s3 = var.enable_key_rotation_s3 @@ -42,6 +45,9 @@ locals { kinesis = var.enable_key_rotation_kinesis glue = var.enable_key_rotation_glue acm = var.enable_key_rotation_acm + mwaa = var.enable_key_rotation_mwaa + ecr = var.enable_key_rotation_ecr + eks = var.enable_key_rotation_eks } multi_region = { s3 = var.enable_multi_region_s3 @@ -60,6 +66,9 @@ locals { kinesis = var.enable_multi_region_kinesis glue = var.enable_multi_region_glue acm = var.enable_multi_region_acm + mwaa = var.enable_multi_region_mwaa + ecr = var.enable_multi_region_ecr + eks = var.enable_multi_region_eks } } @@ -80,6 +89,9 @@ locals { var.enable_kms_session ? "session" : "", var.enable_kms_kinesis ? "kinesis" : "", var.enable_kms_glue ? "glue" : "", - var.enable_kms_acm ? "acm" : "" + var.enable_kms_acm ? "acm" : "", + var.enable_kms_mwaa ? "mwaa" : "", + var.enable_kms_ecr ? "ecr" : "", + var.enable_kms_eks ? "eks" : "" ]) } diff --git a/modules/aws/kms/logs.tf b/modules/aws/kms/logs.tf index 1933b28..8e4202d 100644 --- a/modules/aws/kms/logs.tf +++ b/modules/aws/kms/logs.tf @@ -45,7 +45,7 @@ data "aws_iam_policy_document" "logs" { ] resources = ["*"] condition { - test = "ArnEquals" + test = "ArnLike" variable = "kms:EncryptionContext:aws:logs:arn" values = [ "arn:aws:logs:${var.region}:${data.aws_caller_identity.current.account_id}:*" diff --git a/modules/aws/kms/mwaa.tf b/modules/aws/kms/mwaa.tf new file mode 100644 index 0000000..b0c671c --- /dev/null +++ b/modules/aws/kms/mwaa.tf @@ -0,0 +1,107 @@ +# tflint-ignore: terraform_standard_module_structure +variable "enable_kms_mwaa" { + description = "Enable customer managed key that can be used to encrypt/decrypt Amazon MWAA" + type = bool + default = false +} + +# tflint-ignore: terraform_standard_module_structure +variable "enable_key_rotation_mwaa" { + description = "Enable key rotation for Amazon MWAA CMK" + type = bool + default = true +} + +# tflint-ignore: terraform_standard_module_structure +variable "enable_multi_region_mwaa" { + description = "Enable multi-region for Amazon MWAA CMK" + type = bool + default = false +} + +# tflint-ignore: terraform_standard_module_structure +variable "override_policy_mwaa" { + description = "A valid KMS key policy JSON document. If not specified, a canonical key policy will be used." + type = string + default = null +} + +data "aws_iam_policy_document" "mwaa" { + # checkov:skip=CKV_AWS_111: Not applicable, using condition + source_policy_documents = [data.aws_iam_policy_document.admin_kms_policy.json] + + statement { + sid = "Allow access through Amazon S3 for all principals in the account that are authorized to use Amazon S3" + principals { + type = "AWS" + identifiers = ["*"] + } + actions = [ + "kms:Encrypt", + "kms:Decrypt", + "kms:ReEncrypt*", + "kms:GenerateDataKey*", + "kms:DescribeKey" + ] + resources = ["*"] + condition { + test = "StringEquals" + variable = "kms:ViaService" + values = [ + "s3.${var.region}.amazonaws.com" + ] + } + condition { + test = "StringEquals" + variable = "kms:CallerAccount" + values = local.allowed_accounts_via_service + } + } + + statement { + sid = "Allow access to CloudWatch Logs" + principals { + type = "Service" + identifiers = ["logs.${var.region}.amazonaws.com"] + } + actions = [ + "kms:Encrypt*", + "kms:Decrypt*", + "kms:ReEncrypt*", + "kms:GenerateDataKey*", + "kms:Describe*" + ] + resources = ["*"] + condition { + test = "ArnLike" + variable = "kms:EncryptionContext:aws:logs:arn" + values = [ + "arn:aws:logs:${var.region}:${data.aws_caller_identity.current.account_id}:*" + ] + } + } + + statement { + sid = "Allow access to MWAA SQS" + principals { + type = "AWS" + identifiers = ["*"] + } + actions = [ + "kms:Encrypt*", + "kms:Decrypt*", + "kms:ReEncrypt*", + "kms:GenerateDataKey*", + "kms:Describe*" + ] + resources = ["*"] + condition { + test = "ArnLike" + variable = "kms:EncryptionContext:aws:sqs:arn" + #SQS is in the Amazon owned account + values = [ + "arn:aws:sqs:${var.region}:*:airflow-celery-*" + ] + } + } +}