diff --git a/README.md b/README.md index 02c0ac48..a5318013 100644 --- a/README.md +++ b/README.md @@ -603,6 +603,8 @@ Following methods outlines various ways to consume and implement pre-written Sen - Aurora PostgreSQL DB clusters should publish logs to CloudWatch Logs ([docs](https://github.com/hashicorp/policy-library-FSBP-Policy-Set-for-AWS-Terraform/blob/main/docs/policies/aurora-postgresql-db-clusters-should-publish-logs-to-cloudwatch-logs.md) | [code](https://github.com/hashicorp/policy-library-FSBP-Policy-Set-for-AWS-Terraform/blob/main/policies/rds/aurora-postgresql-db-clusters-should-publish-logs-to-cloudwatch-logs.sentinel)) +- SNS topics should be encrypted at rest ([docs](https://github.com/hashicorp/policy-library-FSBP-Policy-Set-for-AWS-Terraform/blob/main/docs/policies/sns-topic-should-be-encrypted-at-rest.md) | [code](https://github.com/hashicorp/policy-library-FSBP-Policy-Set-for-AWS-Terraform/blob/main/policies/sns/sns-topic-should-be-encrypted-at-rest.sentinel)) + - SNS topic access policies should not allow public access([docs](https://github.com/hashicorp/policy-library-FSBP-Policy-Set-for-AWS-Terraform/blob/main/docs/policies/sns-topic-access-policies-should-not-allow-public-access.md) | [code](https://github.com/hashicorp/policy-library-FSBP-Policy-Set-for-AWS-Terraform/blob/main/policies/sns/sns-topic-access-policies-should-not-allow-public-access.sentinel)) - AWS WorkSpaces root volumes should be encrypted at rest ([docs](https://github.com/hashicorp/policy-library-FSBP-Policy-Set-for-AWS-Terraform/blob/main/docs/policies/workspaces-root-volumes-should-be-encrypted-at-rest.md) | [code](https://github.com/hashicorp/policy-library-FSBP-Policy-Set-for-AWS-Terraform/blob/main/policies/workspaces/workspaces-root-volumes-should-be-encrypted-at-rest.sentinel)) diff --git a/docs/policies/sns-topic-should-be-encrypted-at-rest.md b/docs/policies/sns-topic-should-be-encrypted-at-rest.md new file mode 100644 index 00000000..16385fba --- /dev/null +++ b/docs/policies/sns-topic-should-be-encrypted-at-rest.md @@ -0,0 +1,68 @@ +# Amazon SQS queues should be encrypted at rest + +| Provider | Category | +| ------------------- | ------------------------- | +| Amazon Web Services | Data Protection | + +## Description + +This control checks whether an Amazon SNS topic is encrypted at rest using keys managed in AWS Key Management Service (AWS KMS). The controls fails if the SNS topic doesn't use a KMS key for server-side encryption (SSE). By default, SNS stores messages and files using disk encryption. To pass this control, you must choose to use a KMS key for encryption instead. This adds an additional layer of security and provides more access control flexibility. + +Encrypting data at rest reduces the risk of data stored on disk being accessed by a user not authenticated to AWS. API permissions are required to decrypt the data before it can be read. We recommend encrypting SNS topics with KMS keys for an added layer of security. + +This rule is covered by the [sns-topic-should-be-encrypted-at-rest](https://github.com/hashicorp/policy-library-FSBP-Policy-Set-for-AWS-Terraform/blob/main/policies/sns-topic-should-be-encrypted-at-rest.sentinel) policy. + +## Policy Results (Pass) + +```bash +trace: + Pass - sns-topic-should-be-encrypted-at-rest.sentinel + + Description: + This policy requires resources of type `aws_sns_topic` to be encrypted at + rest. + + Print messages: + + → → Overall Result: true + + This result means that all resources have passed the policy check for the policy sns-topic-should-be-encrypted-at-rest. + + ✓ Found 0 resource violations + + sns-topic-should-be-encrypted-at-rest.sentinel:52:1 - Rule "main" + Value: + true +``` + +--- + +## Policy Results (Fail) + +```bash +trace: + Fail - sns-topic-should-be-encrypted-at-rest.sentinel + + Description: + This policy requires resources of type `aws_sns_topic` to be encrypted at + rest. + + Print messages: + + → → Overall Result: false + + This result means that not all resources passed the policy check and the protected behavior is not allowed for the policy sns-topic-should-be-encrypted-at-rest. + + Found 1 resource violations + + → Module name: root + ↳ Resource Address: aws_sns_topic.user_updates + | ✗ failed + | SNS topics should be encrypted at rest. Refer to https://docs.aws.amazon.com/securityhub/latest/userguide/sns-controls.html#sns-1 for more details. + + + sns-topic-should-be-encrypted-at-rest.sentinel:52:1 - Rule "main" + Value: +``` + +--- diff --git a/policies/sns/sns-topic-should-be-encrypted-at-rest.sentinel b/policies/sns/sns-topic-should-be-encrypted-at-rest.sentinel new file mode 100644 index 00000000..4ac2a785 --- /dev/null +++ b/policies/sns/sns-topic-should-be-encrypted-at-rest.sentinel @@ -0,0 +1,54 @@ +# This policy requires resources of type `aws_sns_topic` to be encrypted at rest. + +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: BUSL-1.1 + +# Imports + +import "tfplan/v2" as tfplan +import "tfresources" as tf +import "report" as report +import "collection" as collection +import "collection/maps" as maps + +# Constants + +const = { + "policy_name": "sns-topic-should-be-encrypted-at-rest", + "message": "SNS topics should be encrypted at rest. Refer to https://docs.aws.amazon.com/securityhub/latest/userguide/sns-controls.html#sns-1 for more details.", + "resource_aws_sns_topic": "aws_sns_topic", +} + +# Functions + +get_violations = func(resources) { + return collection.reject(resources, func(res) { + return maps.get(res, "values.kms_master_key_id", null) is not null + }) +} + +# Variables + +aws_sns_topics = tf.plan(tfplan.planned_values.resources).type(const.resource_aws_sns_topic).resources +violations = get_violations(aws_sns_topics) + +summary = { + "policy_name": const.policy_name, + "violations": map violations as _, v { + { + "address": v.address, + "module_address": v.module_address, + "message": const.message, + } + }, +} + +# Outputs + +print(report.generate_policy_report(summary)) + +# Rules + +main = rule { + violations is empty +} diff --git a/policies/sns/test/sns-topic-should-be-encrypted-at-rest/failure-encryption-at-rest-undefined.hcl b/policies/sns/test/sns-topic-should-be-encrypted-at-rest/failure-encryption-at-rest-undefined.hcl new file mode 100644 index 00000000..ca5d255d --- /dev/null +++ b/policies/sns/test/sns-topic-should-be-encrypted-at-rest/failure-encryption-at-rest-undefined.hcl @@ -0,0 +1,26 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: BUSL-1.1 + +mock "tfplan/v2" { + module { + source = "./mocks/failure-encryption-at-rest-undefined/mock-tfplan-v2.sentinel" + } +} + +mock "tfresources" { + module { + source = "../../../../modules/tfresources/tfresources.sentinel" + } +} + +mock "report" { + module { + source = "../../../../modules/mocks/report/report.sentinel" + } +} + +test { + rules = { + main = false + } +} \ No newline at end of file diff --git a/policies/sns/test/sns-topic-should-be-encrypted-at-rest/mocks/failure-encryption-at-rest-undefined/mock-tfplan-v2.sentinel b/policies/sns/test/sns-topic-should-be-encrypted-at-rest/mocks/failure-encryption-at-rest-undefined/mock-tfplan-v2.sentinel new file mode 100644 index 00000000..938474b2 --- /dev/null +++ b/policies/sns/test/sns-topic-should-be-encrypted-at-rest/mocks/failure-encryption-at-rest-undefined/mock-tfplan-v2.sentinel @@ -0,0 +1,45 @@ +terraform_version = "1.7.4" + +planned_values = { + "outputs": {}, + "resources": { + "aws_sns_topic.user_updates": { + "address": "aws_sns_topic.user_updates", + "depends_on": [], + "deposed_key": "", + "index": null, + "mode": "managed", + "module_address": "", + "name": "user_updates", + "provider_name": "registry.terraform.io/hashicorp/aws", + "tainted": false, + "type": "aws_sns_topic", + "values": { + "application_failure_feedback_role_arn": null, + "application_success_feedback_role_arn": null, + "application_success_feedback_sample_rate": null, + "archive_policy": null, + "content_based_deduplication": false, + "delivery_policy": null, + "display_name": null, + "fifo_topic": false, + "firehose_failure_feedback_role_arn": null, + "firehose_success_feedback_role_arn": null, + "firehose_success_feedback_sample_rate": null, + "http_failure_feedback_role_arn": null, + "http_success_feedback_role_arn": null, + "http_success_feedback_sample_rate": null, + "kms_master_key_id": null, + "lambda_failure_feedback_role_arn": null, + "lambda_success_feedback_role_arn": null, + "lambda_success_feedback_sample_rate": null, + "name": "user-updates-topic", + "region": "eu-west-1", + "sqs_failure_feedback_role_arn": null, + "sqs_success_feedback_role_arn": null, + "sqs_success_feedback_sample_rate": null, + "tags": null, + }, + }, + }, +} diff --git a/policies/sns/test/sns-topic-should-be-encrypted-at-rest/mocks/success/mock-tfplan-v2.sentinel b/policies/sns/test/sns-topic-should-be-encrypted-at-rest/mocks/success/mock-tfplan-v2.sentinel new file mode 100644 index 00000000..1a9cfe19 --- /dev/null +++ b/policies/sns/test/sns-topic-should-be-encrypted-at-rest/mocks/success/mock-tfplan-v2.sentinel @@ -0,0 +1,45 @@ +terraform_version = "1.7.4" + +planned_values = { + "outputs": {}, + "resources": { + "aws_sns_topic.user_updates": { + "address": "aws_sns_topic.user_updates", + "depends_on": [], + "deposed_key": "", + "index": null, + "mode": "managed", + "module_address": "", + "name": "user_updates", + "provider_name": "registry.terraform.io/hashicorp/aws", + "tainted": false, + "type": "aws_sns_topic", + "values": { + "application_failure_feedback_role_arn": null, + "application_success_feedback_role_arn": null, + "application_success_feedback_sample_rate": null, + "archive_policy": null, + "content_based_deduplication": false, + "delivery_policy": null, + "display_name": null, + "fifo_topic": false, + "firehose_failure_feedback_role_arn": null, + "firehose_success_feedback_role_arn": null, + "firehose_success_feedback_sample_rate": null, + "http_failure_feedback_role_arn": null, + "http_success_feedback_role_arn": null, + "http_success_feedback_sample_rate": null, + "kms_master_key_id": "alias/aws/sns", + "lambda_failure_feedback_role_arn": null, + "lambda_success_feedback_role_arn": null, + "lambda_success_feedback_sample_rate": null, + "name": "user-updates-topic", + "region": "eu-west-1", + "sqs_failure_feedback_role_arn": null, + "sqs_success_feedback_role_arn": null, + "sqs_success_feedback_sample_rate": null, + "tags": null, + }, + }, + }, +} diff --git a/policies/sns/test/sns-topic-should-be-encrypted-at-rest/success.hcl b/policies/sns/test/sns-topic-should-be-encrypted-at-rest/success.hcl new file mode 100644 index 00000000..66c5a046 --- /dev/null +++ b/policies/sns/test/sns-topic-should-be-encrypted-at-rest/success.hcl @@ -0,0 +1,26 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: BUSL-1.1 + +mock "tfplan/v2" { + module { + source = "./mocks/success/mock-tfplan-v2.sentinel" + } +} + +mock "tfresources" { + module { + source = "../../../../modules/tfresources/tfresources.sentinel" + } +} + +mock "report" { + module { + source = "../../../../modules/mocks/report/report.sentinel" + } +} + +test { + rules = { + main = true + } +} \ No newline at end of file diff --git a/sentinel.hcl b/sentinel.hcl index e3e86935..8cb983dc 100644 --- a/sentinel.hcl +++ b/sentinel.hcl @@ -1379,6 +1379,11 @@ policy "network-firewall-subnet-change-protection-enabled" { enforcement_level = "advisory" } +policy "sns-topic-should-be-encrypted-at-rest" { + source = "./policies/sns/sns-topic-should-be-encrypted-at-rest.sentinel" + enforcement_level = "advisory" +} + policy "sns-topic-access-policies-should-not-allow-public-access" { source = "./policies/sns/sns-topic-access-policies-should-not-allow-public-access.sentinel" enforcement_level = "advisory"