diff --git a/terraform/plan/rds-best-practices/check-rds-aurora-mysql-audit-logging-enabled/README.md b/terraform/plan/rds-best-practices/check-rds-aurora-mysql-audit-logging-enabled/README.md new file mode 100644 index 00000000..9af4059a --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-aurora-mysql-audit-logging-enabled/README.md @@ -0,0 +1,76 @@ +# Check RDS Aurora Mysql Audit Logging Enabled + +This policy checks whether an Amazon Aurora MySQL DB cluster is configured to publish audit logs to Amazon CloudWatch Logs. +The policy fails if the cluster isn't configured to publish audit logs to CloudWatch Logs. The policy doesn't generate findings foAurora Serverless v1 DB clusters. Audit logs capture a record of database activity, including login attempts, data modifications, schema changes, and other events that can be audited for security and compliance purposes. +When you configure an Aurora MySQL DB cluster to publish audit logs to a log group in Amazon CloudWatch Logs, you can perform real-time analysis of the log data. +CloudWatch Logs retains logs in highly durable storage. You can also create alarms and view metrics in CloudWatch. + +## Policy Details: + +- **Policy Name:** check-rds-aurora-mysql-audit-logging-enabled +- **Check Description:** This policy checks whether Aurora MySQL DB clusters publish audit logs to CloudWatch Logs +- **Policy Category:** AWS RDS Best Practices + +### Policy Validation Testing Instructions + +For testing this policy you will need to: +- Make sure you have `kyverno-json` installed on the machine +- Properly authenticate with AWS + +1. **Initialize Terraform:** + ```bash + terraform init + ``` + +2. **Create Binary Terraform Plan:** + ```bash + terraform plan -out tfplan.binary + ``` + +3. **Convert Binary to JSON Payload:** + ```bash + terraform show -json tfplan.binary | jq > payload.json + ``` + +4. **Test the Policy with Kyverno:** + ```bash + kyverno-json scan --payload payload.json --policy policy.yaml + ``` + + a. **Test Policy Against Valid Payload:** + ```bash + kyverno-json scan --payload test/good-test/good-payload-01.json --policy check-rds-aurora-mysql-audit-logging-enabled.yaml --bindings test/binding.yaml + ``` + + This produces the output: + ```bash + Loading policies ... + Loading bindings ... + - analyzer -> map[resource:map[type:terraform-plan]] + Loading payload ... + Pre processing ... + Running ( evaluating 1 resource against 1 policy ) ... + - PASSED (POLICY=check-rds-aurora-mysql-audit-logging-enabled, RULE=check-rds-aurora-mysql-audit-logging-enabled) + Done + ``` + + b. **Test Against Invalid Payload:** + ``` + kyverno-json scan --payload test/bad-test/bad-payload-01.json --policy check-rds-aurora-mysql-audit-logging-enabled.yaml --bindings test/binding.yaml + ``` + + This produces the output: + ```bash + Loading policies ... + Loading bindings ... + - analyzer -> map[resource:map[type:terraform-plan]] + Loading payload ... + Pre processing ... + Running ( evaluating 1 resource against 1 policy ) ... + - FAILED (POLICY=check-rds-aurora-mysql-audit-logging-enabled, RULE=check-rds-aurora-mysql-audit-logging-enabled) + -> Aurora MySQL DB clusters should publish audit logs to CloudWatch Logs (CHECK=spec.rules[0].assert.all[0]) + -> Invalid value: false: Expected value: true (PATH=~.(planned_values.root_module.resources[?type=='aws_rds_cluster' && contains('aurora-mysql', values.engine) && !contains('serverless', values.engine_mode)])[0].values.(enabled_cloudwatch_logs_exports != `null` && length(enabled_cloudwatch_logs_exports) > `0`)) + Done + ``` + +--- \ No newline at end of file diff --git a/terraform/plan/rds-best-practices/check-rds-aurora-mysql-audit-logging-enabled/check-rds-aurora-mysql-audit-logging-enabled.yaml b/terraform/plan/rds-best-practices/check-rds-aurora-mysql-audit-logging-enabled/check-rds-aurora-mysql-audit-logging-enabled.yaml new file mode 100644 index 00000000..dfe498c7 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-aurora-mysql-audit-logging-enabled/check-rds-aurora-mysql-audit-logging-enabled.yaml @@ -0,0 +1,29 @@ +apiVersion: json.kyverno.io/v1alpha1 +kind: ValidatingPolicy +metadata: + name: check-rds-aurora-mysql-audit-logging-enabled + annotations: + policies.kyverno.io/title: Check RDS Aurora Mysql Audit Logging Enabled + policies.kyverno.io/category: AWS RDS Best Practices + policies.kyverno.io/severity: medium + policies.kyverno.io/description: >- + This policy checks whether an Amazon Aurora MySQL DB cluster is configured to publish audit logs to Amazon CloudWatch Logs. + The policy fails if the cluster isn't configured to publish audit logs to CloudWatch Logs. The policy doesn't generate findings for Aurora Serverless v1 DB clusters. + Audit logs capture a record of database activity, including login attempts, data modifications, schema changes, and other events + that can be audited for security and compliance purposes. When you configure an Aurora MySQL DB cluster to publish + audit logs to a log group in Amazon CloudWatch Logs, you can perform real-time analysis of the log data. + CloudWatch Logs retains logs in highly durable storage. You can also create alarms and view metrics in CloudWatch. +spec: + rules: + - name: check-rds-aurora-mysql-audit-logging-enabled + match: + all: + - ($analyzer.resource.type): terraform-plan + - (planned_values.root_module.resources[?type=='aws_rds_cluster' && contains('aurora-mysql', values.engine) && !contains('serverless', values.engine_mode)] || `[]` | length(@) > `0`): true + assert: + all: + - message: Aurora MySQL DB clusters should publish audit logs to CloudWatch Logs + check: + ~.(planned_values.root_module.resources[?type=='aws_rds_cluster' && contains('aurora-mysql', values.engine) && !contains('serverless', values.engine_mode)]): + values: + (enabled_cloudwatch_logs_exports != `null` && length(enabled_cloudwatch_logs_exports) > `0`): true \ No newline at end of file diff --git a/terraform/plan/rds-best-practices/check-rds-aurora-mysql-audit-logging-enabled/test/bad-test/bad-01.tf b/terraform/plan/rds-best-practices/check-rds-aurora-mysql-audit-logging-enabled/test/bad-test/bad-01.tf new file mode 100644 index 00000000..2c767af2 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-aurora-mysql-audit-logging-enabled/test/bad-test/bad-01.tf @@ -0,0 +1,24 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" # Updated region +} + +# No audit log publication to CloudWatch Logs +resource "aws_rds_cluster" "bad_aurora_mysql_cluster" { + cluster_identifier = "bad-aurora-mysql-cluster" + engine = "aurora-mysql" + master_username = "admin" + master_password = "secret99" + backup_retention_period = 7 + skip_final_snapshot = true +} diff --git a/terraform/plan/rds-best-practices/check-rds-aurora-mysql-audit-logging-enabled/test/bad-test/bad-payload-01.json b/terraform/plan/rds-best-practices/check-rds-aurora-mysql-audit-logging-enabled/test/bad-test/bad-payload-01.json new file mode 100644 index 00000000..76eea0ce --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-aurora-mysql-audit-logging-enabled/test/bad-test/bad-payload-01.json @@ -0,0 +1,224 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_rds_cluster.bad_aurora_mysql_cluster", + "mode": "managed", + "type": "aws_rds_cluster", + "name": "bad_aurora_mysql_cluster", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 1, + "values": { + "allow_major_version_upgrade": null, + "backtrack_window": null, + "backup_retention_period": 7, + "cluster_identifier": "bad-aurora-mysql-cluster", + "copy_tags_to_snapshot": false, + "db_cluster_instance_class": null, + "db_instance_parameter_group_name": null, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_iam_role_name": null, + "enable_global_write_forwarding": false, + "enable_http_endpoint": false, + "enable_local_write_forwarding": false, + "enabled_cloudwatch_logs_exports": null, + "engine": "aurora-mysql", + "engine_mode": "provisioned", + "final_snapshot_identifier": null, + "global_cluster_identifier": null, + "iam_database_authentication_enabled": null, + "iops": null, + "manage_master_user_password": null, + "master_password": "secret99", + "master_username": "admin", + "performance_insights_enabled": null, + "replication_source_identifier": null, + "restore_to_point_in_time": [], + "s3_import": [], + "scaling_configuration": [], + "serverlessv2_scaling_configuration": [], + "skip_final_snapshot": true, + "snapshot_identifier": null, + "source_region": null, + "tags": null, + "timeouts": null + }, + "sensitive_values": { + "availability_zones": [], + "cluster_members": [], + "iam_roles": [], + "master_password": true, + "master_user_secret": [], + "restore_to_point_in_time": [], + "s3_import": [], + "scaling_configuration": [], + "serverlessv2_scaling_configuration": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_rds_cluster.bad_aurora_mysql_cluster", + "mode": "managed", + "type": "aws_rds_cluster", + "name": "bad_aurora_mysql_cluster", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "allow_major_version_upgrade": null, + "backtrack_window": null, + "backup_retention_period": 7, + "cluster_identifier": "bad-aurora-mysql-cluster", + "copy_tags_to_snapshot": false, + "db_cluster_instance_class": null, + "db_instance_parameter_group_name": null, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_iam_role_name": null, + "enable_global_write_forwarding": false, + "enable_http_endpoint": false, + "enable_local_write_forwarding": false, + "enabled_cloudwatch_logs_exports": null, + "engine": "aurora-mysql", + "engine_mode": "provisioned", + "final_snapshot_identifier": null, + "global_cluster_identifier": null, + "iam_database_authentication_enabled": null, + "iops": null, + "manage_master_user_password": null, + "master_password": "secret99", + "master_username": "admin", + "performance_insights_enabled": null, + "replication_source_identifier": null, + "restore_to_point_in_time": [], + "s3_import": [], + "scaling_configuration": [], + "serverlessv2_scaling_configuration": [], + "skip_final_snapshot": true, + "snapshot_identifier": null, + "source_region": null, + "tags": null, + "timeouts": null + }, + "after_unknown": { + "allocated_storage": true, + "apply_immediately": true, + "arn": true, + "availability_zones": true, + "ca_certificate_identifier": true, + "ca_certificate_valid_till": true, + "cluster_identifier_prefix": true, + "cluster_members": true, + "cluster_resource_id": true, + "database_name": true, + "db_cluster_parameter_group_name": true, + "db_subnet_group_name": true, + "db_system_id": true, + "endpoint": true, + "engine_lifecycle_support": true, + "engine_version": true, + "engine_version_actual": true, + "hosted_zone_id": true, + "iam_roles": true, + "id": true, + "kms_key_id": true, + "master_user_secret": true, + "master_user_secret_kms_key_id": true, + "network_type": true, + "performance_insights_kms_key_id": true, + "performance_insights_retention_period": true, + "port": true, + "preferred_backup_window": true, + "preferred_maintenance_window": true, + "reader_endpoint": true, + "restore_to_point_in_time": [], + "s3_import": [], + "scaling_configuration": [], + "serverlessv2_scaling_configuration": [], + "storage_encrypted": true, + "storage_type": true, + "tags_all": true, + "vpc_security_group_ids": true + }, + "before_sensitive": false, + "after_sensitive": { + "availability_zones": [], + "cluster_members": [], + "iam_roles": [], + "master_password": true, + "master_user_secret": [], + "restore_to_point_in_time": [], + "s3_import": [], + "scaling_configuration": [], + "serverlessv2_scaling_configuration": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": ">= 5.32.0", + "expressions": { + "region": { + "constant_value": "us-west-2" + } + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_rds_cluster.bad_aurora_mysql_cluster", + "mode": "managed", + "type": "aws_rds_cluster", + "name": "bad_aurora_mysql_cluster", + "provider_config_key": "aws", + "expressions": { + "backup_retention_period": { + "constant_value": 7 + }, + "cluster_identifier": { + "constant_value": "bad-aurora-mysql-cluster" + }, + "engine": { + "constant_value": "aurora-mysql" + }, + "master_password": { + "constant_value": "secret99" + }, + "master_username": { + "constant_value": "admin" + }, + "skip_final_snapshot": { + "constant_value": true + } + }, + "schema_version": 1 + } + ] + } + }, + "timestamp": "2024-10-01T13:07:17Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/rds-best-practices/check-rds-aurora-mysql-audit-logging-enabled/test/binding.yaml b/terraform/plan/rds-best-practices/check-rds-aurora-mysql-audit-logging-enabled/test/binding.yaml new file mode 100644 index 00000000..a3dd760d --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-aurora-mysql-audit-logging-enabled/test/binding.yaml @@ -0,0 +1,3 @@ +analyzer: + resource: + type: terraform-plan \ No newline at end of file diff --git a/terraform/plan/rds-best-practices/check-rds-aurora-mysql-audit-logging-enabled/test/chainsaw-test.yaml b/terraform/plan/rds-best-practices/check-rds-aurora-mysql-audit-logging-enabled/test/chainsaw-test.yaml new file mode 100644 index 00000000..3a8acc88 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-aurora-mysql-audit-logging-enabled/test/chainsaw-test.yaml @@ -0,0 +1,82 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/kyverno/chainsaw/main/.schemas/json/test-chainsaw-v1alpha1.json +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: good-test-01 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --payload ./good-test/good-payload-01.json --policy ../check-rds-aurora-mysql-audit-logging-enabled.yaml --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-rds-aurora-mysql-audit-logging-enabled + rules: + - rule: + name: check-rds-aurora-mysql-audit-logging-enabled + error: ~ + violations: ~ +--- +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: bad-test-01 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --payload ./bad-test/bad-payload-01.json --policy ../check-rds-aurora-mysql-audit-logging-enabled.yaml --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-rds-aurora-mysql-audit-logging-enabled + rules: + - rule: + name: check-rds-aurora-mysql-audit-logging-enabled + error: ~ + violations: + - message: Aurora MySQL DB clusters should publish audit logs to CloudWatch Logs (CHECK=spec.rules[0].assert.all[0]) + errors: + - type: FieldValueInvalid + value: false + detail: "Expected value: true" +--- +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: skip-test-01 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --payload ./skip-test/skip-payload-01.json --policy ../check-rds-aurora-mysql-audit-logging-enabled.yaml --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-rds-aurora-mysql-audit-logging-enabled + rules: ~ \ No newline at end of file diff --git a/terraform/plan/rds-best-practices/check-rds-aurora-mysql-audit-logging-enabled/test/good-test/good-01.tf b/terraform/plan/rds-best-practices/check-rds-aurora-mysql-audit-logging-enabled/test/good-test/good-01.tf new file mode 100644 index 00000000..e4f71b95 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-aurora-mysql-audit-logging-enabled/test/good-test/good-01.tf @@ -0,0 +1,24 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_rds_cluster" "good_aurora_mysql_cluster" { + cluster_identifier = "good-aurora-mysql-cluster" + engine = "aurora-mysql" + master_username = "admin" + master_password = "secret99" + backup_retention_period = 7 + enabled_cloudwatch_logs_exports = ["audit"] + skip_final_snapshot = true +} diff --git a/terraform/plan/rds-best-practices/check-rds-aurora-mysql-audit-logging-enabled/test/good-test/good-payload-01.json b/terraform/plan/rds-best-practices/check-rds-aurora-mysql-audit-logging-enabled/test/good-test/good-payload-01.json new file mode 100644 index 00000000..a611dc20 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-aurora-mysql-audit-logging-enabled/test/good-test/good-payload-01.json @@ -0,0 +1,242 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_rds_cluster.good_aurora_mysql_cluster", + "mode": "managed", + "type": "aws_rds_cluster", + "name": "good_aurora_mysql_cluster", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 1, + "values": { + "allow_major_version_upgrade": null, + "backtrack_window": null, + "backup_retention_period": 7, + "cluster_identifier": "good-aurora-mysql-cluster", + "copy_tags_to_snapshot": false, + "db_cluster_instance_class": null, + "db_instance_parameter_group_name": null, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_iam_role_name": null, + "enable_global_write_forwarding": false, + "enable_http_endpoint": false, + "enable_local_write_forwarding": false, + "enabled_cloudwatch_logs_exports": [ + "audit" + ], + "engine": "aurora-mysql", + "engine_mode": "provisioned", + "final_snapshot_identifier": null, + "global_cluster_identifier": null, + "iam_database_authentication_enabled": null, + "iops": null, + "manage_master_user_password": null, + "master_password": "secret99", + "master_username": "admin", + "performance_insights_enabled": null, + "replication_source_identifier": null, + "restore_to_point_in_time": [], + "s3_import": [], + "scaling_configuration": [], + "serverlessv2_scaling_configuration": [], + "skip_final_snapshot": true, + "snapshot_identifier": null, + "source_region": null, + "tags": null, + "timeouts": null + }, + "sensitive_values": { + "availability_zones": [], + "cluster_members": [], + "enabled_cloudwatch_logs_exports": [ + false + ], + "iam_roles": [], + "master_password": true, + "master_user_secret": [], + "restore_to_point_in_time": [], + "s3_import": [], + "scaling_configuration": [], + "serverlessv2_scaling_configuration": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_rds_cluster.good_aurora_mysql_cluster", + "mode": "managed", + "type": "aws_rds_cluster", + "name": "good_aurora_mysql_cluster", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "allow_major_version_upgrade": null, + "backtrack_window": null, + "backup_retention_period": 7, + "cluster_identifier": "good-aurora-mysql-cluster", + "copy_tags_to_snapshot": false, + "db_cluster_instance_class": null, + "db_instance_parameter_group_name": null, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_iam_role_name": null, + "enable_global_write_forwarding": false, + "enable_http_endpoint": false, + "enable_local_write_forwarding": false, + "enabled_cloudwatch_logs_exports": [ + "audit" + ], + "engine": "aurora-mysql", + "engine_mode": "provisioned", + "final_snapshot_identifier": null, + "global_cluster_identifier": null, + "iam_database_authentication_enabled": null, + "iops": null, + "manage_master_user_password": null, + "master_password": "secret99", + "master_username": "admin", + "performance_insights_enabled": null, + "replication_source_identifier": null, + "restore_to_point_in_time": [], + "s3_import": [], + "scaling_configuration": [], + "serverlessv2_scaling_configuration": [], + "skip_final_snapshot": true, + "snapshot_identifier": null, + "source_region": null, + "tags": null, + "timeouts": null + }, + "after_unknown": { + "allocated_storage": true, + "apply_immediately": true, + "arn": true, + "availability_zones": true, + "ca_certificate_identifier": true, + "ca_certificate_valid_till": true, + "cluster_identifier_prefix": true, + "cluster_members": true, + "cluster_resource_id": true, + "database_name": true, + "db_cluster_parameter_group_name": true, + "db_subnet_group_name": true, + "db_system_id": true, + "enabled_cloudwatch_logs_exports": [ + false + ], + "endpoint": true, + "engine_lifecycle_support": true, + "engine_version": true, + "engine_version_actual": true, + "hosted_zone_id": true, + "iam_roles": true, + "id": true, + "kms_key_id": true, + "master_user_secret": true, + "master_user_secret_kms_key_id": true, + "network_type": true, + "performance_insights_kms_key_id": true, + "performance_insights_retention_period": true, + "port": true, + "preferred_backup_window": true, + "preferred_maintenance_window": true, + "reader_endpoint": true, + "restore_to_point_in_time": [], + "s3_import": [], + "scaling_configuration": [], + "serverlessv2_scaling_configuration": [], + "storage_encrypted": true, + "storage_type": true, + "tags_all": true, + "vpc_security_group_ids": true + }, + "before_sensitive": false, + "after_sensitive": { + "availability_zones": [], + "cluster_members": [], + "enabled_cloudwatch_logs_exports": [ + false + ], + "iam_roles": [], + "master_password": true, + "master_user_secret": [], + "restore_to_point_in_time": [], + "s3_import": [], + "scaling_configuration": [], + "serverlessv2_scaling_configuration": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": ">= 5.32.0", + "expressions": { + "region": { + "constant_value": "us-west-2" + } + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_rds_cluster.good_aurora_mysql_cluster", + "mode": "managed", + "type": "aws_rds_cluster", + "name": "good_aurora_mysql_cluster", + "provider_config_key": "aws", + "expressions": { + "backup_retention_period": { + "constant_value": 7 + }, + "cluster_identifier": { + "constant_value": "good-aurora-mysql-cluster" + }, + "enabled_cloudwatch_logs_exports": { + "constant_value": [ + "audit" + ] + }, + "engine": { + "constant_value": "aurora-mysql" + }, + "master_password": { + "constant_value": "secret99" + }, + "master_username": { + "constant_value": "admin" + }, + "skip_final_snapshot": { + "constant_value": true + } + }, + "schema_version": 1 + } + ] + } + }, + "timestamp": "2024-10-01T13:07:19Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/rds-best-practices/check-rds-aurora-mysql-audit-logging-enabled/test/skip-test/skip-01.tf b/terraform/plan/rds-best-practices/check-rds-aurora-mysql-audit-logging-enabled/test/skip-test/skip-01.tf new file mode 100644 index 00000000..3fb261ce --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-aurora-mysql-audit-logging-enabled/test/skip-test/skip-01.tf @@ -0,0 +1,24 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" # Updated region +} + +resource "aws_rds_cluster" "skip_serverless_aurora_cluster" { + cluster_identifier = "skip-serverless-aurora-cluster" + engine = "aurora-mysql" + engine_mode = "serverless" # Aurora Serverless v1 is skipped + master_username = "admin" + master_password = "secret99" + backup_retention_period = 7 + skip_final_snapshot = true +} diff --git a/terraform/plan/rds-best-practices/check-rds-aurora-mysql-audit-logging-enabled/test/skip-test/skip-payload-01.json b/terraform/plan/rds-best-practices/check-rds-aurora-mysql-audit-logging-enabled/test/skip-test/skip-payload-01.json new file mode 100644 index 00000000..59b565bb --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-aurora-mysql-audit-logging-enabled/test/skip-test/skip-payload-01.json @@ -0,0 +1,227 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_rds_cluster.skip_serverless_aurora_cluster", + "mode": "managed", + "type": "aws_rds_cluster", + "name": "skip_serverless_aurora_cluster", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 1, + "values": { + "allow_major_version_upgrade": null, + "backtrack_window": null, + "backup_retention_period": 7, + "cluster_identifier": "skip-serverless-aurora-cluster", + "copy_tags_to_snapshot": false, + "db_cluster_instance_class": null, + "db_instance_parameter_group_name": null, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_iam_role_name": null, + "enable_global_write_forwarding": false, + "enable_http_endpoint": false, + "enable_local_write_forwarding": false, + "enabled_cloudwatch_logs_exports": null, + "engine": "aurora-mysql", + "engine_mode": "serverless", + "final_snapshot_identifier": null, + "global_cluster_identifier": null, + "iam_database_authentication_enabled": null, + "iops": null, + "manage_master_user_password": null, + "master_password": "secret99", + "master_username": "admin", + "performance_insights_enabled": null, + "replication_source_identifier": null, + "restore_to_point_in_time": [], + "s3_import": [], + "scaling_configuration": [], + "serverlessv2_scaling_configuration": [], + "skip_final_snapshot": true, + "snapshot_identifier": null, + "source_region": null, + "tags": null, + "timeouts": null + }, + "sensitive_values": { + "availability_zones": [], + "cluster_members": [], + "iam_roles": [], + "master_password": true, + "master_user_secret": [], + "restore_to_point_in_time": [], + "s3_import": [], + "scaling_configuration": [], + "serverlessv2_scaling_configuration": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_rds_cluster.skip_serverless_aurora_cluster", + "mode": "managed", + "type": "aws_rds_cluster", + "name": "skip_serverless_aurora_cluster", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "allow_major_version_upgrade": null, + "backtrack_window": null, + "backup_retention_period": 7, + "cluster_identifier": "skip-serverless-aurora-cluster", + "copy_tags_to_snapshot": false, + "db_cluster_instance_class": null, + "db_instance_parameter_group_name": null, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_iam_role_name": null, + "enable_global_write_forwarding": false, + "enable_http_endpoint": false, + "enable_local_write_forwarding": false, + "enabled_cloudwatch_logs_exports": null, + "engine": "aurora-mysql", + "engine_mode": "serverless", + "final_snapshot_identifier": null, + "global_cluster_identifier": null, + "iam_database_authentication_enabled": null, + "iops": null, + "manage_master_user_password": null, + "master_password": "secret99", + "master_username": "admin", + "performance_insights_enabled": null, + "replication_source_identifier": null, + "restore_to_point_in_time": [], + "s3_import": [], + "scaling_configuration": [], + "serverlessv2_scaling_configuration": [], + "skip_final_snapshot": true, + "snapshot_identifier": null, + "source_region": null, + "tags": null, + "timeouts": null + }, + "after_unknown": { + "allocated_storage": true, + "apply_immediately": true, + "arn": true, + "availability_zones": true, + "ca_certificate_identifier": true, + "ca_certificate_valid_till": true, + "cluster_identifier_prefix": true, + "cluster_members": true, + "cluster_resource_id": true, + "database_name": true, + "db_cluster_parameter_group_name": true, + "db_subnet_group_name": true, + "db_system_id": true, + "endpoint": true, + "engine_lifecycle_support": true, + "engine_version": true, + "engine_version_actual": true, + "hosted_zone_id": true, + "iam_roles": true, + "id": true, + "kms_key_id": true, + "master_user_secret": true, + "master_user_secret_kms_key_id": true, + "network_type": true, + "performance_insights_kms_key_id": true, + "performance_insights_retention_period": true, + "port": true, + "preferred_backup_window": true, + "preferred_maintenance_window": true, + "reader_endpoint": true, + "restore_to_point_in_time": [], + "s3_import": [], + "scaling_configuration": [], + "serverlessv2_scaling_configuration": [], + "storage_encrypted": true, + "storage_type": true, + "tags_all": true, + "vpc_security_group_ids": true + }, + "before_sensitive": false, + "after_sensitive": { + "availability_zones": [], + "cluster_members": [], + "iam_roles": [], + "master_password": true, + "master_user_secret": [], + "restore_to_point_in_time": [], + "s3_import": [], + "scaling_configuration": [], + "serverlessv2_scaling_configuration": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": ">= 5.32.0", + "expressions": { + "region": { + "constant_value": "us-west-2" + } + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_rds_cluster.skip_serverless_aurora_cluster", + "mode": "managed", + "type": "aws_rds_cluster", + "name": "skip_serverless_aurora_cluster", + "provider_config_key": "aws", + "expressions": { + "backup_retention_period": { + "constant_value": 7 + }, + "cluster_identifier": { + "constant_value": "skip-serverless-aurora-cluster" + }, + "engine": { + "constant_value": "aurora-mysql" + }, + "engine_mode": { + "constant_value": "serverless" + }, + "master_password": { + "constant_value": "secret99" + }, + "master_username": { + "constant_value": "admin" + }, + "skip_final_snapshot": { + "constant_value": true + } + }, + "schema_version": 1 + } + ] + } + }, + "timestamp": "2024-10-01T13:07:16Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/rds-best-practices/check-rds-automatic-minor-version-upgrade-enabled/README.md b/terraform/plan/rds-best-practices/check-rds-automatic-minor-version-upgrade-enabled/README.md new file mode 100644 index 00000000..de161017 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-automatic-minor-version-upgrade-enabled/README.md @@ -0,0 +1,76 @@ +# Check RDS Automatic Minor Version Upgrade Enabled + +This policy checks whether automatic minor version upgrades are enabled for the RDS database instance. +Enabling automatic minor version upgrades ensures that the latest minor version updates to the +relational database management system (RDBMS) are installed. These upgrades might include security patches and bug fixes. +Keeping up to date with patch installation is an important step in securing systems. + +## Policy Details: + +- **Policy Name:** check-rds-automatic-minor-version-upgrade-enabled +- **Check Description:** This policy checks whether automatic minor version upgrades are enabled for the RDS database instance. +- **Policy Category:** AWS RDS Best Practices + +### Policy Validation Testing Instructions + +For testing this policy you will need to: +- Make sure you have `kyverno-json` installed on the machine +- Properly authenticate with AWS + +1. **Initialize Terraform:** + ```bash + terraform init + ``` + +2. **Create Binary Terraform Plan:** + ```bash + terraform plan -out tfplan.binary + ``` + +3. **Convert Binary to JSON Payload:** + ```bash + terraform show -json tfplan.binary | jq > payload.json + ``` + +4. **Test the Policy with Kyverno:** + ```bash + kyverno-json scan --payload payload.json --policy policy.yaml + ``` + + a. **Test Policy Against Valid Payload:** + ```bash + kyverno-json scan --payload test/good-test/good-payload-01.json --policy check-rds-automatic-minor-version-upgrade-enabled.yaml --bindings test/binding.yaml + ``` + + This produces the output: + ```bash + Loading policies ... + Loading bindings ... + - analyzer -> map[resource:map[type:terraform-plan]] + Loading payload ... + Pre processing ... + Running ( evaluating 1 resource against 1 policy ) ... + - PASSED (POLICY=check-rds-automatic-minor-version-upgrade-enabled, RULE=check-rds-automatic-minor-version-upgrade-enabled) + Done + ``` + + b. **Test Against Invalid Payload:** + ```bash + kyverno-json scan --payload test/bad-test/bad-payload-01.json --policy check-rds-automatic-minor-version-upgrade-enabled.yaml --bindings test/binding.yaml + ``` + + This produces the output: + ```bash + Loading policies ... + Loading bindings ... + - analyzer -> map[resource:map[type:terraform-plan]] + Loading payload ... + Pre processing ... + Running ( evaluating 1 resource against 1 policy ) ... + - FAILED (POLICY=check-rds-automatic-minor-version-upgrade-enabled, RULE=check-rds-automatic-minor-version-upgrade-enabled) + -> RDS instances should have automatic minor version upgrades enabled (CHECK=spec.rules[0].assert.all[0]) + -> Invalid value: false: Expected value: true (PATH=~.(planned_values.root_module.resources[?type=='aws_db_instance'])[0].values.(auto_minor_version_upgrade)) + Done + ``` + +--- \ No newline at end of file diff --git a/terraform/plan/rds-best-practices/check-rds-automatic-minor-version-upgrade-enabled/check-rds-automatic-minor-version-upgrade-enabled.yaml b/terraform/plan/rds-best-practices/check-rds-automatic-minor-version-upgrade-enabled/check-rds-automatic-minor-version-upgrade-enabled.yaml new file mode 100644 index 00000000..ca787019 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-automatic-minor-version-upgrade-enabled/check-rds-automatic-minor-version-upgrade-enabled.yaml @@ -0,0 +1,27 @@ +apiVersion: json.kyverno.io/v1alpha1 +kind: ValidatingPolicy +metadata: + name: check-rds-automatic-minor-version-upgrade-enabled + annotations: + policies.kyverno.io/title: Check RDS Automatic Minor Version Upgrade Enabled + policies.kyverno.io/category: AWS RDS Best Practices + policies.kyverno.io/severity: high + policies.kyverno.io/description: >- + This policy checks whether automatic minor version upgrades are enabled for the RDS database instance. + Enabling automatic minor version upgrades ensures that the latest minor version updates to the + relational database management system (RDBMS) are installed. These upgrades might include security patches and bug fixes. + Keeping up to date with patch installation is an important step in securing systems. +spec: + rules: + - name: check-rds-automatic-minor-version-upgrade-enabled + match: + all: + - ($analyzer.resource.type): terraform-plan + - (planned_values.root_module.resources[?type=='aws_db_instance'] || `[]` | length(@) > `0`): true + assert: + all: + - message: RDS instances should have automatic minor version upgrades enabled + check: + ~.(planned_values.root_module.resources[?type=='aws_db_instance']): + values: + (auto_minor_version_upgrade): true diff --git a/terraform/plan/rds-best-practices/check-rds-automatic-minor-version-upgrade-enabled/test/bad-test/bad-01.tf b/terraform/plan/rds-best-practices/check-rds-automatic-minor-version-upgrade-enabled/test/bad-test/bad-01.tf new file mode 100644 index 00000000..b1219f96 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-automatic-minor-version-upgrade-enabled/test/bad-test/bad-01.tf @@ -0,0 +1,25 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_db_instance" "bad_mysql_instance" { + identifier = "bad-mysql-instance-01" + instance_class = "db.t3.micro" + engine = "mysql" + username = "admin" + password = "secret99" + allocated_storage = 5 + skip_final_snapshot = true + auto_minor_version_upgrade = false +} diff --git a/terraform/plan/rds-best-practices/check-rds-automatic-minor-version-upgrade-enabled/test/bad-test/bad-payload-01.json b/terraform/plan/rds-best-practices/check-rds-automatic-minor-version-upgrade-enabled/test/bad-test/bad-payload-01.json new file mode 100644 index 00000000..d7560ad1 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-automatic-minor-version-upgrade-enabled/test/bad-test/bad-payload-01.json @@ -0,0 +1,240 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_db_instance.bad_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "bad_mysql_instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 2, + "values": { + "allocated_storage": 5, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": false, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "identifier": "bad-mysql-instance-01", + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "secret99", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "admin" + }, + "sensitive_values": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_db_instance.bad_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "bad_mysql_instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "allocated_storage": 5, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": false, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "identifier": "bad-mysql-instance-01", + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "secret99", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "admin" + }, + "after_unknown": { + "address": true, + "arn": true, + "availability_zone": true, + "backup_retention_period": true, + "backup_target": true, + "backup_window": true, + "blue_green_update": [], + "ca_cert_identifier": true, + "character_set_name": true, + "db_name": true, + "db_subnet_group_name": true, + "domain_fqdn": true, + "endpoint": true, + "engine_lifecycle_support": true, + "engine_version": true, + "engine_version_actual": true, + "hosted_zone_id": true, + "id": true, + "identifier_prefix": true, + "iops": true, + "kms_key_id": true, + "latest_restorable_time": true, + "license_model": true, + "listener_endpoint": true, + "maintenance_window": true, + "master_user_secret": true, + "master_user_secret_kms_key_id": true, + "monitoring_role_arn": true, + "multi_az": true, + "nchar_character_set_name": true, + "network_type": true, + "option_group_name": true, + "parameter_group_name": true, + "performance_insights_kms_key_id": true, + "performance_insights_retention_period": true, + "port": true, + "replica_mode": true, + "replicas": true, + "resource_id": true, + "restore_to_point_in_time": [], + "s3_import": [], + "snapshot_identifier": true, + "status": true, + "storage_throughput": true, + "storage_type": true, + "tags_all": true, + "timezone": true, + "vpc_security_group_ids": true + }, + "before_sensitive": false, + "after_sensitive": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": ">= 5.32.0", + "expressions": { + "region": { + "constant_value": "us-west-2" + } + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_db_instance.bad_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "bad_mysql_instance", + "provider_config_key": "aws", + "expressions": { + "allocated_storage": { + "constant_value": 5 + }, + "auto_minor_version_upgrade": { + "constant_value": false + }, + "engine": { + "constant_value": "mysql" + }, + "identifier": { + "constant_value": "bad-mysql-instance-01" + }, + "instance_class": { + "constant_value": "db.t3.micro" + }, + "password": { + "constant_value": "secret99" + }, + "skip_final_snapshot": { + "constant_value": true + }, + "username": { + "constant_value": "admin" + } + }, + "schema_version": 2 + } + ] + } + }, + "timestamp": "2024-10-01T12:34:22Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/rds-best-practices/check-rds-automatic-minor-version-upgrade-enabled/test/binding.yaml b/terraform/plan/rds-best-practices/check-rds-automatic-minor-version-upgrade-enabled/test/binding.yaml new file mode 100644 index 00000000..a3dd760d --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-automatic-minor-version-upgrade-enabled/test/binding.yaml @@ -0,0 +1,3 @@ +analyzer: + resource: + type: terraform-plan \ No newline at end of file diff --git a/terraform/plan/rds-best-practices/check-rds-automatic-minor-version-upgrade-enabled/test/chainsaw-test.yaml b/terraform/plan/rds-best-practices/check-rds-automatic-minor-version-upgrade-enabled/test/chainsaw-test.yaml new file mode 100644 index 00000000..406393dd --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-automatic-minor-version-upgrade-enabled/test/chainsaw-test.yaml @@ -0,0 +1,86 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/kyverno/chainsaw/main/.schemas/json/test-chainsaw-v1alpha1.json +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: good-test-01 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --payload ./good-test/good-payload-01.json --policy ../check-rds-automatic-minor-version-upgrade-enabled.yaml --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-rds-automatic-minor-version-upgrade-enabled + rules: + - rule: + name: check-rds-automatic-minor-version-upgrade-enabled + error: ~ + violations: ~ +--- +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: good-test-02 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --payload ./good-test/good-payload-02.json --policy ../check-rds-automatic-minor-version-upgrade-enabled.yaml --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-rds-automatic-minor-version-upgrade-enabled + rules: + - rule: + name: check-rds-automatic-minor-version-upgrade-enabled + error: ~ + violations: ~ +--- +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: bad-test-01 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --payload ./bad-test/bad-payload-01.json --policy ../check-rds-automatic-minor-version-upgrade-enabled.yaml --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-rds-automatic-minor-version-upgrade-enabled + rules: + - rule: + name: check-rds-automatic-minor-version-upgrade-enabled + error: ~ + violations: + - message: RDS instances should have automatic minor version upgrades enabled (CHECK=spec.rules[0].assert.all[0]) + errors: + - type: FieldValueInvalid + value: false + detail: "Expected value: true" diff --git a/terraform/plan/rds-best-practices/check-rds-automatic-minor-version-upgrade-enabled/test/good-test/good-01.tf b/terraform/plan/rds-best-practices/check-rds-automatic-minor-version-upgrade-enabled/test/good-test/good-01.tf new file mode 100644 index 00000000..39f1bf99 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-automatic-minor-version-upgrade-enabled/test/good-test/good-01.tf @@ -0,0 +1,25 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_db_instance" "good_mysql_instance" { + identifier = "good-mysql-instance-01" + instance_class = "db.t3.micro" + engine = "mysql" + username = "admin" + password = "secret99" + allocated_storage = 5 + skip_final_snapshot = true + auto_minor_version_upgrade = true +} diff --git a/terraform/plan/rds-best-practices/check-rds-automatic-minor-version-upgrade-enabled/test/good-test/good-02.tf b/terraform/plan/rds-best-practices/check-rds-automatic-minor-version-upgrade-enabled/test/good-test/good-02.tf new file mode 100644 index 00000000..e36d1c25 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-automatic-minor-version-upgrade-enabled/test/good-test/good-02.tf @@ -0,0 +1,26 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_db_instance" "good_mysql_instance" { + identifier = "good-mysql-instance-01" + instance_class = "db.t3.micro" + engine = "mysql" + username = "admin" + password = "secret99" + allocated_storage = 5 + skip_final_snapshot = true +# auto_minor_version_upgrade defaults to true +# auto_minor_version_upgrade = true +} diff --git a/terraform/plan/rds-best-practices/check-rds-automatic-minor-version-upgrade-enabled/test/good-test/good-payload-01.json b/terraform/plan/rds-best-practices/check-rds-automatic-minor-version-upgrade-enabled/test/good-test/good-payload-01.json new file mode 100644 index 00000000..85d35cd7 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-automatic-minor-version-upgrade-enabled/test/good-test/good-payload-01.json @@ -0,0 +1,240 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_db_instance.good_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "good_mysql_instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 2, + "values": { + "allocated_storage": 5, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "identifier": "good-mysql-instance-01", + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "secret99", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "admin" + }, + "sensitive_values": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_db_instance.good_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "good_mysql_instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "allocated_storage": 5, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "identifier": "good-mysql-instance-01", + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "secret99", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "admin" + }, + "after_unknown": { + "address": true, + "arn": true, + "availability_zone": true, + "backup_retention_period": true, + "backup_target": true, + "backup_window": true, + "blue_green_update": [], + "ca_cert_identifier": true, + "character_set_name": true, + "db_name": true, + "db_subnet_group_name": true, + "domain_fqdn": true, + "endpoint": true, + "engine_lifecycle_support": true, + "engine_version": true, + "engine_version_actual": true, + "hosted_zone_id": true, + "id": true, + "identifier_prefix": true, + "iops": true, + "kms_key_id": true, + "latest_restorable_time": true, + "license_model": true, + "listener_endpoint": true, + "maintenance_window": true, + "master_user_secret": true, + "master_user_secret_kms_key_id": true, + "monitoring_role_arn": true, + "multi_az": true, + "nchar_character_set_name": true, + "network_type": true, + "option_group_name": true, + "parameter_group_name": true, + "performance_insights_kms_key_id": true, + "performance_insights_retention_period": true, + "port": true, + "replica_mode": true, + "replicas": true, + "resource_id": true, + "restore_to_point_in_time": [], + "s3_import": [], + "snapshot_identifier": true, + "status": true, + "storage_throughput": true, + "storage_type": true, + "tags_all": true, + "timezone": true, + "vpc_security_group_ids": true + }, + "before_sensitive": false, + "after_sensitive": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": ">= 5.32.0", + "expressions": { + "region": { + "constant_value": "us-west-2" + } + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_db_instance.good_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "good_mysql_instance", + "provider_config_key": "aws", + "expressions": { + "allocated_storage": { + "constant_value": 5 + }, + "auto_minor_version_upgrade": { + "constant_value": true + }, + "engine": { + "constant_value": "mysql" + }, + "identifier": { + "constant_value": "good-mysql-instance-01" + }, + "instance_class": { + "constant_value": "db.t3.micro" + }, + "password": { + "constant_value": "secret99" + }, + "skip_final_snapshot": { + "constant_value": true + }, + "username": { + "constant_value": "admin" + } + }, + "schema_version": 2 + } + ] + } + }, + "timestamp": "2024-10-01T12:34:55Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/rds-best-practices/check-rds-automatic-minor-version-upgrade-enabled/test/good-test/good-payload-02.json b/terraform/plan/rds-best-practices/check-rds-automatic-minor-version-upgrade-enabled/test/good-test/good-payload-02.json new file mode 100644 index 00000000..a1b0e8a2 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-automatic-minor-version-upgrade-enabled/test/good-test/good-payload-02.json @@ -0,0 +1,237 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_db_instance.good_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "good_mysql_instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 2, + "values": { + "allocated_storage": 5, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "identifier": "good-mysql-instance-01", + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "secret99", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "admin" + }, + "sensitive_values": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_db_instance.good_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "good_mysql_instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "allocated_storage": 5, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "identifier": "good-mysql-instance-01", + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "secret99", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "admin" + }, + "after_unknown": { + "address": true, + "arn": true, + "availability_zone": true, + "backup_retention_period": true, + "backup_target": true, + "backup_window": true, + "blue_green_update": [], + "ca_cert_identifier": true, + "character_set_name": true, + "db_name": true, + "db_subnet_group_name": true, + "domain_fqdn": true, + "endpoint": true, + "engine_lifecycle_support": true, + "engine_version": true, + "engine_version_actual": true, + "hosted_zone_id": true, + "id": true, + "identifier_prefix": true, + "iops": true, + "kms_key_id": true, + "latest_restorable_time": true, + "license_model": true, + "listener_endpoint": true, + "maintenance_window": true, + "master_user_secret": true, + "master_user_secret_kms_key_id": true, + "monitoring_role_arn": true, + "multi_az": true, + "nchar_character_set_name": true, + "network_type": true, + "option_group_name": true, + "parameter_group_name": true, + "performance_insights_kms_key_id": true, + "performance_insights_retention_period": true, + "port": true, + "replica_mode": true, + "replicas": true, + "resource_id": true, + "restore_to_point_in_time": [], + "s3_import": [], + "snapshot_identifier": true, + "status": true, + "storage_throughput": true, + "storage_type": true, + "tags_all": true, + "timezone": true, + "vpc_security_group_ids": true + }, + "before_sensitive": false, + "after_sensitive": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": ">= 5.32.0", + "expressions": { + "region": { + "constant_value": "us-west-2" + } + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_db_instance.good_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "good_mysql_instance", + "provider_config_key": "aws", + "expressions": { + "allocated_storage": { + "constant_value": 5 + }, + "engine": { + "constant_value": "mysql" + }, + "identifier": { + "constant_value": "good-mysql-instance-01" + }, + "instance_class": { + "constant_value": "db.t3.micro" + }, + "password": { + "constant_value": "secret99" + }, + "skip_final_snapshot": { + "constant_value": true + }, + "username": { + "constant_value": "admin" + } + }, + "schema_version": 2 + } + ] + } + }, + "timestamp": "2024-10-01T12:35:25Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/rds-best-practices/check-rds-cluster-deletion-protection-enabled/README.md b/terraform/plan/rds-best-practices/check-rds-cluster-deletion-protection-enabled/README.md new file mode 100644 index 00000000..ae7e5bbd --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-cluster-deletion-protection-enabled/README.md @@ -0,0 +1,76 @@ +# Check RDS Cluster Deletion Protection Enabled + +Preventing accidental deletion of an RDS database through the AWS Management Console, AWS CLI, or the RDS API is essential for avoiding data loss. +The database can't be deleted when deletion protection is enabled. This ensures an extra layer of protection for your data, preventing +unintended actions from impacting availability or causing data loss. By enabling deletion protection, you ensure that the database +remains intact until deliberate action is taken to disable this setting. + +## Policy Details: + +- **Policy Name:** check-rds-cluster-deletion-protection-enabled +- **Check Description:** This policy ensures that deletion protection is enabled for RDS databases +- **Policy Category:** AWS RDS Best Practices + +### Policy Validation Testing Instructions + +For testing this policy you will need to: +- Make sure you have `kyverno-json` installed on the machine +- Properly authenticate with AWS + +1. **Initialize Terraform:** + ```bash + terraform init + ``` + +2. **Create Binary Terraform Plan:** + ```bash + terraform plan -out tfplan.binary + ``` + +3. **Convert Binary to JSON Payload:** + ```bash + terraform show -json tfplan.binary | jq > payload.json + ``` + +4. **Test the Policy with Kyverno:** + ```bash + kyverno-json scan --payload payload.json --policy policy.yaml + ``` + + a. **Test Policy Against Valid Payload:** + ```bash + kyverno-json scan --payload test/good-test/good-payload-01.json --policy check-rds-cluster-deletion-protection-enabled.yaml --bindings test/binding.yaml + ``` + + This produces the output: + ```bash + Loading policies ... + Loading bindings ... + - analyzer -> map[resource:map[type:terraform-plan]] + Loading payload ... + Pre processing ... + Running ( evaluating 1 resource against 1 policy ) ... + - PASSED (POLICY=check-rds-cluster-deletion-protection-enabled, RULE=check-rds-cluster-deletion-protection-enabled) + Done + ``` + + b. **Test Against Invalid Payload:** + ``` + kyverno-json scan --payload test/bad-test/bad-payload-01.json --policy check-rds-cluster-deletion-protection-enabled.yaml --bindings test/binding.yaml + ``` + + This produces the output: + ```bash + Loading policies ... + Loading bindings ... + - analyzer -> map[resource:map[type:terraform-plan]] + Loading payload ... + Pre processing ... + Running ( evaluating 1 resource against 1 policy ) ... + - FAILED (POLICY=check-rds-cluster-deletion-protection-enabled, RULE=check-rds-cluster-deletion-protection-enabled) + -> RDS Database Deletion Protection must be enabled (CHECK=spec.rules[0].assert.all[0]) + -> Invalid value: false: Expected value: true (PATH=~.(planned_values.root_module.resources[?type=='aws_rds_cluster'])[0].values.(!!deletion_protection)) + Done + ``` + +--- \ No newline at end of file diff --git a/terraform/plan/rds-best-practices/check-rds-cluster-deletion-protection-enabled/check-rds-cluster-deletion-protection-enabled.yaml b/terraform/plan/rds-best-practices/check-rds-cluster-deletion-protection-enabled/check-rds-cluster-deletion-protection-enabled.yaml new file mode 100644 index 00000000..b3e56f59 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-cluster-deletion-protection-enabled/check-rds-cluster-deletion-protection-enabled.yaml @@ -0,0 +1,27 @@ +apiVersion: json.kyverno.io/v1alpha1 +kind: ValidatingPolicy +metadata: + name: check-rds-cluster-deletion-protection-enabled + annotations: + policies.kyverno.io/title: Check RDS Cluster Deletion Protection Enabled + policies.kyverno.io/category: AWS RDS Best Practices + policies.kyverno.io/severity: medium + policies.kyverno.io/description: >- + Preventing accidental deletion of an RDS database through the AWS Management Console, AWS CLI, or the RDS API is essential for avoiding data loss. + The database can't be deleted when deletion protection is enabled. This ensures an extra layer of protection for your data, preventing + unintended actions from impacting availability or causing data loss. By enabling deletion protection, you ensure that the database + remains intact until deliberate action is taken to disable this setting. +spec: + rules: + - name: check-rds-cluster-deletion-protection-enabled + match: + all: + - ($analyzer.resource.type): terraform-plan + - (planned_values.root_module.resources[?type=='aws_rds_cluster'] || `[]` | length(@) > `0`): true + assert: + all: + - message: RDS Database Deletion Protection must be enabled + check: + ~.(planned_values.root_module.resources[?type=='aws_rds_cluster']): + values: + (!!deletion_protection): true diff --git a/terraform/plan/rds-best-practices/check-rds-cluster-deletion-protection-enabled/test/bad-test/bad-01.tf b/terraform/plan/rds-best-practices/check-rds-cluster-deletion-protection-enabled/test/bad-test/bad-01.tf new file mode 100644 index 00000000..87a5fa34 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-cluster-deletion-protection-enabled/test/bad-test/bad-01.tf @@ -0,0 +1,22 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_rds_cluster" "bad_rds_db_cluster" { + cluster_identifier = "bad-rds-db-cluster-01" + engine = "aurora-mysql" + master_username = "admin" + master_password = "admin123" + deletion_protection = false +} diff --git a/terraform/plan/rds-best-practices/check-rds-cluster-deletion-protection-enabled/test/bad-test/bad-02.tf b/terraform/plan/rds-best-practices/check-rds-cluster-deletion-protection-enabled/test/bad-test/bad-02.tf new file mode 100644 index 00000000..de95fc5b --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-cluster-deletion-protection-enabled/test/bad-test/bad-02.tf @@ -0,0 +1,23 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_rds_cluster" "bad_rds_db_cluster" { + cluster_identifier = "bad-rds-db-cluster-01" + engine = "aurora-mysql" + master_username = "admin" + master_password = "admin123" + # deletion_protection defaults to false + # deletion_protection = false +} diff --git a/terraform/plan/rds-best-practices/check-rds-cluster-deletion-protection-enabled/test/bad-test/bad-payload-01.json b/terraform/plan/rds-best-practices/check-rds-cluster-deletion-protection-enabled/test/bad-test/bad-payload-01.json new file mode 100644 index 00000000..40c2c65b --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-cluster-deletion-protection-enabled/test/bad-test/bad-payload-01.json @@ -0,0 +1,220 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_rds_cluster.bad_rds_db_cluster", + "mode": "managed", + "type": "aws_rds_cluster", + "name": "bad_rds_db_cluster", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 1, + "values": { + "allow_major_version_upgrade": null, + "backtrack_window": null, + "cluster_identifier": "bad-rds-db-cluster-01", + "copy_tags_to_snapshot": false, + "db_cluster_instance_class": null, + "db_instance_parameter_group_name": null, + "delete_automated_backups": true, + "deletion_protection": false, + "domain": null, + "domain_iam_role_name": null, + "enable_global_write_forwarding": false, + "enable_http_endpoint": false, + "enable_local_write_forwarding": false, + "enabled_cloudwatch_logs_exports": null, + "engine": "aurora-mysql", + "engine_mode": "provisioned", + "final_snapshot_identifier": null, + "global_cluster_identifier": null, + "iam_database_authentication_enabled": null, + "iops": null, + "manage_master_user_password": null, + "master_password": "admin123", + "master_username": "admin", + "performance_insights_enabled": null, + "replication_source_identifier": null, + "restore_to_point_in_time": [], + "s3_import": [], + "scaling_configuration": [], + "serverlessv2_scaling_configuration": [], + "skip_final_snapshot": false, + "snapshot_identifier": null, + "source_region": null, + "tags": null, + "timeouts": null + }, + "sensitive_values": { + "availability_zones": [], + "cluster_members": [], + "iam_roles": [], + "master_password": true, + "master_user_secret": [], + "restore_to_point_in_time": [], + "s3_import": [], + "scaling_configuration": [], + "serverlessv2_scaling_configuration": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_rds_cluster.bad_rds_db_cluster", + "mode": "managed", + "type": "aws_rds_cluster", + "name": "bad_rds_db_cluster", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "allow_major_version_upgrade": null, + "backtrack_window": null, + "cluster_identifier": "bad-rds-db-cluster-01", + "copy_tags_to_snapshot": false, + "db_cluster_instance_class": null, + "db_instance_parameter_group_name": null, + "delete_automated_backups": true, + "deletion_protection": false, + "domain": null, + "domain_iam_role_name": null, + "enable_global_write_forwarding": false, + "enable_http_endpoint": false, + "enable_local_write_forwarding": false, + "enabled_cloudwatch_logs_exports": null, + "engine": "aurora-mysql", + "engine_mode": "provisioned", + "final_snapshot_identifier": null, + "global_cluster_identifier": null, + "iam_database_authentication_enabled": null, + "iops": null, + "manage_master_user_password": null, + "master_password": "admin123", + "master_username": "admin", + "performance_insights_enabled": null, + "replication_source_identifier": null, + "restore_to_point_in_time": [], + "s3_import": [], + "scaling_configuration": [], + "serverlessv2_scaling_configuration": [], + "skip_final_snapshot": false, + "snapshot_identifier": null, + "source_region": null, + "tags": null, + "timeouts": null + }, + "after_unknown": { + "allocated_storage": true, + "apply_immediately": true, + "arn": true, + "availability_zones": true, + "backup_retention_period": true, + "ca_certificate_identifier": true, + "ca_certificate_valid_till": true, + "cluster_identifier_prefix": true, + "cluster_members": true, + "cluster_resource_id": true, + "database_name": true, + "db_cluster_parameter_group_name": true, + "db_subnet_group_name": true, + "db_system_id": true, + "endpoint": true, + "engine_lifecycle_support": true, + "engine_version": true, + "engine_version_actual": true, + "hosted_zone_id": true, + "iam_roles": true, + "id": true, + "kms_key_id": true, + "master_user_secret": true, + "master_user_secret_kms_key_id": true, + "network_type": true, + "performance_insights_kms_key_id": true, + "performance_insights_retention_period": true, + "port": true, + "preferred_backup_window": true, + "preferred_maintenance_window": true, + "reader_endpoint": true, + "restore_to_point_in_time": [], + "s3_import": [], + "scaling_configuration": [], + "serverlessv2_scaling_configuration": [], + "storage_encrypted": true, + "storage_type": true, + "tags_all": true, + "vpc_security_group_ids": true + }, + "before_sensitive": false, + "after_sensitive": { + "availability_zones": [], + "cluster_members": [], + "iam_roles": [], + "master_password": true, + "master_user_secret": [], + "restore_to_point_in_time": [], + "s3_import": [], + "scaling_configuration": [], + "serverlessv2_scaling_configuration": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": ">= 5.32.0", + "expressions": { + "region": { + "constant_value": "us-west-2" + } + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_rds_cluster.bad_rds_db_cluster", + "mode": "managed", + "type": "aws_rds_cluster", + "name": "bad_rds_db_cluster", + "provider_config_key": "aws", + "expressions": { + "cluster_identifier": { + "constant_value": "bad-rds-db-cluster-01" + }, + "deletion_protection": { + "constant_value": false + }, + "engine": { + "constant_value": "aurora-mysql" + }, + "master_password": { + "constant_value": "admin123" + }, + "master_username": { + "constant_value": "admin" + } + }, + "schema_version": 1 + } + ] + } + }, + "timestamp": "2024-10-01T05:47:19Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/rds-best-practices/check-rds-cluster-deletion-protection-enabled/test/bad-test/bad-payload-02.json b/terraform/plan/rds-best-practices/check-rds-cluster-deletion-protection-enabled/test/bad-test/bad-payload-02.json new file mode 100644 index 00000000..90874ffa --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-cluster-deletion-protection-enabled/test/bad-test/bad-payload-02.json @@ -0,0 +1,217 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_rds_cluster.bad_rds_db_cluster", + "mode": "managed", + "type": "aws_rds_cluster", + "name": "bad_rds_db_cluster", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 1, + "values": { + "allow_major_version_upgrade": null, + "backtrack_window": null, + "cluster_identifier": "bad-rds-db-cluster-01", + "copy_tags_to_snapshot": false, + "db_cluster_instance_class": null, + "db_instance_parameter_group_name": null, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_iam_role_name": null, + "enable_global_write_forwarding": false, + "enable_http_endpoint": false, + "enable_local_write_forwarding": false, + "enabled_cloudwatch_logs_exports": null, + "engine": "aurora-mysql", + "engine_mode": "provisioned", + "final_snapshot_identifier": null, + "global_cluster_identifier": null, + "iam_database_authentication_enabled": null, + "iops": null, + "manage_master_user_password": null, + "master_password": "admin123", + "master_username": "admin", + "performance_insights_enabled": null, + "replication_source_identifier": null, + "restore_to_point_in_time": [], + "s3_import": [], + "scaling_configuration": [], + "serverlessv2_scaling_configuration": [], + "skip_final_snapshot": false, + "snapshot_identifier": null, + "source_region": null, + "tags": null, + "timeouts": null + }, + "sensitive_values": { + "availability_zones": [], + "cluster_members": [], + "iam_roles": [], + "master_password": true, + "master_user_secret": [], + "restore_to_point_in_time": [], + "s3_import": [], + "scaling_configuration": [], + "serverlessv2_scaling_configuration": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_rds_cluster.bad_rds_db_cluster", + "mode": "managed", + "type": "aws_rds_cluster", + "name": "bad_rds_db_cluster", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "allow_major_version_upgrade": null, + "backtrack_window": null, + "cluster_identifier": "bad-rds-db-cluster-01", + "copy_tags_to_snapshot": false, + "db_cluster_instance_class": null, + "db_instance_parameter_group_name": null, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_iam_role_name": null, + "enable_global_write_forwarding": false, + "enable_http_endpoint": false, + "enable_local_write_forwarding": false, + "enabled_cloudwatch_logs_exports": null, + "engine": "aurora-mysql", + "engine_mode": "provisioned", + "final_snapshot_identifier": null, + "global_cluster_identifier": null, + "iam_database_authentication_enabled": null, + "iops": null, + "manage_master_user_password": null, + "master_password": "admin123", + "master_username": "admin", + "performance_insights_enabled": null, + "replication_source_identifier": null, + "restore_to_point_in_time": [], + "s3_import": [], + "scaling_configuration": [], + "serverlessv2_scaling_configuration": [], + "skip_final_snapshot": false, + "snapshot_identifier": null, + "source_region": null, + "tags": null, + "timeouts": null + }, + "after_unknown": { + "allocated_storage": true, + "apply_immediately": true, + "arn": true, + "availability_zones": true, + "backup_retention_period": true, + "ca_certificate_identifier": true, + "ca_certificate_valid_till": true, + "cluster_identifier_prefix": true, + "cluster_members": true, + "cluster_resource_id": true, + "database_name": true, + "db_cluster_parameter_group_name": true, + "db_subnet_group_name": true, + "db_system_id": true, + "endpoint": true, + "engine_lifecycle_support": true, + "engine_version": true, + "engine_version_actual": true, + "hosted_zone_id": true, + "iam_roles": true, + "id": true, + "kms_key_id": true, + "master_user_secret": true, + "master_user_secret_kms_key_id": true, + "network_type": true, + "performance_insights_kms_key_id": true, + "performance_insights_retention_period": true, + "port": true, + "preferred_backup_window": true, + "preferred_maintenance_window": true, + "reader_endpoint": true, + "restore_to_point_in_time": [], + "s3_import": [], + "scaling_configuration": [], + "serverlessv2_scaling_configuration": [], + "storage_encrypted": true, + "storage_type": true, + "tags_all": true, + "vpc_security_group_ids": true + }, + "before_sensitive": false, + "after_sensitive": { + "availability_zones": [], + "cluster_members": [], + "iam_roles": [], + "master_password": true, + "master_user_secret": [], + "restore_to_point_in_time": [], + "s3_import": [], + "scaling_configuration": [], + "serverlessv2_scaling_configuration": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": ">= 5.32.0", + "expressions": { + "region": { + "constant_value": "us-west-2" + } + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_rds_cluster.bad_rds_db_cluster", + "mode": "managed", + "type": "aws_rds_cluster", + "name": "bad_rds_db_cluster", + "provider_config_key": "aws", + "expressions": { + "cluster_identifier": { + "constant_value": "bad-rds-db-cluster-01" + }, + "engine": { + "constant_value": "aurora-mysql" + }, + "master_password": { + "constant_value": "admin123" + }, + "master_username": { + "constant_value": "admin" + } + }, + "schema_version": 1 + } + ] + } + }, + "timestamp": "2024-10-01T05:48:12Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/rds-best-practices/check-rds-cluster-deletion-protection-enabled/test/binding.yaml b/terraform/plan/rds-best-practices/check-rds-cluster-deletion-protection-enabled/test/binding.yaml new file mode 100644 index 00000000..a3dd760d --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-cluster-deletion-protection-enabled/test/binding.yaml @@ -0,0 +1,3 @@ +analyzer: + resource: + type: terraform-plan \ No newline at end of file diff --git a/terraform/plan/rds-best-practices/check-rds-cluster-deletion-protection-enabled/test/chainsaw-test.yaml b/terraform/plan/rds-best-practices/check-rds-cluster-deletion-protection-enabled/test/chainsaw-test.yaml new file mode 100644 index 00000000..74250dec --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-cluster-deletion-protection-enabled/test/chainsaw-test.yaml @@ -0,0 +1,91 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/kyverno/chainsaw/main/.schemas/json/test-chainsaw-v1alpha1.json +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: good-test-01 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --payload ./good-test/good-payload-01.json --policy ../check-rds-cluster-deletion-protection-enabled.yaml --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-rds-cluster-deletion-protection-enabled + rules: + - rule: + name: check-rds-cluster-deletion-protection-enabled + error: ~ + violations: ~ +--- +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: bad-test-01 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --payload ./bad-test/bad-payload-01.json --policy ../check-rds-cluster-deletion-protection-enabled.yaml --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-rds-cluster-deletion-protection-enabled + rules: + - rule: + name: check-rds-cluster-deletion-protection-enabled + error: ~ + violations: + - message: RDS Database Deletion Protection must be enabled (CHECK=spec.rules[0].assert.all[0]) + errors: + - type: FieldValueInvalid + value: false + detail: "Expected value: true" +--- +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: bad-test-02 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --payload ./bad-test/bad-payload-02.json --policy ../check-rds-cluster-deletion-protection-enabled.yaml --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-rds-cluster-deletion-protection-enabled + rules: + - rule: + name: check-rds-cluster-deletion-protection-enabled + error: ~ + violations: + - message: RDS Database Deletion Protection must be enabled (CHECK=spec.rules[0].assert.all[0]) + errors: + - type: FieldValueInvalid + value: false + detail: "Expected value: true" \ No newline at end of file diff --git a/terraform/plan/rds-best-practices/check-rds-cluster-deletion-protection-enabled/test/good-test/good-01.tf b/terraform/plan/rds-best-practices/check-rds-cluster-deletion-protection-enabled/test/good-test/good-01.tf new file mode 100644 index 00000000..3efe74f4 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-cluster-deletion-protection-enabled/test/good-test/good-01.tf @@ -0,0 +1,22 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_rds_cluster" "good_rds_db_cluster" { + cluster_identifier = "good-rds-db-cluster-01" + engine = "aurora-mysql" + master_username = "admin" + master_password = "admin123" + deletion_protection = true +} diff --git a/terraform/plan/rds-best-practices/check-rds-cluster-deletion-protection-enabled/test/good-test/good-payload-01.json b/terraform/plan/rds-best-practices/check-rds-cluster-deletion-protection-enabled/test/good-test/good-payload-01.json new file mode 100644 index 00000000..a470e611 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-cluster-deletion-protection-enabled/test/good-test/good-payload-01.json @@ -0,0 +1,220 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_rds_cluster.good_rds_db_cluster", + "mode": "managed", + "type": "aws_rds_cluster", + "name": "good_rds_db_cluster", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 1, + "values": { + "allow_major_version_upgrade": null, + "backtrack_window": null, + "cluster_identifier": "good-rds-db-cluster-01", + "copy_tags_to_snapshot": false, + "db_cluster_instance_class": null, + "db_instance_parameter_group_name": null, + "delete_automated_backups": true, + "deletion_protection": true, + "domain": null, + "domain_iam_role_name": null, + "enable_global_write_forwarding": false, + "enable_http_endpoint": false, + "enable_local_write_forwarding": false, + "enabled_cloudwatch_logs_exports": null, + "engine": "aurora-mysql", + "engine_mode": "provisioned", + "final_snapshot_identifier": null, + "global_cluster_identifier": null, + "iam_database_authentication_enabled": null, + "iops": null, + "manage_master_user_password": null, + "master_password": "admin123", + "master_username": "admin", + "performance_insights_enabled": null, + "replication_source_identifier": null, + "restore_to_point_in_time": [], + "s3_import": [], + "scaling_configuration": [], + "serverlessv2_scaling_configuration": [], + "skip_final_snapshot": false, + "snapshot_identifier": null, + "source_region": null, + "tags": null, + "timeouts": null + }, + "sensitive_values": { + "availability_zones": [], + "cluster_members": [], + "iam_roles": [], + "master_password": true, + "master_user_secret": [], + "restore_to_point_in_time": [], + "s3_import": [], + "scaling_configuration": [], + "serverlessv2_scaling_configuration": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_rds_cluster.good_rds_db_cluster", + "mode": "managed", + "type": "aws_rds_cluster", + "name": "good_rds_db_cluster", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "allow_major_version_upgrade": null, + "backtrack_window": null, + "cluster_identifier": "good-rds-db-cluster-01", + "copy_tags_to_snapshot": false, + "db_cluster_instance_class": null, + "db_instance_parameter_group_name": null, + "delete_automated_backups": true, + "deletion_protection": true, + "domain": null, + "domain_iam_role_name": null, + "enable_global_write_forwarding": false, + "enable_http_endpoint": false, + "enable_local_write_forwarding": false, + "enabled_cloudwatch_logs_exports": null, + "engine": "aurora-mysql", + "engine_mode": "provisioned", + "final_snapshot_identifier": null, + "global_cluster_identifier": null, + "iam_database_authentication_enabled": null, + "iops": null, + "manage_master_user_password": null, + "master_password": "admin123", + "master_username": "admin", + "performance_insights_enabled": null, + "replication_source_identifier": null, + "restore_to_point_in_time": [], + "s3_import": [], + "scaling_configuration": [], + "serverlessv2_scaling_configuration": [], + "skip_final_snapshot": false, + "snapshot_identifier": null, + "source_region": null, + "tags": null, + "timeouts": null + }, + "after_unknown": { + "allocated_storage": true, + "apply_immediately": true, + "arn": true, + "availability_zones": true, + "backup_retention_period": true, + "ca_certificate_identifier": true, + "ca_certificate_valid_till": true, + "cluster_identifier_prefix": true, + "cluster_members": true, + "cluster_resource_id": true, + "database_name": true, + "db_cluster_parameter_group_name": true, + "db_subnet_group_name": true, + "db_system_id": true, + "endpoint": true, + "engine_lifecycle_support": true, + "engine_version": true, + "engine_version_actual": true, + "hosted_zone_id": true, + "iam_roles": true, + "id": true, + "kms_key_id": true, + "master_user_secret": true, + "master_user_secret_kms_key_id": true, + "network_type": true, + "performance_insights_kms_key_id": true, + "performance_insights_retention_period": true, + "port": true, + "preferred_backup_window": true, + "preferred_maintenance_window": true, + "reader_endpoint": true, + "restore_to_point_in_time": [], + "s3_import": [], + "scaling_configuration": [], + "serverlessv2_scaling_configuration": [], + "storage_encrypted": true, + "storage_type": true, + "tags_all": true, + "vpc_security_group_ids": true + }, + "before_sensitive": false, + "after_sensitive": { + "availability_zones": [], + "cluster_members": [], + "iam_roles": [], + "master_password": true, + "master_user_secret": [], + "restore_to_point_in_time": [], + "s3_import": [], + "scaling_configuration": [], + "serverlessv2_scaling_configuration": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": ">= 5.32.0", + "expressions": { + "region": { + "constant_value": "us-west-2" + } + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_rds_cluster.good_rds_db_cluster", + "mode": "managed", + "type": "aws_rds_cluster", + "name": "good_rds_db_cluster", + "provider_config_key": "aws", + "expressions": { + "cluster_identifier": { + "constant_value": "good-rds-db-cluster-01" + }, + "deletion_protection": { + "constant_value": true + }, + "engine": { + "constant_value": "aurora-mysql" + }, + "master_password": { + "constant_value": "admin123" + }, + "master_username": { + "constant_value": "admin" + } + }, + "schema_version": 1 + } + ] + } + }, + "timestamp": "2024-10-01T05:48:45Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/rds-best-practices/check-rds-db-proxy-tls/README.md b/terraform/plan/rds-best-practices/check-rds-db-proxy-tls/README.md new file mode 100644 index 00000000..619cbaa3 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-db-proxy-tls/README.md @@ -0,0 +1,76 @@ +# Check RDS DB Proxy TLS + +RDS Proxy can use security mechanisms such as TLS to add an additional layer of security between client applications and the underlying database. +Database connections often involve sensitive information, such as personally identifiable information (PII), financial data, or confidential business data. +Protecting this data in transit is important to maintain security of the data. +This policy checks if the RDS Proxy is using TLS. + +## Policy Details: + +- **Policy Name:** check-rds-db-proxy-tls +- **Check Description:** This policy ensures that RDS Proxies use TLS +- **Policy Category:** AWS RDS Best Practices + +### Policy Validation Testing Instructions + +For testing this policy you will need to: +- Make sure you have `kyverno-json` installed on the machine +- Properly authenticate with AWS + +1. **Initialize Terraform:** + ```bash + terraform init + ``` + +2. **Create Binary Terraform Plan:** + ```bash + terraform plan -out tfplan.binary + ``` + +3. **Convert Binary to JSON Payload:** + ```bash + terraform show -json tfplan.binary | jq > payload.json + ``` + +4. **Test the Policy with Kyverno:** + ```bash + kyverno-json scan --payload payload.json --policy policy.yaml + ``` + + a. **Test Policy Against Valid Payload:** + ```bash + kyverno-json scan --payload test/good-test/good-payload-01.json --policy check-rds-db-proxy-tls.yaml --bindings test/binding.yaml + ``` + + This produces the output: + ```bash + Loading policies ... + Loading bindings ... + - analyzer -> map[resource:map[type:terraform-plan]] + Loading payload ... + Pre processing ... + Running ( evaluating 1 resource against 1 policy ) ... + - PASSED (POLICY=check-rds-db-proxy-tls, RULE=check-rds-db-proxy-tls) + Done + ``` + + b. **Test Against Invalid Payload:** + ``` + kyverno-json scan --payload test/bad-test/bad-payload-01.json --policy check-rds-db-proxy-tls.yaml --bindings test/binding.yaml + ``` + + This produces the output: + ```bash + Loading policies ... + Loading bindings ... + - analyzer -> map[resource:map[type:terraform-plan]] + Loading payload ... + Pre processing ... + Running ( evaluating 1 resource against 1 policy ) ... + - FAILED (POLICY=check-rds-db-proxy-tls, RULE=check-rds-db-proxy-tls) + -> RDS Database Proxy should use TLS (CHECK=spec.rules[0].assert.all[0]) + -> Invalid value: false: Expected value: true (PATH=~.(planned_values.root_module.resources[?type=='aws_db_proxy'])[0].values.(!!require_tls)) + Done + ``` + +--- \ No newline at end of file diff --git a/terraform/plan/rds-best-practices/check-rds-db-proxy-tls/check-rds-db-proxy-tls.yaml b/terraform/plan/rds-best-practices/check-rds-db-proxy-tls/check-rds-db-proxy-tls.yaml new file mode 100644 index 00000000..b920f911 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-db-proxy-tls/check-rds-db-proxy-tls.yaml @@ -0,0 +1,27 @@ +apiVersion: json.kyverno.io/v1alpha1 +kind: ValidatingPolicy +metadata: + name: check-rds-db-proxy-tls + annotations: + policies.kyverno.io/title: Check RDS DB Proxy TLS + policies.kyverno.io/category: AWS RDS Best Practices + policies.kyverno.io/severity: medium + policies.kyverno.io/description: >- + RDS Proxy can use security mechanisms such as TLS to add an additional layer of security between client applications and the underlying database. + Database connections often involve sensitive information, such as personally identifiable information (PII), financial data, or confidential business data. + Protecting this data in transit is important to maintain security of the data. + This policy checks if the RDS Proxy is using TLS. +spec: + rules: + - name: check-rds-db-proxy-tls + match: + all: + - ($analyzer.resource.type): terraform-plan + - (planned_values.root_module.resources[?type=='aws_db_proxy'] || `[]` | length(@) > `0`): true + assert: + all: + - message: RDS Database Proxy should use TLS + check: + ~.(planned_values.root_module.resources[?type=='aws_db_proxy']): + values: + (!!require_tls): true \ No newline at end of file diff --git a/terraform/plan/rds-best-practices/check-rds-db-proxy-tls/test/bad-test/bad-01.tf b/terraform/plan/rds-best-practices/check-rds-db-proxy-tls/test/bad-test/bad-01.tf new file mode 100644 index 00000000..9e533349 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-db-proxy-tls/test/bad-test/bad-01.tf @@ -0,0 +1,43 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_secretsmanager_secret" "rds_secret" { + name = "rds-db-secret" + + tags = { + Name = "rds-db-secret" + } +} + +resource "aws_secretsmanager_secret_version" "rds_secret_version" { + secret_id = aws_secretsmanager_secret.rds_secret.id + secret_string = jsonencode({ + username = "admin" + password = "admin1234" + }) +} + +resource "aws_db_proxy" "bad_db_proxy" { + name = "bad-db-proxy-01" + engine_family = "POSTGRESQL" + role_arn = "arn:aws:iam::xxxx:role/aws-service-role/rds.amazonaws.com/AWSServiceRoleForRDS" + vpc_subnet_ids = ["subnet-id-1", "subnet-id-2"] + require_tls = false + + auth { + auth_scheme = "SECRETS" + secret_arn = aws_secretsmanager_secret.rds_secret.arn + } +} diff --git a/terraform/plan/rds-best-practices/check-rds-db-proxy-tls/test/bad-test/bad-02.tf b/terraform/plan/rds-best-practices/check-rds-db-proxy-tls/test/bad-test/bad-02.tf new file mode 100644 index 00000000..f1386050 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-db-proxy-tls/test/bad-test/bad-02.tf @@ -0,0 +1,42 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_secretsmanager_secret" "rds_secret" { + name = "rds-db-secret" + + tags = { + Name = "rds-db-secret" + } +} + +resource "aws_secretsmanager_secret_version" "rds_secret_version" { + secret_id = aws_secretsmanager_secret.rds_secret.id + secret_string = jsonencode({ + username = "admin" + password = "admin1234" + }) +} + +resource "aws_db_proxy" "bad_db_proxy" { + name = "bad-db-proxy-02" + engine_family = "POSTGRESQL" + role_arn = "arn:aws:iam::xxxx:role/aws-service-role/rds.amazonaws.com/AWSServiceRoleForRDS" + vpc_subnet_ids = ["subnet-id-1", "subnet-id-2"] + + auth { + auth_scheme = "SECRETS" + secret_arn = aws_secretsmanager_secret.rds_secret.arn + } +} diff --git a/terraform/plan/rds-best-practices/check-rds-db-proxy-tls/test/bad-test/bad-payload-01.json b/terraform/plan/rds-best-practices/check-rds-db-proxy-tls/test/bad-test/bad-payload-01.json new file mode 100644 index 00000000..bec146f9 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-db-proxy-tls/test/bad-test/bad-payload-01.json @@ -0,0 +1,342 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_db_proxy.bad_db_proxy", + "mode": "managed", + "type": "aws_db_proxy", + "name": "bad_db_proxy", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 0, + "values": { + "auth": [ + { + "auth_scheme": "SECRETS", + "description": "", + "iam_auth": "", + "username": "" + } + ], + "debug_logging": null, + "engine_family": "POSTGRESQL", + "name": "bad-db-proxy-01", + "require_tls": false, + "role_arn": "arn:aws:iam::xxxx:role/aws-service-role/rds.amazonaws.com/AWSServiceRoleForRDS", + "tags": null, + "timeouts": null, + "vpc_subnet_ids": [ + "subnet-id-1", + "subnet-id-2" + ] + }, + "sensitive_values": { + "auth": [ + {} + ], + "tags_all": {}, + "vpc_security_group_ids": [], + "vpc_subnet_ids": [ + false, + false + ] + } + }, + { + "address": "aws_secretsmanager_secret.rds_secret", + "mode": "managed", + "type": "aws_secretsmanager_secret", + "name": "rds_secret", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 0, + "values": { + "description": null, + "force_overwrite_replica_secret": false, + "kms_key_id": null, + "name": "rds-db-secret", + "recovery_window_in_days": 30, + "tags": { + "Name": "rds-db-secret" + }, + "tags_all": { + "Name": "rds-db-secret" + } + }, + "sensitive_values": { + "replica": [], + "tags": {}, + "tags_all": {} + } + }, + { + "address": "aws_secretsmanager_secret_version.rds_secret_version", + "mode": "managed", + "type": "aws_secretsmanager_secret_version", + "name": "rds_secret_version", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 0, + "values": { + "secret_binary": null, + "secret_string": "{\"password\":\"admin1234\",\"username\":\"admin\"}" + }, + "sensitive_values": { + "secret_binary": true, + "secret_string": true, + "version_stages": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_db_proxy.bad_db_proxy", + "mode": "managed", + "type": "aws_db_proxy", + "name": "bad_db_proxy", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "auth": [ + { + "auth_scheme": "SECRETS", + "description": "", + "iam_auth": "", + "username": "" + } + ], + "debug_logging": null, + "engine_family": "POSTGRESQL", + "name": "bad-db-proxy-01", + "require_tls": false, + "role_arn": "arn:aws:iam::xxxx:role/aws-service-role/rds.amazonaws.com/AWSServiceRoleForRDS", + "tags": null, + "timeouts": null, + "vpc_subnet_ids": [ + "subnet-id-1", + "subnet-id-2" + ] + }, + "after_unknown": { + "arn": true, + "auth": [ + { + "client_password_auth_type": true, + "secret_arn": true + } + ], + "endpoint": true, + "id": true, + "idle_client_timeout": true, + "tags_all": true, + "vpc_security_group_ids": true, + "vpc_subnet_ids": [ + false, + false + ] + }, + "before_sensitive": false, + "after_sensitive": { + "auth": [ + {} + ], + "tags_all": {}, + "vpc_security_group_ids": [], + "vpc_subnet_ids": [ + false, + false + ] + } + } + }, + { + "address": "aws_secretsmanager_secret.rds_secret", + "mode": "managed", + "type": "aws_secretsmanager_secret", + "name": "rds_secret", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "description": null, + "force_overwrite_replica_secret": false, + "kms_key_id": null, + "name": "rds-db-secret", + "recovery_window_in_days": 30, + "tags": { + "Name": "rds-db-secret" + }, + "tags_all": { + "Name": "rds-db-secret" + } + }, + "after_unknown": { + "arn": true, + "id": true, + "name_prefix": true, + "policy": true, + "replica": true, + "tags": {}, + "tags_all": {} + }, + "before_sensitive": false, + "after_sensitive": { + "replica": [], + "tags": {}, + "tags_all": {} + } + } + }, + { + "address": "aws_secretsmanager_secret_version.rds_secret_version", + "mode": "managed", + "type": "aws_secretsmanager_secret_version", + "name": "rds_secret_version", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "secret_binary": null, + "secret_string": "{\"password\":\"admin1234\",\"username\":\"admin\"}" + }, + "after_unknown": { + "arn": true, + "id": true, + "secret_id": true, + "version_id": true, + "version_stages": true + }, + "before_sensitive": false, + "after_sensitive": { + "secret_binary": true, + "secret_string": true, + "version_stages": [] + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": ">= 5.32.0", + "expressions": { + "region": { + "constant_value": "us-west-2" + } + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_db_proxy.bad_db_proxy", + "mode": "managed", + "type": "aws_db_proxy", + "name": "bad_db_proxy", + "provider_config_key": "aws", + "expressions": { + "auth": [ + { + "auth_scheme": { + "constant_value": "SECRETS" + }, + "secret_arn": { + "references": [ + "aws_secretsmanager_secret.rds_secret.arn", + "aws_secretsmanager_secret.rds_secret" + ] + } + } + ], + "engine_family": { + "constant_value": "POSTGRESQL" + }, + "name": { + "constant_value": "bad-db-proxy-01" + }, + "require_tls": { + "constant_value": false + }, + "role_arn": { + "constant_value": "arn:aws:iam::xxxx:role/aws-service-role/rds.amazonaws.com/AWSServiceRoleForRDS" + }, + "vpc_subnet_ids": { + "constant_value": [ + "subnet-id-1", + "subnet-id-2" + ] + } + }, + "schema_version": 0 + }, + { + "address": "aws_secretsmanager_secret.rds_secret", + "mode": "managed", + "type": "aws_secretsmanager_secret", + "name": "rds_secret", + "provider_config_key": "aws", + "expressions": { + "name": { + "constant_value": "rds-db-secret" + }, + "tags": { + "constant_value": { + "Name": "rds-db-secret" + } + } + }, + "schema_version": 0 + }, + { + "address": "aws_secretsmanager_secret_version.rds_secret_version", + "mode": "managed", + "type": "aws_secretsmanager_secret_version", + "name": "rds_secret_version", + "provider_config_key": "aws", + "expressions": { + "secret_id": { + "references": [ + "aws_secretsmanager_secret.rds_secret.id", + "aws_secretsmanager_secret.rds_secret" + ] + }, + "secret_string": {} + }, + "schema_version": 0 + } + ] + } + }, + "relevant_attributes": [ + { + "resource": "aws_secretsmanager_secret.rds_secret", + "attribute": [ + "id" + ] + }, + { + "resource": "aws_secretsmanager_secret.rds_secret", + "attribute": [ + "arn" + ] + } + ], + "timestamp": "2024-10-01T07:48:25Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/rds-best-practices/check-rds-db-proxy-tls/test/bad-test/bad-payload-02.json b/terraform/plan/rds-best-practices/check-rds-db-proxy-tls/test/bad-test/bad-payload-02.json new file mode 100644 index 00000000..5a74cd92 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-db-proxy-tls/test/bad-test/bad-payload-02.json @@ -0,0 +1,339 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_db_proxy.bad_db_proxy", + "mode": "managed", + "type": "aws_db_proxy", + "name": "bad_db_proxy", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 0, + "values": { + "auth": [ + { + "auth_scheme": "SECRETS", + "description": "", + "iam_auth": "", + "username": "" + } + ], + "debug_logging": null, + "engine_family": "POSTGRESQL", + "name": "bad-db-proxy-02", + "require_tls": null, + "role_arn": "arn:aws:iam::xxxx:role/aws-service-role/rds.amazonaws.com/AWSServiceRoleForRDS", + "tags": null, + "timeouts": null, + "vpc_subnet_ids": [ + "subnet-03c8d8c9fc4dc6c23", + "subnet-0a3043a2ad9bd85a7" + ] + }, + "sensitive_values": { + "auth": [ + {} + ], + "tags_all": {}, + "vpc_security_group_ids": [], + "vpc_subnet_ids": [ + false, + false + ] + } + }, + { + "address": "aws_secretsmanager_secret.rds_secret", + "mode": "managed", + "type": "aws_secretsmanager_secret", + "name": "rds_secret", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 0, + "values": { + "description": null, + "force_overwrite_replica_secret": false, + "kms_key_id": null, + "name": "rds-db-secret", + "recovery_window_in_days": 30, + "tags": { + "Name": "rds-db-secret" + }, + "tags_all": { + "Name": "rds-db-secret" + } + }, + "sensitive_values": { + "replica": [], + "tags": {}, + "tags_all": {} + } + }, + { + "address": "aws_secretsmanager_secret_version.rds_secret_version", + "mode": "managed", + "type": "aws_secretsmanager_secret_version", + "name": "rds_secret_version", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 0, + "values": { + "secret_binary": null, + "secret_string": "{\"password\":\"admin1234\",\"username\":\"admin\"}" + }, + "sensitive_values": { + "secret_binary": true, + "secret_string": true, + "version_stages": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_db_proxy.bad_db_proxy", + "mode": "managed", + "type": "aws_db_proxy", + "name": "bad_db_proxy", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "auth": [ + { + "auth_scheme": "SECRETS", + "description": "", + "iam_auth": "", + "username": "" + } + ], + "debug_logging": null, + "engine_family": "POSTGRESQL", + "name": "bad-db-proxy-02", + "require_tls": null, + "role_arn": "arn:aws:iam::xxxx:role/aws-service-role/rds.amazonaws.com/AWSServiceRoleForRDS", + "tags": null, + "timeouts": null, + "vpc_subnet_ids": [ + "subnet-03c8d8c9fc4dc6c23", + "subnet-0a3043a2ad9bd85a7" + ] + }, + "after_unknown": { + "arn": true, + "auth": [ + { + "client_password_auth_type": true, + "secret_arn": true + } + ], + "endpoint": true, + "id": true, + "idle_client_timeout": true, + "tags_all": true, + "vpc_security_group_ids": true, + "vpc_subnet_ids": [ + false, + false + ] + }, + "before_sensitive": false, + "after_sensitive": { + "auth": [ + {} + ], + "tags_all": {}, + "vpc_security_group_ids": [], + "vpc_subnet_ids": [ + false, + false + ] + } + } + }, + { + "address": "aws_secretsmanager_secret.rds_secret", + "mode": "managed", + "type": "aws_secretsmanager_secret", + "name": "rds_secret", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "description": null, + "force_overwrite_replica_secret": false, + "kms_key_id": null, + "name": "rds-db-secret", + "recovery_window_in_days": 30, + "tags": { + "Name": "rds-db-secret" + }, + "tags_all": { + "Name": "rds-db-secret" + } + }, + "after_unknown": { + "arn": true, + "id": true, + "name_prefix": true, + "policy": true, + "replica": true, + "tags": {}, + "tags_all": {} + }, + "before_sensitive": false, + "after_sensitive": { + "replica": [], + "tags": {}, + "tags_all": {} + } + } + }, + { + "address": "aws_secretsmanager_secret_version.rds_secret_version", + "mode": "managed", + "type": "aws_secretsmanager_secret_version", + "name": "rds_secret_version", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "secret_binary": null, + "secret_string": "{\"password\":\"admin1234\",\"username\":\"admin\"}" + }, + "after_unknown": { + "arn": true, + "id": true, + "secret_id": true, + "version_id": true, + "version_stages": true + }, + "before_sensitive": false, + "after_sensitive": { + "secret_binary": true, + "secret_string": true, + "version_stages": [] + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": ">= 5.32.0", + "expressions": { + "region": { + "constant_value": "us-west-2" + } + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_db_proxy.bad_db_proxy", + "mode": "managed", + "type": "aws_db_proxy", + "name": "bad_db_proxy", + "provider_config_key": "aws", + "expressions": { + "auth": [ + { + "auth_scheme": { + "constant_value": "SECRETS" + }, + "secret_arn": { + "references": [ + "aws_secretsmanager_secret.rds_secret.arn", + "aws_secretsmanager_secret.rds_secret" + ] + } + } + ], + "engine_family": { + "constant_value": "POSTGRESQL" + }, + "name": { + "constant_value": "bad-db-proxy-02" + }, + "role_arn": { + "constant_value": "arn:aws:iam::xxxx:role/aws-service-role/rds.amazonaws.com/AWSServiceRoleForRDS" + }, + "vpc_subnet_ids": { + "constant_value": [ + "subnet-0a3043a2ad9bd85a7", + "subnet-03c8d8c9fc4dc6c23" + ] + } + }, + "schema_version": 0 + }, + { + "address": "aws_secretsmanager_secret.rds_secret", + "mode": "managed", + "type": "aws_secretsmanager_secret", + "name": "rds_secret", + "provider_config_key": "aws", + "expressions": { + "name": { + "constant_value": "rds-db-secret" + }, + "tags": { + "constant_value": { + "Name": "rds-db-secret" + } + } + }, + "schema_version": 0 + }, + { + "address": "aws_secretsmanager_secret_version.rds_secret_version", + "mode": "managed", + "type": "aws_secretsmanager_secret_version", + "name": "rds_secret_version", + "provider_config_key": "aws", + "expressions": { + "secret_id": { + "references": [ + "aws_secretsmanager_secret.rds_secret.id", + "aws_secretsmanager_secret.rds_secret" + ] + }, + "secret_string": {} + }, + "schema_version": 0 + } + ] + } + }, + "relevant_attributes": [ + { + "resource": "aws_secretsmanager_secret.rds_secret", + "attribute": [ + "id" + ] + }, + { + "resource": "aws_secretsmanager_secret.rds_secret", + "attribute": [ + "arn" + ] + } + ], + "timestamp": "2024-10-01T08:03:48Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/rds-best-practices/check-rds-db-proxy-tls/test/binding.yaml b/terraform/plan/rds-best-practices/check-rds-db-proxy-tls/test/binding.yaml new file mode 100644 index 00000000..a3dd760d --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-db-proxy-tls/test/binding.yaml @@ -0,0 +1,3 @@ +analyzer: + resource: + type: terraform-plan \ No newline at end of file diff --git a/terraform/plan/rds-best-practices/check-rds-db-proxy-tls/test/chainsaw-test.yaml b/terraform/plan/rds-best-practices/check-rds-db-proxy-tls/test/chainsaw-test.yaml new file mode 100644 index 00000000..a9e6b8c3 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-db-proxy-tls/test/chainsaw-test.yaml @@ -0,0 +1,91 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/kyverno/chainsaw/main/.schemas/json/test-chainsaw-v1alpha1.json +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: good-test-01 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --payload ./good-test/good-payload-01.json --policy ../check-rds-db-proxy-tls.yaml --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-rds-db-proxy-tls + rules: + - rule: + name: check-rds-db-proxy-tls + error: ~ + violations: ~ +--- +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: bad-test-01 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --payload ./bad-test/bad-payload-01.json --policy ../check-rds-db-proxy-tls.yaml --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-rds-db-proxy-tls + rules: + - rule: + name: check-rds-db-proxy-tls + error: ~ + violations: + - message: RDS Database Proxy should use TLS (CHECK=spec.rules[0].assert.all[0]) + errors: + - type: FieldValueInvalid + value: false + detail: "Expected value: true" +--- +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: bad-test-02 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --payload ./bad-test/bad-payload-02.json --policy ../check-rds-db-proxy-tls.yaml --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-rds-db-proxy-tls + rules: + - rule: + name: check-rds-db-proxy-tls + error: ~ + violations: + - message: RDS Database Proxy should use TLS (CHECK=spec.rules[0].assert.all[0]) + errors: + - type: FieldValueInvalid + value: false + detail: "Expected value: true" \ No newline at end of file diff --git a/terraform/plan/rds-best-practices/check-rds-db-proxy-tls/test/good-test/good-01.tf b/terraform/plan/rds-best-practices/check-rds-db-proxy-tls/test/good-test/good-01.tf new file mode 100644 index 00000000..35a2c3a4 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-db-proxy-tls/test/good-test/good-01.tf @@ -0,0 +1,43 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_secretsmanager_secret" "rds_secret" { + name = "rds-db-secret" + + tags = { + Name = "rds-db-secret" + } +} + +resource "aws_secretsmanager_secret_version" "rds_secret_version" { + secret_id = aws_secretsmanager_secret.rds_secret.id + secret_string = jsonencode({ + username = "admin" + password = "admin1234" + }) +} + +resource "aws_db_proxy" "good_db_proxy" { + name = "good-db-proxy-01" + engine_family = "POSTGRESQL" + role_arn = "arn:aws:iam::xxxx:role/aws-service-role/rds.amazonaws.com/AWSServiceRoleForRDS" + vpc_subnet_ids = ["subnet-id-1", "subnet-id-2"] + require_tls = true + + auth { + auth_scheme = "SECRETS" + secret_arn = aws_secretsmanager_secret.rds_secret.arn + } +} diff --git a/terraform/plan/rds-best-practices/check-rds-db-proxy-tls/test/good-test/good-payload-01.json b/terraform/plan/rds-best-practices/check-rds-db-proxy-tls/test/good-test/good-payload-01.json new file mode 100644 index 00000000..535db5bf --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-db-proxy-tls/test/good-test/good-payload-01.json @@ -0,0 +1,342 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_db_proxy.good_db_proxy", + "mode": "managed", + "type": "aws_db_proxy", + "name": "good_db_proxy", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 0, + "values": { + "auth": [ + { + "auth_scheme": "SECRETS", + "description": "", + "iam_auth": "", + "username": "" + } + ], + "debug_logging": null, + "engine_family": "POSTGRESQL", + "name": "good-db-proxy-01", + "require_tls": true, + "role_arn": "arn:aws:iam::xxxx:role/aws-service-role/rds.amazonaws.com/AWSServiceRoleForRDS", + "tags": null, + "timeouts": null, + "vpc_subnet_ids": [ + "subnet-id-1", + "subnet-id-2" + ] + }, + "sensitive_values": { + "auth": [ + {} + ], + "tags_all": {}, + "vpc_security_group_ids": [], + "vpc_subnet_ids": [ + false, + false + ] + } + }, + { + "address": "aws_secretsmanager_secret.rds_secret", + "mode": "managed", + "type": "aws_secretsmanager_secret", + "name": "rds_secret", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 0, + "values": { + "description": null, + "force_overwrite_replica_secret": false, + "kms_key_id": null, + "name": "rds-db-secret", + "recovery_window_in_days": 30, + "tags": { + "Name": "rds-db-secret" + }, + "tags_all": { + "Name": "rds-db-secret" + } + }, + "sensitive_values": { + "replica": [], + "tags": {}, + "tags_all": {} + } + }, + { + "address": "aws_secretsmanager_secret_version.rds_secret_version", + "mode": "managed", + "type": "aws_secretsmanager_secret_version", + "name": "rds_secret_version", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 0, + "values": { + "secret_binary": null, + "secret_string": "{\"password\":\"admin1234\",\"username\":\"admin\"}" + }, + "sensitive_values": { + "secret_binary": true, + "secret_string": true, + "version_stages": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_db_proxy.good_db_proxy", + "mode": "managed", + "type": "aws_db_proxy", + "name": "good_db_proxy", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "auth": [ + { + "auth_scheme": "SECRETS", + "description": "", + "iam_auth": "", + "username": "" + } + ], + "debug_logging": null, + "engine_family": "POSTGRESQL", + "name": "good-db-proxy-01", + "require_tls": true, + "role_arn": "arn:aws:iam::xxxx:role/aws-service-role/rds.amazonaws.com/AWSServiceRoleForRDS", + "tags": null, + "timeouts": null, + "vpc_subnet_ids": [ + "subnet-id-1", + "subnet-id-2" + ] + }, + "after_unknown": { + "arn": true, + "auth": [ + { + "client_password_auth_type": true, + "secret_arn": true + } + ], + "endpoint": true, + "id": true, + "idle_client_timeout": true, + "tags_all": true, + "vpc_security_group_ids": true, + "vpc_subnet_ids": [ + false, + false + ] + }, + "before_sensitive": false, + "after_sensitive": { + "auth": [ + {} + ], + "tags_all": {}, + "vpc_security_group_ids": [], + "vpc_subnet_ids": [ + false, + false + ] + } + } + }, + { + "address": "aws_secretsmanager_secret.rds_secret", + "mode": "managed", + "type": "aws_secretsmanager_secret", + "name": "rds_secret", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "description": null, + "force_overwrite_replica_secret": false, + "kms_key_id": null, + "name": "rds-db-secret", + "recovery_window_in_days": 30, + "tags": { + "Name": "rds-db-secret" + }, + "tags_all": { + "Name": "rds-db-secret" + } + }, + "after_unknown": { + "arn": true, + "id": true, + "name_prefix": true, + "policy": true, + "replica": true, + "tags": {}, + "tags_all": {} + }, + "before_sensitive": false, + "after_sensitive": { + "replica": [], + "tags": {}, + "tags_all": {} + } + } + }, + { + "address": "aws_secretsmanager_secret_version.rds_secret_version", + "mode": "managed", + "type": "aws_secretsmanager_secret_version", + "name": "rds_secret_version", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "secret_binary": null, + "secret_string": "{\"password\":\"admin1234\",\"username\":\"admin\"}" + }, + "after_unknown": { + "arn": true, + "id": true, + "secret_id": true, + "version_id": true, + "version_stages": true + }, + "before_sensitive": false, + "after_sensitive": { + "secret_binary": true, + "secret_string": true, + "version_stages": [] + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": ">= 5.32.0", + "expressions": { + "region": { + "constant_value": "us-west-2" + } + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_db_proxy.good_db_proxy", + "mode": "managed", + "type": "aws_db_proxy", + "name": "good_db_proxy", + "provider_config_key": "aws", + "expressions": { + "auth": [ + { + "auth_scheme": { + "constant_value": "SECRETS" + }, + "secret_arn": { + "references": [ + "aws_secretsmanager_secret.rds_secret.arn", + "aws_secretsmanager_secret.rds_secret" + ] + } + } + ], + "engine_family": { + "constant_value": "POSTGRESQL" + }, + "name": { + "constant_value": "good-db-proxy-01" + }, + "require_tls": { + "constant_value": true + }, + "role_arn": { + "constant_value": "arn:aws:iam::xxxx:role/aws-service-role/rds.amazonaws.com/AWSServiceRoleForRDS" + }, + "vpc_subnet_ids": { + "constant_value": [ + "subnet-id-1", + "subnet-id-2" + ] + } + }, + "schema_version": 0 + }, + { + "address": "aws_secretsmanager_secret.rds_secret", + "mode": "managed", + "type": "aws_secretsmanager_secret", + "name": "rds_secret", + "provider_config_key": "aws", + "expressions": { + "name": { + "constant_value": "rds-db-secret" + }, + "tags": { + "constant_value": { + "Name": "rds-db-secret" + } + } + }, + "schema_version": 0 + }, + { + "address": "aws_secretsmanager_secret_version.rds_secret_version", + "mode": "managed", + "type": "aws_secretsmanager_secret_version", + "name": "rds_secret_version", + "provider_config_key": "aws", + "expressions": { + "secret_id": { + "references": [ + "aws_secretsmanager_secret.rds_secret.id", + "aws_secretsmanager_secret.rds_secret" + ] + }, + "secret_string": {} + }, + "schema_version": 0 + } + ] + } + }, + "relevant_attributes": [ + { + "resource": "aws_secretsmanager_secret.rds_secret", + "attribute": [ + "id" + ] + }, + { + "resource": "aws_secretsmanager_secret.rds_secret", + "attribute": [ + "arn" + ] + } + ], + "timestamp": "2024-10-01T07:44:38Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/rds-best-practices/check-rds-instance-copy-tags-to-snapshots-enabled/README.md b/terraform/plan/rds-best-practices/check-rds-instance-copy-tags-to-snapshots-enabled/README.md new file mode 100644 index 00000000..da163770 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-instance-copy-tags-to-snapshots-enabled/README.md @@ -0,0 +1,78 @@ +# Check RDS Instance Copy Tags To Snapshots Enabled + +This policy checks whether RDS DB instances are configured to copy all tags to snapshots when the snapshots are created. +Identification and inventory of your IT assets is a crucial aspect of governance and security. +You need to have visibility of all your RDS DB instances so that you can assess their security posture and take action on +potential areas of weakness. Snapshots should be tagged in the same way as their parent RDS database instances. +Enabling this setting ensures that snapshots inherit the tags of their parent database instances. +Read more about it [here](https://docs.aws.amazon.com/securityhub/latest/userguide/rds-controls.html#rds-17) + +## Policy Details: + +- **Policy Name:** check-rds-instance-copy-tags-to-snapshots-enabled +- **Check Description:** This policy checks if RDS DB instances are configured to copy tags to snapshots +- **Policy Category:** AWS RDS Best Practices + +### Policy Validation Testing Instructions + +For testing this policy you will need to: +- Make sure you have `kyverno-json` installed on the machine +- Properly authenticate with AWS + +1. **Initialize Terraform:** + ```bash + terraform init + ``` + +2. **Create Binary Terraform Plan:** + ```bash + terraform plan -out tfplan.binary + ``` + +3. **Convert Binary to JSON Payload:** + ```bash + terraform show -json tfplan.binary | jq > payload.json + ``` + +4. **Test the Policy with Kyverno:** + ```bash + kyverno-json scan --payload payload.json --policy policy.yaml + ``` + + a. **Test Policy Against Valid Payload:** + ```bash + kyverno-json scan --payload test/good-test/good-payload-01.json --policy check-rds-instance-copy-tags-to-snapshots-enabled.yaml --bindings test/binding.yaml + ``` + + This produces the output: + ```bash + Loading policies ... + Loading bindings ... + - analyzer -> map[resource:map[type:terraform-plan]] + Loading payload ... + Pre processing ... + Running ( evaluating 1 resource against 1 policy ) ... + - PASSED (POLICY=check-rds-instance-copy-tags-to-snapshots-enabled, RULE=check-rds-instance-copy-tags-to-snapshots-enabled) + Done + ``` + + b. **Test Against Invalid Payload:** + ``` + kyverno-json scan --payload test/bad-test/bad-payload-01.json --policy check-rds-instance-copy-tags-to-snapshots-enabled.yaml --bindings test/binding.yaml + ``` + + This produces the output: + ```bash + Loading policies ... + Loading bindings ... + - analyzer -> map[resource:map[type:terraform-plan]] + Loading payload ... + Pre processing ... + Running ( evaluating 1 resource against 1 policy ) ... + - FAILED (POLICY=check-rds-instance-copy-tags-to-snapshots-enabled, RULE=check-rds-instance-copy-tags-to-snapshots-enabled) + -> RDS DB instances should be configured to copy tags to snapshots (CHECK=spec.rules[0].assert.all[0]) + -> Invalid value: false: Expected value: true (PATH=~.(planned_values.root_module.resources[?type=='aws_db_instance'])[0].values.copy_tags_to_snapshot) + Done + ``` + +--- \ No newline at end of file diff --git a/terraform/plan/rds-best-practices/check-rds-instance-copy-tags-to-snapshots-enabled/check-rds-instance-copy-tags-to-snapshots-enabled.yaml b/terraform/plan/rds-best-practices/check-rds-instance-copy-tags-to-snapshots-enabled/check-rds-instance-copy-tags-to-snapshots-enabled.yaml new file mode 100644 index 00000000..af96b5b9 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-instance-copy-tags-to-snapshots-enabled/check-rds-instance-copy-tags-to-snapshots-enabled.yaml @@ -0,0 +1,28 @@ +apiVersion: json.kyverno.io/v1alpha1 +kind: ValidatingPolicy +metadata: + name: check-rds-instance-copy-tags-to-snapshots-enabled + annotations: + policies.kyverno.io/title: Check RDS Instance Copy Tags To Snapshots Enabled + policies.kyverno.io/category: AWS RDS Best Practices + policies.kyverno.io/severity: low + policies.kyverno.io/description: >- + This policy checks whether RDS DB instances are configured to copy all tags to snapshots when the snapshots are created. + Identification and inventory of your IT assets is a crucial aspect of governance and security. + You need to have visibility of all your RDS DB instances so that you can assess their security posture and take action on + potential areas of weakness. Snapshots should be tagged in the same way as their parent RDS database instances. + Enabling this setting ensures that snapshots inherit the tags of their parent database instances. +spec: + rules: + - name: check-rds-instance-copy-tags-to-snapshots-enabled + match: + all: + - ($analyzer.resource.type): terraform-plan + - (planned_values.root_module.resources[?type=='aws_db_instance'] || `[]` | length(@) > `0`): true + assert: + all: + - message: RDS DB instances should be configured to copy tags to snapshots + check: + ~.(planned_values.root_module.resources[?type=='aws_db_instance']): + values: + copy_tags_to_snapshot: true \ No newline at end of file diff --git a/terraform/plan/rds-best-practices/check-rds-instance-copy-tags-to-snapshots-enabled/test/bad-test/bad-01.tf b/terraform/plan/rds-best-practices/check-rds-instance-copy-tags-to-snapshots-enabled/test/bad-test/bad-01.tf new file mode 100644 index 00000000..d86ab723 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-instance-copy-tags-to-snapshots-enabled/test/bad-test/bad-01.tf @@ -0,0 +1,25 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_db_instance" "bad_mysql_instance" { + identifier = "bad-mysql-instance-01" + instance_class = "db.t3.micro" + engine = "mysql" + username = "admin" + password = "secret99" + allocated_storage = 5 + skip_final_snapshot = true + copy_tags_to_snapshot = false +} diff --git a/terraform/plan/rds-best-practices/check-rds-instance-copy-tags-to-snapshots-enabled/test/bad-test/bad-02.tf b/terraform/plan/rds-best-practices/check-rds-instance-copy-tags-to-snapshots-enabled/test/bad-test/bad-02.tf new file mode 100644 index 00000000..f7c1209a --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-instance-copy-tags-to-snapshots-enabled/test/bad-test/bad-02.tf @@ -0,0 +1,26 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_db_instance" "bad_mysql_instance" { + identifier = "bad-mysql-instance-02" + instance_class = "db.t3.micro" + engine = "mysql" + username = "admin" + password = "secret99" + allocated_storage = 5 + skip_final_snapshot = true + # copy_tags_to_snapshot defaults to false + # copy_tags_to_snapshot = false +} diff --git a/terraform/plan/rds-best-practices/check-rds-instance-copy-tags-to-snapshots-enabled/test/bad-test/bad-payload-01.json b/terraform/plan/rds-best-practices/check-rds-instance-copy-tags-to-snapshots-enabled/test/bad-test/bad-payload-01.json new file mode 100644 index 00000000..9cc481f2 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-instance-copy-tags-to-snapshots-enabled/test/bad-test/bad-payload-01.json @@ -0,0 +1,240 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_db_instance.bad_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "bad_mysql_instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 2, + "values": { + "allocated_storage": 5, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "identifier": "bad-mysql-instance-01", + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "secret99", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "admin" + }, + "sensitive_values": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_db_instance.bad_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "bad_mysql_instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "allocated_storage": 5, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "identifier": "bad-mysql-instance-01", + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "secret99", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "admin" + }, + "after_unknown": { + "address": true, + "arn": true, + "availability_zone": true, + "backup_retention_period": true, + "backup_target": true, + "backup_window": true, + "blue_green_update": [], + "ca_cert_identifier": true, + "character_set_name": true, + "db_name": true, + "db_subnet_group_name": true, + "domain_fqdn": true, + "endpoint": true, + "engine_lifecycle_support": true, + "engine_version": true, + "engine_version_actual": true, + "hosted_zone_id": true, + "id": true, + "identifier_prefix": true, + "iops": true, + "kms_key_id": true, + "latest_restorable_time": true, + "license_model": true, + "listener_endpoint": true, + "maintenance_window": true, + "master_user_secret": true, + "master_user_secret_kms_key_id": true, + "monitoring_role_arn": true, + "multi_az": true, + "nchar_character_set_name": true, + "network_type": true, + "option_group_name": true, + "parameter_group_name": true, + "performance_insights_kms_key_id": true, + "performance_insights_retention_period": true, + "port": true, + "replica_mode": true, + "replicas": true, + "resource_id": true, + "restore_to_point_in_time": [], + "s3_import": [], + "snapshot_identifier": true, + "status": true, + "storage_throughput": true, + "storage_type": true, + "tags_all": true, + "timezone": true, + "vpc_security_group_ids": true + }, + "before_sensitive": false, + "after_sensitive": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": ">= 5.32.0", + "expressions": { + "region": { + "constant_value": "us-west-2" + } + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_db_instance.bad_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "bad_mysql_instance", + "provider_config_key": "aws", + "expressions": { + "allocated_storage": { + "constant_value": 5 + }, + "copy_tags_to_snapshot": { + "constant_value": false + }, + "engine": { + "constant_value": "mysql" + }, + "identifier": { + "constant_value": "bad-mysql-instance-01" + }, + "instance_class": { + "constant_value": "db.t3.micro" + }, + "password": { + "constant_value": "secret99" + }, + "skip_final_snapshot": { + "constant_value": true + }, + "username": { + "constant_value": "admin" + } + }, + "schema_version": 2 + } + ] + } + }, + "timestamp": "2024-10-01T11:10:14Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/rds-best-practices/check-rds-instance-copy-tags-to-snapshots-enabled/test/bad-test/bad-payload-02.json b/terraform/plan/rds-best-practices/check-rds-instance-copy-tags-to-snapshots-enabled/test/bad-test/bad-payload-02.json new file mode 100644 index 00000000..5610098c --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-instance-copy-tags-to-snapshots-enabled/test/bad-test/bad-payload-02.json @@ -0,0 +1,237 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_db_instance.bad_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "bad_mysql_instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 2, + "values": { + "allocated_storage": 5, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "identifier": "bad-mysql-instance-02", + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "secret99", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "admin" + }, + "sensitive_values": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_db_instance.bad_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "bad_mysql_instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "allocated_storage": 5, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "identifier": "bad-mysql-instance-02", + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "secret99", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "admin" + }, + "after_unknown": { + "address": true, + "arn": true, + "availability_zone": true, + "backup_retention_period": true, + "backup_target": true, + "backup_window": true, + "blue_green_update": [], + "ca_cert_identifier": true, + "character_set_name": true, + "db_name": true, + "db_subnet_group_name": true, + "domain_fqdn": true, + "endpoint": true, + "engine_lifecycle_support": true, + "engine_version": true, + "engine_version_actual": true, + "hosted_zone_id": true, + "id": true, + "identifier_prefix": true, + "iops": true, + "kms_key_id": true, + "latest_restorable_time": true, + "license_model": true, + "listener_endpoint": true, + "maintenance_window": true, + "master_user_secret": true, + "master_user_secret_kms_key_id": true, + "monitoring_role_arn": true, + "multi_az": true, + "nchar_character_set_name": true, + "network_type": true, + "option_group_name": true, + "parameter_group_name": true, + "performance_insights_kms_key_id": true, + "performance_insights_retention_period": true, + "port": true, + "replica_mode": true, + "replicas": true, + "resource_id": true, + "restore_to_point_in_time": [], + "s3_import": [], + "snapshot_identifier": true, + "status": true, + "storage_throughput": true, + "storage_type": true, + "tags_all": true, + "timezone": true, + "vpc_security_group_ids": true + }, + "before_sensitive": false, + "after_sensitive": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": ">= 5.32.0", + "expressions": { + "region": { + "constant_value": "us-west-2" + } + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_db_instance.bad_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "bad_mysql_instance", + "provider_config_key": "aws", + "expressions": { + "allocated_storage": { + "constant_value": 5 + }, + "engine": { + "constant_value": "mysql" + }, + "identifier": { + "constant_value": "bad-mysql-instance-02" + }, + "instance_class": { + "constant_value": "db.t3.micro" + }, + "password": { + "constant_value": "secret99" + }, + "skip_final_snapshot": { + "constant_value": true + }, + "username": { + "constant_value": "admin" + } + }, + "schema_version": 2 + } + ] + } + }, + "timestamp": "2024-10-01T11:10:35Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/rds-best-practices/check-rds-instance-copy-tags-to-snapshots-enabled/test/binding.yaml b/terraform/plan/rds-best-practices/check-rds-instance-copy-tags-to-snapshots-enabled/test/binding.yaml new file mode 100644 index 00000000..a3dd760d --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-instance-copy-tags-to-snapshots-enabled/test/binding.yaml @@ -0,0 +1,3 @@ +analyzer: + resource: + type: terraform-plan \ No newline at end of file diff --git a/terraform/plan/rds-best-practices/check-rds-instance-copy-tags-to-snapshots-enabled/test/chainsaw-test.yaml b/terraform/plan/rds-best-practices/check-rds-instance-copy-tags-to-snapshots-enabled/test/chainsaw-test.yaml new file mode 100644 index 00000000..ec44cd12 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-instance-copy-tags-to-snapshots-enabled/test/chainsaw-test.yaml @@ -0,0 +1,92 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/kyverno/chainsaw/main/.schemas/json/test-chainsaw-v1alpha1.json +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: good-test-01 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --payload ./good-test/good-payload-01.json --policy ../check-rds-instance-copy-tags-to-snapshots-enabled.yaml --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-rds-instance-copy-tags-to-snapshots-enabled + rules: + - rule: + name: check-rds-instance-copy-tags-to-snapshots-enabled + error: ~ + violations: ~ +--- +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: bad-test-01 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --payload ./bad-test/bad-payload-01.json --policy ../check-rds-instance-copy-tags-to-snapshots-enabled.yaml --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-rds-instance-copy-tags-to-snapshots-enabled + rules: + - rule: + name: check-rds-instance-copy-tags-to-snapshots-enabled + error: ~ + violations: + - message: RDS DB instances should be configured to copy tags to snapshots (CHECK=spec.rules[0].assert.all[0]) + errors: + - type: FieldValueInvalid + value: false + detail: "Expected value: true" +--- +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: bad-test-02 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --payload ./bad-test/bad-payload-02.json --policy ../check-rds-instance-copy-tags-to-snapshots-enabled.yaml --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-rds-instance-copy-tags-to-snapshots-enabled + rules: + - rule: + name: check-rds-instance-copy-tags-to-snapshots-enabled + error: ~ + violations: + - message: RDS DB instances should be configured to copy tags to snapshots (CHECK=spec.rules[0].assert.all[0]) + errors: + - type: FieldValueInvalid + value: false + detail: "Expected value: true" + diff --git a/terraform/plan/rds-best-practices/check-rds-instance-copy-tags-to-snapshots-enabled/test/good-test/good-01.tf b/terraform/plan/rds-best-practices/check-rds-instance-copy-tags-to-snapshots-enabled/test/good-test/good-01.tf new file mode 100644 index 00000000..474f8e0b --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-instance-copy-tags-to-snapshots-enabled/test/good-test/good-01.tf @@ -0,0 +1,25 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_db_instance" "good_mysql_instance" { + identifier = "good-mysql-instance-01" + instance_class = "db.t3.micro" + engine = "mysql" + username = "admin" + password = "secret99" + allocated_storage = 5 + skip_final_snapshot = true + copy_tags_to_snapshot = true +} diff --git a/terraform/plan/rds-best-practices/check-rds-instance-copy-tags-to-snapshots-enabled/test/good-test/good-payload-01.json b/terraform/plan/rds-best-practices/check-rds-instance-copy-tags-to-snapshots-enabled/test/good-test/good-payload-01.json new file mode 100644 index 00000000..ffd793b5 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-instance-copy-tags-to-snapshots-enabled/test/good-test/good-payload-01.json @@ -0,0 +1,240 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_db_instance.good_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "good_mysql_instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 2, + "values": { + "allocated_storage": 5, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": true, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "identifier": "good-mysql-instance-01", + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "secret99", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "admin" + }, + "sensitive_values": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_db_instance.good_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "good_mysql_instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "allocated_storage": 5, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": true, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "identifier": "good-mysql-instance-01", + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "secret99", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "admin" + }, + "after_unknown": { + "address": true, + "arn": true, + "availability_zone": true, + "backup_retention_period": true, + "backup_target": true, + "backup_window": true, + "blue_green_update": [], + "ca_cert_identifier": true, + "character_set_name": true, + "db_name": true, + "db_subnet_group_name": true, + "domain_fqdn": true, + "endpoint": true, + "engine_lifecycle_support": true, + "engine_version": true, + "engine_version_actual": true, + "hosted_zone_id": true, + "id": true, + "identifier_prefix": true, + "iops": true, + "kms_key_id": true, + "latest_restorable_time": true, + "license_model": true, + "listener_endpoint": true, + "maintenance_window": true, + "master_user_secret": true, + "master_user_secret_kms_key_id": true, + "monitoring_role_arn": true, + "multi_az": true, + "nchar_character_set_name": true, + "network_type": true, + "option_group_name": true, + "parameter_group_name": true, + "performance_insights_kms_key_id": true, + "performance_insights_retention_period": true, + "port": true, + "replica_mode": true, + "replicas": true, + "resource_id": true, + "restore_to_point_in_time": [], + "s3_import": [], + "snapshot_identifier": true, + "status": true, + "storage_throughput": true, + "storage_type": true, + "tags_all": true, + "timezone": true, + "vpc_security_group_ids": true + }, + "before_sensitive": false, + "after_sensitive": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": ">= 5.32.0", + "expressions": { + "region": { + "constant_value": "us-west-2" + } + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_db_instance.good_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "good_mysql_instance", + "provider_config_key": "aws", + "expressions": { + "allocated_storage": { + "constant_value": 5 + }, + "copy_tags_to_snapshot": { + "constant_value": true + }, + "engine": { + "constant_value": "mysql" + }, + "identifier": { + "constant_value": "good-mysql-instance-01" + }, + "instance_class": { + "constant_value": "db.t3.micro" + }, + "password": { + "constant_value": "secret99" + }, + "skip_final_snapshot": { + "constant_value": true + }, + "username": { + "constant_value": "admin" + } + }, + "schema_version": 2 + } + ] + } + }, + "timestamp": "2024-10-01T11:08:35Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/rds-best-practices/check-rds-instance-public-access/README.md b/terraform/plan/rds-best-practices/check-rds-instance-public-access/README.md new file mode 100644 index 00000000..02925a92 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-instance-public-access/README.md @@ -0,0 +1,75 @@ +# Check RDS Instance Public Access + +The `PubliclyAccessible` value in the RDS instance configuration indicates whether the DB instance is publicly accessible. When the DB instance is configured with `PubliclyAccessible`, it is an Internet-facing instance with a publicly resolvable DNS name, which resolves to a public IP address. When the DB instance isn't publicly accessible, it is an internal instance with a DNS name that resolves to a private IP address. + +Unless you intend for your RDS instance to be publicly accessible, the RDS instance should not be configured with `PubliclyAccessible` value. Doing so might allow unnecessary traffic to your database instance. You can read about it [here](https://docs.aws.amazon.com/securityhub/latest/userguide/rds-controls.html#rds-2) + +## Policy Details: + +- **Policy Name:** check-rds-instance-public-access +- **Check Description:** This policy ensures that RDS instances are not publicly accessible +- **Policy Category:** AWS RDS Best Practices + +### Policy Validation Testing Instructions + +For testing this policy you will need to: +- Make sure you have `kyverno-json` installed on the machine +- Properly authenticate with AWS + +1. **Initialize Terraform:** + ```bash + terraform init + ``` + +2. **Create Binary Terraform Plan:** + ```bash + terraform plan -out tfplan.binary + ``` + +3. **Convert Binary to JSON Payload:** + ```bash + terraform show -json tfplan.binary | jq > payload.json + ``` + +4. **Test the Policy with Kyverno:** + ```bash + kyverno-json scan --payload payload.json --policy policy.yaml + ``` + + a. **Test Policy Against Valid Payload:** + ```bash + kyverno-json scan --payload test/good-test/good-payload-01.json --policy check-rds-instance-public-access.yaml --bindings test/binding.yaml + ``` + + This produces the output: + ```bash + Loading policies ... + Loading bindings ... + - analyzer -> map[resource:map[type:terraform-plan]] + Loading payload ... + Pre processing ... + Running ( evaluating 1 resource against 1 policy ) ... + - PASSED (POLICY=check-rds-instance-public-access, RULE=check-rds-instance-public-access) + Done + ``` + + b. **Test Against Invalid Payload:** + ``` + kyverno-json scan --payload test/bad-test/bad-payload-01.json --policy check-rds-instance-public-access.yaml --bindings test/binding.yaml + ``` + + This produces the output: + ```bash + Loading policies ... + Loading bindings ... + - analyzer -> map[resource:map[type:terraform-plan]] + Loading payload ... + Pre processing ... + Running ( evaluating 1 resource against 1 policy ) ... + - FAILED (POLICY=check-rds-instance-public-access, RULE=check-rds-instance-public-access) + -> RDS Database Instance should not be publicly accessible (CHECK=spec.rules[0].assert.all[0]) + -> Invalid value: true: Expected value: false (PATH=~.(planned_values.root_module.resources[?type=='aws_db_instance'])[0].values.publicly_accessible) + Done + ``` + +--- \ No newline at end of file diff --git a/terraform/plan/rds-best-practices/check-rds-instance-public-access/check-rds-instance-public-access.yaml b/terraform/plan/rds-best-practices/check-rds-instance-public-access/check-rds-instance-public-access.yaml new file mode 100644 index 00000000..922f758b --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-instance-public-access/check-rds-instance-public-access.yaml @@ -0,0 +1,28 @@ +apiVersion: json.kyverno.io/v1alpha1 +kind: ValidatingPolicy +metadata: + name: check-rds-instance-public-access + annotations: + policies.kyverno.io/title: Check RDS Instance Public Access + policies.kyverno.io/category: AWS RDS Best Practices + policies.kyverno.io/severity: medium + policies.kyverno.io/description: >- + The `PubliclyAccessible` value in the RDS instance configuration indicates whether the DB instance is publicly accessible. + When the DB instance is configured with `PubliclyAccessible`, it is an Internet-facing instance with a publicly resolvable DNS name, + which resolves to a public IP address. When the DB instance isn't publicly accessible, it is an internal instance with a DNS name + that resolves to a private IP address. Unless you intend for your RDS instance to be publicly accessible, the RDS instance + should not be configured with `PubliclyAccessible` value. Doing so might allow unnecessary traffic to your database instance. +spec: + rules: + - name: check-rds-instance-public-access + match: + all: + - ($analyzer.resource.type): terraform-plan + - (planned_values.root_module.resources[?type=='aws_db_instance'] || `[]` | length(@) > `0`): true + assert: + all: + - message: RDS Database Instance should not be publicly accessible + check: + ~.(planned_values.root_module.resources[?type=='aws_db_instance']): + values: + publicly_accessible: false diff --git a/terraform/plan/rds-best-practices/check-rds-instance-public-access/test/bad-test/bad-01.tf b/terraform/plan/rds-best-practices/check-rds-instance-public-access/test/bad-test/bad-01.tf new file mode 100644 index 00000000..b450e97d --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-instance-public-access/test/bad-test/bad-01.tf @@ -0,0 +1,26 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_db_instance" "bad-db-instance" { + allocated_storage = 10 + engine = "mysql" + engine_version = "8.0" + instance_class = "db.t3.micro" + db_name = "mydb" + username = "username" + password = "password" + publicly_accessible = true + skip_final_snapshot = true +} diff --git a/terraform/plan/rds-best-practices/check-rds-instance-public-access/test/bad-test/bad-payload-01.json b/terraform/plan/rds-best-practices/check-rds-instance-public-access/test/bad-test/bad-payload-01.json new file mode 100644 index 00000000..01382aeb --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-instance-public-access/test/bad-test/bad-payload-01.json @@ -0,0 +1,244 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_db_instance.bad-db-instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "bad-db-instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 2, + "values": { + "allocated_storage": 10, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "db_name": "mydb", + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "engine_version": "8.0", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "password", + "performance_insights_enabled": false, + "publicly_accessible": true, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "username" + }, + "sensitive_values": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_db_instance.bad-db-instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "bad-db-instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "allocated_storage": 10, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "db_name": "mydb", + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "engine_version": "8.0", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "password", + "performance_insights_enabled": false, + "publicly_accessible": true, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "username" + }, + "after_unknown": { + "address": true, + "arn": true, + "availability_zone": true, + "backup_retention_period": true, + "backup_target": true, + "backup_window": true, + "blue_green_update": [], + "ca_cert_identifier": true, + "character_set_name": true, + "db_subnet_group_name": true, + "domain_fqdn": true, + "endpoint": true, + "engine_lifecycle_support": true, + "engine_version_actual": true, + "hosted_zone_id": true, + "id": true, + "identifier": true, + "identifier_prefix": true, + "iops": true, + "kms_key_id": true, + "latest_restorable_time": true, + "license_model": true, + "listener_endpoint": true, + "maintenance_window": true, + "master_user_secret": true, + "master_user_secret_kms_key_id": true, + "monitoring_role_arn": true, + "multi_az": true, + "nchar_character_set_name": true, + "network_type": true, + "option_group_name": true, + "parameter_group_name": true, + "performance_insights_kms_key_id": true, + "performance_insights_retention_period": true, + "port": true, + "replica_mode": true, + "replicas": true, + "resource_id": true, + "restore_to_point_in_time": [], + "s3_import": [], + "snapshot_identifier": true, + "status": true, + "storage_throughput": true, + "storage_type": true, + "tags_all": true, + "timezone": true, + "vpc_security_group_ids": true + }, + "before_sensitive": false, + "after_sensitive": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": ">= 5.32.0", + "expressions": { + "region": { + "constant_value": "us-west-2" + } + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_db_instance.bad-db-instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "bad-db-instance", + "provider_config_key": "aws", + "expressions": { + "allocated_storage": { + "constant_value": 10 + }, + "db_name": { + "constant_value": "mydb" + }, + "engine": { + "constant_value": "mysql" + }, + "engine_version": { + "constant_value": "8.0" + }, + "instance_class": { + "constant_value": "db.t3.micro" + }, + "password": { + "constant_value": "password" + }, + "publicly_accessible": { + "constant_value": true + }, + "skip_final_snapshot": { + "constant_value": true + }, + "username": { + "constant_value": "username" + } + }, + "schema_version": 2 + } + ] + } + }, + "timestamp": "2024-10-01T05:24:15Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/rds-best-practices/check-rds-instance-public-access/test/binding.yaml b/terraform/plan/rds-best-practices/check-rds-instance-public-access/test/binding.yaml new file mode 100644 index 00000000..a3dd760d --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-instance-public-access/test/binding.yaml @@ -0,0 +1,3 @@ +analyzer: + resource: + type: terraform-plan \ No newline at end of file diff --git a/terraform/plan/rds-best-practices/check-rds-instance-public-access/test/chainsaw-test.yaml b/terraform/plan/rds-best-practices/check-rds-instance-public-access/test/chainsaw-test.yaml new file mode 100644 index 00000000..3c75ff93 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-instance-public-access/test/chainsaw-test.yaml @@ -0,0 +1,86 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/kyverno/chainsaw/main/.schemas/json/test-chainsaw-v1alpha1.json +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: good-test-01 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --payload ./good-test/good-payload-01.json --policy ../check-rds-instance-public-access.yaml --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-rds-instance-public-access + rules: + - rule: + name: check-rds-instance-public-access + error: ~ + violations: ~ +--- +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: good-test-02 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --payload ./good-test/good-payload-02.json --policy ../check-rds-instance-public-access.yaml --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-rds-instance-public-access + rules: + - rule: + name: check-rds-instance-public-access + error: ~ + violations: ~ +--- +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: bad-test-01 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --payload ./bad-test/bad-payload-01.json --policy ../check-rds-instance-public-access.yaml --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-rds-instance-public-access + rules: + - rule: + name: check-rds-instance-public-access + error: ~ + violations: + - message: RDS Database Instance should not be publicly accessible (CHECK=spec.rules[0].assert.all[0]) + errors: + - type: FieldValueInvalid + value: true + detail: "Expected value: false" \ No newline at end of file diff --git a/terraform/plan/rds-best-practices/check-rds-instance-public-access/test/good-test/good-01.tf b/terraform/plan/rds-best-practices/check-rds-instance-public-access/test/good-test/good-01.tf new file mode 100644 index 00000000..01276359 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-instance-public-access/test/good-test/good-01.tf @@ -0,0 +1,26 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_db_instance" "good-db-instance" { + allocated_storage = 10 + engine = "mysql" + engine_version = "8.0" + instance_class = "db.t3.micro" + db_name = "mydb" + username = "username" + password = "password" + publicly_accessible = false + skip_final_snapshot = true +} diff --git a/terraform/plan/rds-best-practices/check-rds-instance-public-access/test/good-test/good-02.tf b/terraform/plan/rds-best-practices/check-rds-instance-public-access/test/good-test/good-02.tf new file mode 100644 index 00000000..5b1d7268 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-instance-public-access/test/good-test/good-02.tf @@ -0,0 +1,27 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_db_instance" "good-db-instance" { + allocated_storage = 10 + engine = "mysql" + engine_version = "8.0" + instance_class = "db.t3.micro" + db_name = "mydb" + username = "username" + password = "password" + # publicly_accessible defaults to false + # publicly_accessible = false + skip_final_snapshot = true +} diff --git a/terraform/plan/rds-best-practices/check-rds-instance-public-access/test/good-test/good-payload-01.json b/terraform/plan/rds-best-practices/check-rds-instance-public-access/test/good-test/good-payload-01.json new file mode 100644 index 00000000..f43551fb --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-instance-public-access/test/good-test/good-payload-01.json @@ -0,0 +1,244 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_db_instance.good-db-instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "good-db-instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 2, + "values": { + "allocated_storage": 10, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "db_name": "mydb", + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "engine_version": "8.0", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "password", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "username" + }, + "sensitive_values": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_db_instance.good-db-instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "good-db-instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "allocated_storage": 10, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "db_name": "mydb", + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "engine_version": "8.0", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "password", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "username" + }, + "after_unknown": { + "address": true, + "arn": true, + "availability_zone": true, + "backup_retention_period": true, + "backup_target": true, + "backup_window": true, + "blue_green_update": [], + "ca_cert_identifier": true, + "character_set_name": true, + "db_subnet_group_name": true, + "domain_fqdn": true, + "endpoint": true, + "engine_lifecycle_support": true, + "engine_version_actual": true, + "hosted_zone_id": true, + "id": true, + "identifier": true, + "identifier_prefix": true, + "iops": true, + "kms_key_id": true, + "latest_restorable_time": true, + "license_model": true, + "listener_endpoint": true, + "maintenance_window": true, + "master_user_secret": true, + "master_user_secret_kms_key_id": true, + "monitoring_role_arn": true, + "multi_az": true, + "nchar_character_set_name": true, + "network_type": true, + "option_group_name": true, + "parameter_group_name": true, + "performance_insights_kms_key_id": true, + "performance_insights_retention_period": true, + "port": true, + "replica_mode": true, + "replicas": true, + "resource_id": true, + "restore_to_point_in_time": [], + "s3_import": [], + "snapshot_identifier": true, + "status": true, + "storage_throughput": true, + "storage_type": true, + "tags_all": true, + "timezone": true, + "vpc_security_group_ids": true + }, + "before_sensitive": false, + "after_sensitive": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": ">= 5.32.0", + "expressions": { + "region": { + "constant_value": "us-west-2" + } + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_db_instance.good-db-instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "good-db-instance", + "provider_config_key": "aws", + "expressions": { + "allocated_storage": { + "constant_value": 10 + }, + "db_name": { + "constant_value": "mydb" + }, + "engine": { + "constant_value": "mysql" + }, + "engine_version": { + "constant_value": "8.0" + }, + "instance_class": { + "constant_value": "db.t3.micro" + }, + "password": { + "constant_value": "password" + }, + "publicly_accessible": { + "constant_value": false + }, + "skip_final_snapshot": { + "constant_value": true + }, + "username": { + "constant_value": "username" + } + }, + "schema_version": 2 + } + ] + } + }, + "timestamp": "2024-10-01T05:26:46Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/rds-best-practices/check-rds-instance-public-access/test/good-test/good-payload-02.json b/terraform/plan/rds-best-practices/check-rds-instance-public-access/test/good-test/good-payload-02.json new file mode 100644 index 00000000..976d0cfa --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-instance-public-access/test/good-test/good-payload-02.json @@ -0,0 +1,241 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_db_instance.good-db-instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "good-db-instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 2, + "values": { + "allocated_storage": 10, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "db_name": "mydb", + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "engine_version": "8.0", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "password", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "username" + }, + "sensitive_values": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_db_instance.good-db-instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "good-db-instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "allocated_storage": 10, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "db_name": "mydb", + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "engine_version": "8.0", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "password", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "username" + }, + "after_unknown": { + "address": true, + "arn": true, + "availability_zone": true, + "backup_retention_period": true, + "backup_target": true, + "backup_window": true, + "blue_green_update": [], + "ca_cert_identifier": true, + "character_set_name": true, + "db_subnet_group_name": true, + "domain_fqdn": true, + "endpoint": true, + "engine_lifecycle_support": true, + "engine_version_actual": true, + "hosted_zone_id": true, + "id": true, + "identifier": true, + "identifier_prefix": true, + "iops": true, + "kms_key_id": true, + "latest_restorable_time": true, + "license_model": true, + "listener_endpoint": true, + "maintenance_window": true, + "master_user_secret": true, + "master_user_secret_kms_key_id": true, + "monitoring_role_arn": true, + "multi_az": true, + "nchar_character_set_name": true, + "network_type": true, + "option_group_name": true, + "parameter_group_name": true, + "performance_insights_kms_key_id": true, + "performance_insights_retention_period": true, + "port": true, + "replica_mode": true, + "replicas": true, + "resource_id": true, + "restore_to_point_in_time": [], + "s3_import": [], + "snapshot_identifier": true, + "status": true, + "storage_throughput": true, + "storage_type": true, + "tags_all": true, + "timezone": true, + "vpc_security_group_ids": true + }, + "before_sensitive": false, + "after_sensitive": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": ">= 5.32.0", + "expressions": { + "region": { + "constant_value": "us-west-2" + } + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_db_instance.good-db-instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "good-db-instance", + "provider_config_key": "aws", + "expressions": { + "allocated_storage": { + "constant_value": 10 + }, + "db_name": { + "constant_value": "mydb" + }, + "engine": { + "constant_value": "mysql" + }, + "engine_version": { + "constant_value": "8.0" + }, + "instance_class": { + "constant_value": "db.t3.micro" + }, + "password": { + "constant_value": "password" + }, + "skip_final_snapshot": { + "constant_value": true + }, + "username": { + "constant_value": "username" + } + }, + "schema_version": 2 + } + ] + } + }, + "timestamp": "2024-10-01T05:27:36Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/rds-best-practices/check-rds-multi-az-support/README.md b/terraform/plan/rds-best-practices/check-rds-multi-az-support/README.md new file mode 100644 index 00000000..245bcf0e --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-multi-az-support/README.md @@ -0,0 +1,77 @@ +# Check RDS Multi AZ Support + +This policy checks whether high availability is enabled for your RDS DB instances. +RDS DB instances should be configured for multiple Availability Zones (AZs). +This ensures the availability of the data stored. Multi-AZ deployments allow for automated failover +if there is an issue with AZ availability and during regular RDS maintenance. +You can read more about it [here](https://docs.aws.amazon.com/securityhub/latest/userguide/rds-controls.html#rds-5) + +## Policy Details: + +- **Policy Name:** check-rds-multi-az-support +- **Check Description:** This policy ensures that RDS DB instances have Multi AZ enabled +- **Policy Category:** AWS RDS Best Practices + +### Policy Validation Testing Instructions + +For testing this policy you will need to: +- Make sure you have `kyverno-json` installed on the machine +- Properly authenticate with AWS + +1. **Initialize Terraform:** + ```bash + terraform init + ``` + +2. **Create Binary Terraform Plan:** + ```bash + terraform plan -out tfplan.binary + ``` + +3. **Convert Binary to JSON Payload:** + ```bash + terraform show -json tfplan.binary | jq > payload.json + ``` + +4. **Test the Policy with Kyverno:** + ```bash + kyverno-json scan --payload payload.json --policy policy.yaml + ``` + + a. **Test Policy Against Valid Payload:** + ```bash + kyverno-json scan --payload test/good-test/good-payload-01.json --policy check-rds-multi-az-support.yaml --bindings test/binding.yaml + ``` + + This produces the output: + ```bash + Loading policies ... + Loading bindings ... + - analyzer -> map[resource:map[type:terraform-plan]] + Loading payload ... + Pre processing ... + Running ( evaluating 1 resource against 1 policy ) ... + - PASSED (POLICY=check-rds-multi-az-support, RULE=check-rds-multi-az-support) + Done + ``` + + b. **Test Against Invalid Payload:** + ``` + kyverno-json scan --payload test/bad-test/bad-payload-01.json --policy check-rds-multi-az-support.yaml --bindings test/binding.yaml + ``` + + This produces the output: + ```bash + Loading policies ... + Loading bindings ... + - analyzer -> map[resource:map[type:terraform-plan]] + Loading payload ... + Pre processing ... + Running ( evaluating 1 resource against 1 policy ) ... + - FAILED (POLICY=check-rds-multi-az-support, RULE=check-rds-multi-az-support) + -> RDS DB instances should be configured with multiple Availability Zones (CHECK=spec.rules[0].assert.all[0]) + -> Invalid value: false: Expected value: true (PATH=~.(planned_values.root_module.resources[?type=='aws_db_instance'])[0].values.(!!multi_az)) + Done + ``` + +--- \ No newline at end of file diff --git a/terraform/plan/rds-best-practices/check-rds-multi-az-support/check-rds-multi-az-support.yaml b/terraform/plan/rds-best-practices/check-rds-multi-az-support/check-rds-multi-az-support.yaml new file mode 100644 index 00000000..3602f44a --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-multi-az-support/check-rds-multi-az-support.yaml @@ -0,0 +1,27 @@ +apiVersion: json.kyverno.io/v1alpha1 +kind: ValidatingPolicy +metadata: + name: check-rds-multi-az-support + annotations: + policies.kyverno.io/title: Check RDS Multi AZ Support + policies.kyverno.io/category: AWS RDS Best Practices + policies.kyverno.io/severity: medium + policies.kyverno.io/description: >- + This policy checks whether high availability is enabled for your RDS DB instances. + RDS DB instances should be configured for multiple Availability Zones (AZs). + This ensures the availability of the data stored. Multi-AZ deployments allow for automated failover + if there is an issue with AZ availability and during regular RDS maintenance. +spec: + rules: + - name: check-rds-multi-az-support + match: + all: + - ($analyzer.resource.type): terraform-plan + - (planned_values.root_module.resources[?type=='aws_db_instance'] || `[]` | length(@) > `0`): true + assert: + all: + - message: RDS DB instances should be configured with multiple Availability Zones + check: + ~.(planned_values.root_module.resources[?type=='aws_db_instance']): + values: + (!!multi_az): true \ No newline at end of file diff --git a/terraform/plan/rds-best-practices/check-rds-multi-az-support/test/bad-test/bad-01.tf b/terraform/plan/rds-best-practices/check-rds-multi-az-support/test/bad-test/bad-01.tf new file mode 100644 index 00000000..ef53bfba --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-multi-az-support/test/bad-test/bad-01.tf @@ -0,0 +1,25 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_db_instance" "bad_mysql_instance" { + identifier = "bad-mysql-instance-01" + instance_class = "db.t3.micro" + engine = "mysql" + username = "admin" + password = "secret99" + allocated_storage = 5 + skip_final_snapshot = true + multi_az = false +} diff --git a/terraform/plan/rds-best-practices/check-rds-multi-az-support/test/bad-test/bad-02.tf b/terraform/plan/rds-best-practices/check-rds-multi-az-support/test/bad-test/bad-02.tf new file mode 100644 index 00000000..a7134d0f --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-multi-az-support/test/bad-test/bad-02.tf @@ -0,0 +1,24 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_db_instance" "bad_mysql_instance" { + identifier = "bad-mysql-instance-02" + instance_class = "db.t3.micro" + engine = "mysql" + username = "admin" + password = "secret99" + allocated_storage = 5 + skip_final_snapshot = true +} diff --git a/terraform/plan/rds-best-practices/check-rds-multi-az-support/test/bad-test/bad-payload-01.json b/terraform/plan/rds-best-practices/check-rds-multi-az-support/test/bad-test/bad-payload-01.json new file mode 100644 index 00000000..478a47c5 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-multi-az-support/test/bad-test/bad-payload-01.json @@ -0,0 +1,241 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_db_instance.bad_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "bad_mysql_instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 2, + "values": { + "allocated_storage": 5, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "identifier": "bad-mysql-instance-01", + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "multi_az": false, + "password": "secret99", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "admin" + }, + "sensitive_values": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_db_instance.bad_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "bad_mysql_instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "allocated_storage": 5, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "identifier": "bad-mysql-instance-01", + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "multi_az": false, + "password": "secret99", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "admin" + }, + "after_unknown": { + "address": true, + "arn": true, + "availability_zone": true, + "backup_retention_period": true, + "backup_target": true, + "backup_window": true, + "blue_green_update": [], + "ca_cert_identifier": true, + "character_set_name": true, + "db_name": true, + "db_subnet_group_name": true, + "domain_fqdn": true, + "endpoint": true, + "engine_lifecycle_support": true, + "engine_version": true, + "engine_version_actual": true, + "hosted_zone_id": true, + "id": true, + "identifier_prefix": true, + "iops": true, + "kms_key_id": true, + "latest_restorable_time": true, + "license_model": true, + "listener_endpoint": true, + "maintenance_window": true, + "master_user_secret": true, + "master_user_secret_kms_key_id": true, + "monitoring_role_arn": true, + "nchar_character_set_name": true, + "network_type": true, + "option_group_name": true, + "parameter_group_name": true, + "performance_insights_kms_key_id": true, + "performance_insights_retention_period": true, + "port": true, + "replica_mode": true, + "replicas": true, + "resource_id": true, + "restore_to_point_in_time": [], + "s3_import": [], + "snapshot_identifier": true, + "status": true, + "storage_throughput": true, + "storage_type": true, + "tags_all": true, + "timezone": true, + "vpc_security_group_ids": true + }, + "before_sensitive": false, + "after_sensitive": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": ">= 5.32.0", + "expressions": { + "region": { + "constant_value": "us-west-2" + } + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_db_instance.bad_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "bad_mysql_instance", + "provider_config_key": "aws", + "expressions": { + "allocated_storage": { + "constant_value": 5 + }, + "engine": { + "constant_value": "mysql" + }, + "identifier": { + "constant_value": "bad-mysql-instance-01" + }, + "instance_class": { + "constant_value": "db.t3.micro" + }, + "multi_az": { + "constant_value": false + }, + "password": { + "constant_value": "secret99" + }, + "skip_final_snapshot": { + "constant_value": true + }, + "username": { + "constant_value": "admin" + } + }, + "schema_version": 2 + } + ] + } + }, + "timestamp": "2024-10-01T10:19:03Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/rds-best-practices/check-rds-multi-az-support/test/bad-test/bad-payload-02.json b/terraform/plan/rds-best-practices/check-rds-multi-az-support/test/bad-test/bad-payload-02.json new file mode 100644 index 00000000..185ca419 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-multi-az-support/test/bad-test/bad-payload-02.json @@ -0,0 +1,237 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_db_instance.bad_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "bad_mysql_instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 2, + "values": { + "allocated_storage": 5, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "identifier": "bad-mysql-instance-02", + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "secret99", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "admin" + }, + "sensitive_values": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_db_instance.bad_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "bad_mysql_instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "allocated_storage": 5, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "identifier": "bad-mysql-instance-02", + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "secret99", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "admin" + }, + "after_unknown": { + "address": true, + "arn": true, + "availability_zone": true, + "backup_retention_period": true, + "backup_target": true, + "backup_window": true, + "blue_green_update": [], + "ca_cert_identifier": true, + "character_set_name": true, + "db_name": true, + "db_subnet_group_name": true, + "domain_fqdn": true, + "endpoint": true, + "engine_lifecycle_support": true, + "engine_version": true, + "engine_version_actual": true, + "hosted_zone_id": true, + "id": true, + "identifier_prefix": true, + "iops": true, + "kms_key_id": true, + "latest_restorable_time": true, + "license_model": true, + "listener_endpoint": true, + "maintenance_window": true, + "master_user_secret": true, + "master_user_secret_kms_key_id": true, + "monitoring_role_arn": true, + "multi_az": true, + "nchar_character_set_name": true, + "network_type": true, + "option_group_name": true, + "parameter_group_name": true, + "performance_insights_kms_key_id": true, + "performance_insights_retention_period": true, + "port": true, + "replica_mode": true, + "replicas": true, + "resource_id": true, + "restore_to_point_in_time": [], + "s3_import": [], + "snapshot_identifier": true, + "status": true, + "storage_throughput": true, + "storage_type": true, + "tags_all": true, + "timezone": true, + "vpc_security_group_ids": true + }, + "before_sensitive": false, + "after_sensitive": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": ">= 5.32.0", + "expressions": { + "region": { + "constant_value": "us-west-2" + } + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_db_instance.bad_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "bad_mysql_instance", + "provider_config_key": "aws", + "expressions": { + "allocated_storage": { + "constant_value": 5 + }, + "engine": { + "constant_value": "mysql" + }, + "identifier": { + "constant_value": "bad-mysql-instance-02" + }, + "instance_class": { + "constant_value": "db.t3.micro" + }, + "password": { + "constant_value": "secret99" + }, + "skip_final_snapshot": { + "constant_value": true + }, + "username": { + "constant_value": "admin" + } + }, + "schema_version": 2 + } + ] + } + }, + "timestamp": "2024-10-01T10:25:53Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/rds-best-practices/check-rds-multi-az-support/test/binding.yaml b/terraform/plan/rds-best-practices/check-rds-multi-az-support/test/binding.yaml new file mode 100644 index 00000000..a3dd760d --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-multi-az-support/test/binding.yaml @@ -0,0 +1,3 @@ +analyzer: + resource: + type: terraform-plan \ No newline at end of file diff --git a/terraform/plan/rds-best-practices/check-rds-multi-az-support/test/chainsaw-test.yaml b/terraform/plan/rds-best-practices/check-rds-multi-az-support/test/chainsaw-test.yaml new file mode 100644 index 00000000..ec6413d9 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-multi-az-support/test/chainsaw-test.yaml @@ -0,0 +1,92 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/kyverno/chainsaw/main/.schemas/json/test-chainsaw-v1alpha1.json +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: good-test-01 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --payload ./good-test/good-payload-01.json --policy ../check-rds-multi-az-support.yaml --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-rds-multi-az-support + rules: + - rule: + name: check-rds-multi-az-support + error: ~ + violations: ~ +--- +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: bad-test-01 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --payload ./bad-test/bad-payload-01.json --policy ../check-rds-multi-az-support.yaml --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-rds-multi-az-support + rules: + - rule: + name: check-rds-multi-az-support + error: ~ + violations: + - message: RDS DB instances should be configured with multiple Availability Zones (CHECK=spec.rules[0].assert.all[0]) + errors: + - type: FieldValueInvalid + value: false + detail: "Expected value: true" +--- +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: bad-test-02 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --payload ./bad-test/bad-payload-02.json --policy ../check-rds-multi-az-support.yaml --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-rds-multi-az-support + rules: + - rule: + name: check-rds-multi-az-support + error: ~ + violations: + - message: RDS DB instances should be configured with multiple Availability Zones (CHECK=spec.rules[0].assert.all[0]) + errors: + - type: FieldValueInvalid + value: false + detail: "Expected value: true" + diff --git a/terraform/plan/rds-best-practices/check-rds-multi-az-support/test/good-test/good-01.tf b/terraform/plan/rds-best-practices/check-rds-multi-az-support/test/good-test/good-01.tf new file mode 100644 index 00000000..a53a3107 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-multi-az-support/test/good-test/good-01.tf @@ -0,0 +1,25 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_db_instance" "good_mysql_instance" { + identifier = "good-mysql-instance" + instance_class = "db.t3.micro" + engine = "mysql" + username = "admin" + password = "secret99" + allocated_storage = 5 + skip_final_snapshot = true + multi_az = true +} diff --git a/terraform/plan/rds-best-practices/check-rds-multi-az-support/test/good-test/good-payload-01.json b/terraform/plan/rds-best-practices/check-rds-multi-az-support/test/good-test/good-payload-01.json new file mode 100644 index 00000000..3a7c106d --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-multi-az-support/test/good-test/good-payload-01.json @@ -0,0 +1,241 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_db_instance.good_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "good_mysql_instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 2, + "values": { + "allocated_storage": 5, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "identifier": "good-mysql-instance", + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "multi_az": true, + "password": "secret99", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "admin" + }, + "sensitive_values": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_db_instance.good_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "good_mysql_instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "allocated_storage": 5, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "identifier": "good-mysql-instance", + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "multi_az": true, + "password": "secret99", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "admin" + }, + "after_unknown": { + "address": true, + "arn": true, + "availability_zone": true, + "backup_retention_period": true, + "backup_target": true, + "backup_window": true, + "blue_green_update": [], + "ca_cert_identifier": true, + "character_set_name": true, + "db_name": true, + "db_subnet_group_name": true, + "domain_fqdn": true, + "endpoint": true, + "engine_lifecycle_support": true, + "engine_version": true, + "engine_version_actual": true, + "hosted_zone_id": true, + "id": true, + "identifier_prefix": true, + "iops": true, + "kms_key_id": true, + "latest_restorable_time": true, + "license_model": true, + "listener_endpoint": true, + "maintenance_window": true, + "master_user_secret": true, + "master_user_secret_kms_key_id": true, + "monitoring_role_arn": true, + "nchar_character_set_name": true, + "network_type": true, + "option_group_name": true, + "parameter_group_name": true, + "performance_insights_kms_key_id": true, + "performance_insights_retention_period": true, + "port": true, + "replica_mode": true, + "replicas": true, + "resource_id": true, + "restore_to_point_in_time": [], + "s3_import": [], + "snapshot_identifier": true, + "status": true, + "storage_throughput": true, + "storage_type": true, + "tags_all": true, + "timezone": true, + "vpc_security_group_ids": true + }, + "before_sensitive": false, + "after_sensitive": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": ">= 5.32.0", + "expressions": { + "region": { + "constant_value": "us-west-2" + } + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_db_instance.good_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "good_mysql_instance", + "provider_config_key": "aws", + "expressions": { + "allocated_storage": { + "constant_value": 5 + }, + "engine": { + "constant_value": "mysql" + }, + "identifier": { + "constant_value": "good-mysql-instance" + }, + "instance_class": { + "constant_value": "db.t3.micro" + }, + "multi_az": { + "constant_value": true + }, + "password": { + "constant_value": "secret99" + }, + "skip_final_snapshot": { + "constant_value": true + }, + "username": { + "constant_value": "admin" + } + }, + "schema_version": 2 + } + ] + } + }, + "timestamp": "2024-10-01T10:18:16Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/rds-best-practices/check-rds-storage-encrypted/check-rds-storage-encrypted.yaml b/terraform/plan/rds-best-practices/check-rds-storage-encrypted/check-rds-storage-encrypted.yaml new file mode 100644 index 00000000..395ae915 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-storage-encrypted/check-rds-storage-encrypted.yaml @@ -0,0 +1,31 @@ +apiVersion: json.kyverno.io/v1alpha1 +kind: ValidatingPolicy +metadata: + name: check-rds-storage-encrypted + annotations: + policies.kyverno.io/title: Check RDS Storage Encrypted + policies.kyverno.io/category: AWS RDS Best Practices + policies.kyverno.io/severity: medium + policies.kyverno.io/description: >- + This policy checks whether storage encryption is enabled for your Amazon RDS DB instances. + For an added layer of security for your sensitive data in RDS DB instances, you should configure your + RDS DB instances to be encrypted at rest. To encrypt your RDS DB instances and snapshots at rest, enable the + encryption option for your RDS DB instances. Data that is encrypted at rest includes the underlying storage + for DB instances, its automated backups, read replicas, and snapshots. RDS encrypted DB instances use the open + standard AES-256 encryption algorithm to encrypt your data on the server that hosts your RDS DB instances. + After your data is encrypted, Amazon RDS handles authentication of access and decryption of your data transparently + with a minimal impact on performance. You do not need to modify your database client applications to use encryption. +spec: + rules: + - name: check-rds-storage-encrypted + match: + all: + - ($analyzer.resource.type): terraform-plan + - (planned_values.root_module.resources[?type=='aws_db_instance'] || `[]` | length(@) > `0`): true + assert: + all: + - message: RDS DB instances should have encryption at-rest enabled + check: + ~.(planned_values.root_module.resources[?type=='aws_db_instance']): + values: + (!!storage_encrypted): true \ No newline at end of file diff --git a/terraform/plan/rds-best-practices/check-rds-storage-encrypted/test/README.md b/terraform/plan/rds-best-practices/check-rds-storage-encrypted/test/README.md new file mode 100644 index 00000000..1f449ecd --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-storage-encrypted/test/README.md @@ -0,0 +1,110 @@ +# Check RDS Storage Encrypted + +This policy checks whether storage encryption is enabled for your Amazon RDS DB instances. +For an added layer of security for your sensitive data in RDS DB instances, you should configure your +RDS DB instances to be encrypted at rest. To encrypt your RDS DB instances and snapshots at rest, enable the +encryption option for your RDS DB instances. Data that is encrypted at rest includes the underlying storage +for DB instances, its automated backups, read replicas, and snapshots. RDS encrypted DB instances use the open +standard AES-256 encryption algorithm to encrypt your data on the server that hosts your RDS DB instances. +After your data is encrypted, Amazon RDS handles authentication of access and decryption of your data transparently +with a minimal impact on performance. You do not need to modify your database client applications to use encryption. +You can read more about it [here](https://docs.aws.amazon.com/securityhub/latest/userguide/rds-controls.html#rds-3) + +## Policy Details: + +- **Policy Name:** check-rds-storage-encrypted +- **Check Description:** This policy ensures that RDS DB instances have encryption at-rest enabled +- **Policy Category:** AWS RDS Best Practices + +### Policy Validation Testing Instructions + +For testing this policy you will need to: +- Make sure you have `kyverno-json` installed on the machine +- Properly authenticate with AWS + +1. **Create the RDS Database Instance:** + + a. Good RDS Database Instance + ```bash + aws rds create-db-instance \ + --db-instance-identifier good-mysql-instance \ + --db-instance-class db.t3.micro \ + --engine mysql \ + --master-username admin \ + --master-user-password secret99 \ + --allocated-storage 5 \ + --storage-encrypted + ``` + + b. Bad RDS Database Instance + ```bash + aws rds create-db-instance \ + --db-instance-identifier bad-mysql-instance-01 \ + --db-instance-class db.t3.micro \ + --engine mysql \ + --master-username admin \ + --master-user-password secret99 \ + --allocated-storage 5 \ + --no-storage-encrypted + ``` + +2. **Get the Payloads:** + + a. Bad Payload + ```bash + aws rds describe-db-instances --db-instance-identifier bad-mysql-instance-01 > bad-payload-01.json + ``` + + b. Good Payload + ```bash + aws rds describe-db-instances --db-instance-identifier good-mysql-instance > good-payload-01.json + ``` +3. **Clean Up Resources:** + + a. Delete the Bad RDS Instance + ```bash + aws rds delete-db-instance --db-instance-identifier bad-mysql-instance-01 --skip-final-snapshot + ``` + + b. Delete the Good RDS Instance + + ```bash + aws rds delete-db-instance --db-instance-identifier good-mysql-instance --skip-final-snapshot + ``` + +4. **Test the Policy with Kyverno:** + ``` + kyverno-json scan --payload payload.json --policy policy.yaml + ``` + + a. **Test Policy Against Valid Payload:** + ``` + kyverno-json scan --payload test/good-test/good-payload-01.json --policy check-rds-storage-encrypted.yaml + ``` + + This produces the output: + ```bash + Loading policies ... + Loading payload ... + Pre processing ... + Running ( evaluating 1 resource against 1 policy ) ... + - check-rds-storage-encrypted / check-rds-storage-encrypted / PASSED + Done + ``` + + b. **Test Against Invalid Payload:** + ```bash + kyverno-json scan --payload test/bad-test/bad-payload-01.json --policy check-rds-storage-encrypted.yaml + ``` + + This produces the output: + ```bash + Loading policies ... + Loading payload ... + Pre processing ... + Running ( evaluating 1 resource against 1 policy ) ... + - check-rds-storage-encrypted / check-rds-storage-encrypted / FAILED + -> RDS DB instances should have encryption at-rest enabled + -> all[0].check.~.(DBInstances)[0].StorageEncrypted: Invalid value: false: Expected value: true + Done + ``` \ No newline at end of file diff --git a/terraform/plan/rds-best-practices/check-rds-storage-encrypted/test/bad-test/bad-01.tf b/terraform/plan/rds-best-practices/check-rds-storage-encrypted/test/bad-test/bad-01.tf new file mode 100644 index 00000000..ac1c5a83 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-storage-encrypted/test/bad-test/bad-01.tf @@ -0,0 +1,25 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_db_instance" "bad_mysql_instance" { + identifier = "bad-mysql-instance-01" + instance_class = "db.t3.micro" + engine = "mysql" + username = "admin" + password = "secret99" + allocated_storage = 5 + skip_final_snapshot = true + storage_encrypted = false +} diff --git a/terraform/plan/rds-best-practices/check-rds-storage-encrypted/test/bad-test/bad-02.tf b/terraform/plan/rds-best-practices/check-rds-storage-encrypted/test/bad-test/bad-02.tf new file mode 100644 index 00000000..a7134d0f --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-storage-encrypted/test/bad-test/bad-02.tf @@ -0,0 +1,24 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_db_instance" "bad_mysql_instance" { + identifier = "bad-mysql-instance-02" + instance_class = "db.t3.micro" + engine = "mysql" + username = "admin" + password = "secret99" + allocated_storage = 5 + skip_final_snapshot = true +} diff --git a/terraform/plan/rds-best-practices/check-rds-storage-encrypted/test/bad-test/bad-payload-01.json b/terraform/plan/rds-best-practices/check-rds-storage-encrypted/test/bad-test/bad-payload-01.json new file mode 100644 index 00000000..65d76aa5 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-storage-encrypted/test/bad-test/bad-payload-01.json @@ -0,0 +1,240 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_db_instance.bad_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "bad_mysql_instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 2, + "values": { + "allocated_storage": 5, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "identifier": "bad-mysql-instance-01", + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "secret99", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": false, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "admin" + }, + "sensitive_values": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_db_instance.bad_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "bad_mysql_instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "allocated_storage": 5, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "identifier": "bad-mysql-instance-01", + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "secret99", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": false, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "admin" + }, + "after_unknown": { + "address": true, + "arn": true, + "availability_zone": true, + "backup_retention_period": true, + "backup_target": true, + "backup_window": true, + "blue_green_update": [], + "ca_cert_identifier": true, + "character_set_name": true, + "db_name": true, + "db_subnet_group_name": true, + "domain_fqdn": true, + "endpoint": true, + "engine_lifecycle_support": true, + "engine_version": true, + "engine_version_actual": true, + "hosted_zone_id": true, + "id": true, + "identifier_prefix": true, + "iops": true, + "kms_key_id": true, + "latest_restorable_time": true, + "license_model": true, + "listener_endpoint": true, + "maintenance_window": true, + "master_user_secret": true, + "master_user_secret_kms_key_id": true, + "monitoring_role_arn": true, + "multi_az": true, + "nchar_character_set_name": true, + "network_type": true, + "option_group_name": true, + "parameter_group_name": true, + "performance_insights_kms_key_id": true, + "performance_insights_retention_period": true, + "port": true, + "replica_mode": true, + "replicas": true, + "resource_id": true, + "restore_to_point_in_time": [], + "s3_import": [], + "snapshot_identifier": true, + "status": true, + "storage_throughput": true, + "storage_type": true, + "tags_all": true, + "timezone": true, + "vpc_security_group_ids": true + }, + "before_sensitive": false, + "after_sensitive": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": ">= 5.32.0", + "expressions": { + "region": { + "constant_value": "us-west-2" + } + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_db_instance.bad_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "bad_mysql_instance", + "provider_config_key": "aws", + "expressions": { + "allocated_storage": { + "constant_value": 5 + }, + "engine": { + "constant_value": "mysql" + }, + "identifier": { + "constant_value": "bad-mysql-instance-01" + }, + "instance_class": { + "constant_value": "db.t3.micro" + }, + "password": { + "constant_value": "secret99" + }, + "skip_final_snapshot": { + "constant_value": true + }, + "storage_encrypted": { + "constant_value": false + }, + "username": { + "constant_value": "admin" + } + }, + "schema_version": 2 + } + ] + } + }, + "timestamp": "2024-10-01T10:41:18Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/rds-best-practices/check-rds-storage-encrypted/test/bad-test/bad-payload-02.json b/terraform/plan/rds-best-practices/check-rds-storage-encrypted/test/bad-test/bad-payload-02.json new file mode 100644 index 00000000..185ca419 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-storage-encrypted/test/bad-test/bad-payload-02.json @@ -0,0 +1,237 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_db_instance.bad_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "bad_mysql_instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 2, + "values": { + "allocated_storage": 5, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "identifier": "bad-mysql-instance-02", + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "secret99", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "admin" + }, + "sensitive_values": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_db_instance.bad_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "bad_mysql_instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "allocated_storage": 5, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "identifier": "bad-mysql-instance-02", + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "secret99", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "admin" + }, + "after_unknown": { + "address": true, + "arn": true, + "availability_zone": true, + "backup_retention_period": true, + "backup_target": true, + "backup_window": true, + "blue_green_update": [], + "ca_cert_identifier": true, + "character_set_name": true, + "db_name": true, + "db_subnet_group_name": true, + "domain_fqdn": true, + "endpoint": true, + "engine_lifecycle_support": true, + "engine_version": true, + "engine_version_actual": true, + "hosted_zone_id": true, + "id": true, + "identifier_prefix": true, + "iops": true, + "kms_key_id": true, + "latest_restorable_time": true, + "license_model": true, + "listener_endpoint": true, + "maintenance_window": true, + "master_user_secret": true, + "master_user_secret_kms_key_id": true, + "monitoring_role_arn": true, + "multi_az": true, + "nchar_character_set_name": true, + "network_type": true, + "option_group_name": true, + "parameter_group_name": true, + "performance_insights_kms_key_id": true, + "performance_insights_retention_period": true, + "port": true, + "replica_mode": true, + "replicas": true, + "resource_id": true, + "restore_to_point_in_time": [], + "s3_import": [], + "snapshot_identifier": true, + "status": true, + "storage_throughput": true, + "storage_type": true, + "tags_all": true, + "timezone": true, + "vpc_security_group_ids": true + }, + "before_sensitive": false, + "after_sensitive": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": ">= 5.32.0", + "expressions": { + "region": { + "constant_value": "us-west-2" + } + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_db_instance.bad_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "bad_mysql_instance", + "provider_config_key": "aws", + "expressions": { + "allocated_storage": { + "constant_value": 5 + }, + "engine": { + "constant_value": "mysql" + }, + "identifier": { + "constant_value": "bad-mysql-instance-02" + }, + "instance_class": { + "constant_value": "db.t3.micro" + }, + "password": { + "constant_value": "secret99" + }, + "skip_final_snapshot": { + "constant_value": true + }, + "username": { + "constant_value": "admin" + } + }, + "schema_version": 2 + } + ] + } + }, + "timestamp": "2024-10-01T10:25:53Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/rds-best-practices/check-rds-storage-encrypted/test/binding.yaml b/terraform/plan/rds-best-practices/check-rds-storage-encrypted/test/binding.yaml new file mode 100644 index 00000000..a3dd760d --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-storage-encrypted/test/binding.yaml @@ -0,0 +1,3 @@ +analyzer: + resource: + type: terraform-plan \ No newline at end of file diff --git a/terraform/plan/rds-best-practices/check-rds-storage-encrypted/test/chainsaw-test.yaml b/terraform/plan/rds-best-practices/check-rds-storage-encrypted/test/chainsaw-test.yaml new file mode 100644 index 00000000..0cfdf8d1 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-storage-encrypted/test/chainsaw-test.yaml @@ -0,0 +1,91 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/kyverno/chainsaw/main/.schemas/json/test-chainsaw-v1alpha1.json +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: good-test-01 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --payload ./good-test/good-payload-01.json --policy ../check-rds-storage-encrypted.yaml --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-rds-storage-encrypted + rules: + - rule: + name: check-rds-storage-encrypted + error: ~ + violations: ~ +--- +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: bad-test-01 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --payload ./bad-test/bad-payload-01.json --policy ../check-rds-storage-encrypted.yaml --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-rds-storage-encrypted + rules: + - rule: + name: check-rds-storage-encrypted + error: ~ + violations: + - message: RDS DB instances should have encryption at-rest enabled (CHECK=spec.rules[0].assert.all[0]) + errors: + - type: FieldValueInvalid + value: false + detail: "Expected value: true" +--- +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: bad-test-02 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --payload ./bad-test/bad-payload-02.json --policy ../check-rds-storage-encrypted.yaml --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-rds-storage-encrypted + rules: + - rule: + name: check-rds-storage-encrypted + error: ~ + violations: + - message: RDS DB instances should have encryption at-rest enabled (CHECK=spec.rules[0].assert.all[0]) + errors: + - type: FieldValueInvalid + value: false + detail: "Expected value: true" \ No newline at end of file diff --git a/terraform/plan/rds-best-practices/check-rds-storage-encrypted/test/good-test/good-01.tf b/terraform/plan/rds-best-practices/check-rds-storage-encrypted/test/good-test/good-01.tf new file mode 100644 index 00000000..7df5cfea --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-storage-encrypted/test/good-test/good-01.tf @@ -0,0 +1,25 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_db_instance" "good_mysql_instance" { + identifier = "good-mysql-instance" + instance_class = "db.t3.micro" + engine = "mysql" + username = "admin" + password = "secret99" + allocated_storage = 5 + skip_final_snapshot = true + storage_encrypted = true +} diff --git a/terraform/plan/rds-best-practices/check-rds-storage-encrypted/test/good-test/good-payload-01.json b/terraform/plan/rds-best-practices/check-rds-storage-encrypted/test/good-test/good-payload-01.json new file mode 100644 index 00000000..5f3a5df9 --- /dev/null +++ b/terraform/plan/rds-best-practices/check-rds-storage-encrypted/test/good-test/good-payload-01.json @@ -0,0 +1,240 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_db_instance.good_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "good_mysql_instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 2, + "values": { + "allocated_storage": 5, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "identifier": "good-mysql-instance", + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "secret99", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": true, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "admin" + }, + "sensitive_values": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_db_instance.good_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "good_mysql_instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "allocated_storage": 5, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "identifier": "good-mysql-instance", + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "secret99", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": true, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "admin" + }, + "after_unknown": { + "address": true, + "arn": true, + "availability_zone": true, + "backup_retention_period": true, + "backup_target": true, + "backup_window": true, + "blue_green_update": [], + "ca_cert_identifier": true, + "character_set_name": true, + "db_name": true, + "db_subnet_group_name": true, + "domain_fqdn": true, + "endpoint": true, + "engine_lifecycle_support": true, + "engine_version": true, + "engine_version_actual": true, + "hosted_zone_id": true, + "id": true, + "identifier_prefix": true, + "iops": true, + "kms_key_id": true, + "latest_restorable_time": true, + "license_model": true, + "listener_endpoint": true, + "maintenance_window": true, + "master_user_secret": true, + "master_user_secret_kms_key_id": true, + "monitoring_role_arn": true, + "multi_az": true, + "nchar_character_set_name": true, + "network_type": true, + "option_group_name": true, + "parameter_group_name": true, + "performance_insights_kms_key_id": true, + "performance_insights_retention_period": true, + "port": true, + "replica_mode": true, + "replicas": true, + "resource_id": true, + "restore_to_point_in_time": [], + "s3_import": [], + "snapshot_identifier": true, + "status": true, + "storage_throughput": true, + "storage_type": true, + "tags_all": true, + "timezone": true, + "vpc_security_group_ids": true + }, + "before_sensitive": false, + "after_sensitive": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": ">= 5.32.0", + "expressions": { + "region": { + "constant_value": "us-west-2" + } + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_db_instance.good_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "good_mysql_instance", + "provider_config_key": "aws", + "expressions": { + "allocated_storage": { + "constant_value": 5 + }, + "engine": { + "constant_value": "mysql" + }, + "identifier": { + "constant_value": "good-mysql-instance" + }, + "instance_class": { + "constant_value": "db.t3.micro" + }, + "password": { + "constant_value": "secret99" + }, + "skip_final_snapshot": { + "constant_value": true + }, + "storage_encrypted": { + "constant_value": true + }, + "username": { + "constant_value": "admin" + } + }, + "schema_version": 2 + } + ] + } + }, + "timestamp": "2024-10-01T10:45:49Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/README.md b/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/README.md new file mode 100644 index 00000000..c6b6d064 --- /dev/null +++ b/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/README.md @@ -0,0 +1,89 @@ +# RDS Instance IAM Authentication Enabled + +This policy checks whether an RDS DB instance has IAM database authentication enabled. The policy fails if IAM authentication is not configured for RDS DB instances. This policy only evaluates RDS instances with the following engine types: `mysql`, `postgres`, `aurora`, `aurora-mysql`, `aurora-postgresql` and `mariadb`. IAM database authentication allows authentication to database instances with an authentication token instead of a password. traffic to and from the database is encrypted using SSL. + +## Policy Details: + +- **Policy Name:** rds-instance-iam-authentication-enabled +- **Check Description:** This policy ensures that IAM authentication is configured for RDS instances +- **Policy Category:** AWS RDS Best Practices + +### Policy Validation Testing Instructions + +For testing this policy you will need to: +- Make sure you have `kyverno-json` installed on the machine +- Properly authenticate with AWS + +1. **Initialize Terraform:** + ```bash + terraform init + ``` + +2. **Create Binary Terraform Plan:** + ```bash + terraform plan -out tfplan.binary + ``` + +3. **Convert Binary to JSON Payload:** + ```bash + terraform show -json tfplan.binary | jq > payload.json + ``` + +4. **Test the Policy with Kyverno:** + ```bash + kyverno-json scan --payload payload.json --policy policy.yaml + ``` + + a. **Test Policy Against Valid Payload:** + ```bash + kyverno-json scan --payload test/good-test/good-payload-01.json --policy rds-instance-iam-authentication-enabled.yaml --bindings test/binding.yaml + ``` + + This produces the output: + ```bash + Loading policies ... + Loading bindings ... + - analyzer -> map[resource:map[type:terraform-plan]] + Loading payload ... + Pre processing ... + Running ( evaluating 1 resource against 1 policy ) ... + - PASSED (POLICY=rds-instance-iam-authentication-enabled, RULE=rds-instance-iam-authentication-enabled) + Done + ``` + + b. **Test Against Invalid Payload:** + ``` + kyverno-json scan --payload test/bad-test/bad-payload-01.json --policy rds-instance-iam-authentication-enabled.yaml --bindings test/binding.yaml + ``` + + This produces the output: + ```bash + Loading policies ... + Loading bindings ... + - analyzer -> map[resource:map[type:terraform-plan]] + Loading payload ... + Pre processing ... + Running ( evaluating 1 resource against 1 policy ) ... + - FAILED (POLICY=rds-instance-iam-authentication-enabled, RULE=rds-instance-iam-authentication-enabled) + -> IAM authentication should be configured for RDS instances (CHECK=spec.rules[0].assert.all[0]) + -> Invalid value: false: Expected value: true (PATH=~.(planned_values.root_module.resources[?type=='aws_db_instance' && contains($engineTypes, values.engine)])[0].values.(!!iam_database_authentication_enabled)) + Done + ``` + + c. **Test against Payload to Be Skipped:** + ``` + kyverno-json scan --payload test/skip-test/skip-payload-01.json --policy rds-instance-iam-authentication-enabled.yaml --bindings test/binding.yaml + ``` + + This produces the output: + ```bash + Loading policies ... + Loading bindings ... + - analyzer -> map[resource:map[type:terraform-plan]] + Loading payload ... + Pre processing ... + Running ( evaluating 1 resource against 1 policy ) ... + Done + ``` + +--- \ No newline at end of file diff --git a/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/rds-instance-iam-authentication-enabled.yaml b/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/rds-instance-iam-authentication-enabled.yaml new file mode 100644 index 00000000..cea2d0bf --- /dev/null +++ b/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/rds-instance-iam-authentication-enabled.yaml @@ -0,0 +1,37 @@ +apiVersion: json.kyverno.io/v1alpha1 +kind: ValidatingPolicy +metadata: + name: rds-instance-iam-authentication-enabled + annotations: + policies.kyverno.io/title: RDS Instance IAM Authentication Enabled + policies.kyverno.io/category: AWS RDS Best Practices + policies.kyverno.io/severity: medium + policies.kyverno.io/description: >- + This policy checks whether an RDS DB instance has IAM database authentication enabled. + The policy fails if IAM authentication is not configured for RDS DB instances. + This policy only evaluates RDS instances with the following engine types: mysql, postgres, aurora, aurora-mysql, aurora-postgresql, and mariadb. + IAM database authentication allows authentication to database instances with an authentication token instead of a password. Network traffic to and from the database is encrypted using SSL. +spec: + rules: + - name: rds-instance-iam-authentication-enabled + match: + all: + - ($analyzer.resource.type): terraform-plan + - (planned_values.root_module.resources[?type=='aws_db_instance' && contains($engineTypes, values.engine)] || `[]` | length(@) > `0`): true + context: + - name: engineTypes + variable: + - 'mysql' + - 'postgres' + - 'aurora' + - 'aurora-mysql' + - 'aurora-postgresql' + - 'mariadb' + assert: + all: + - message: IAM authentication should be configured for RDS instances + check: + ~.(planned_values.root_module.resources[?type=='aws_db_instance' && contains($engineTypes, values.engine)]): + values: + (!!iam_database_authentication_enabled): true + \ No newline at end of file diff --git a/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/test/bad-test/bad-01.tf b/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/test/bad-test/bad-01.tf new file mode 100644 index 00000000..f8218015 --- /dev/null +++ b/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/test/bad-test/bad-01.tf @@ -0,0 +1,25 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_db_instance" "bad_mysql_instance" { + identifier = "bad-mysql-instance-01" + instance_class = "db.t3.micro" + engine = "mysql" + username = "admin" + password = "secret99" + allocated_storage = 5 + skip_final_snapshot = true + iam_database_authentication_enabled = false +} diff --git a/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/test/bad-test/bad-02.tf b/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/test/bad-test/bad-02.tf new file mode 100644 index 00000000..82b3245f --- /dev/null +++ b/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/test/bad-test/bad-02.tf @@ -0,0 +1,24 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_db_instance" "bad_mysql_instance" { + identifier = "bad-mysql-instance-02" + instance_class = "db.t3.micro" + engine = "mysql" + username = "admin" + password = "secret99" + allocated_storage = 5 + skip_final_snapshot = true +} diff --git a/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/test/bad-test/bad-payload-01.json b/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/test/bad-test/bad-payload-01.json new file mode 100644 index 00000000..1d16b53d --- /dev/null +++ b/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/test/bad-test/bad-payload-01.json @@ -0,0 +1,240 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_db_instance.bad_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "bad_mysql_instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 2, + "values": { + "allocated_storage": 5, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": false, + "identifier": "bad-mysql-instance-01", + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "secret99", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "admin" + }, + "sensitive_values": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_db_instance.bad_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "bad_mysql_instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "allocated_storage": 5, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": false, + "identifier": "bad-mysql-instance-01", + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "secret99", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "admin" + }, + "after_unknown": { + "address": true, + "arn": true, + "availability_zone": true, + "backup_retention_period": true, + "backup_target": true, + "backup_window": true, + "blue_green_update": [], + "ca_cert_identifier": true, + "character_set_name": true, + "db_name": true, + "db_subnet_group_name": true, + "domain_fqdn": true, + "endpoint": true, + "engine_lifecycle_support": true, + "engine_version": true, + "engine_version_actual": true, + "hosted_zone_id": true, + "id": true, + "identifier_prefix": true, + "iops": true, + "kms_key_id": true, + "latest_restorable_time": true, + "license_model": true, + "listener_endpoint": true, + "maintenance_window": true, + "master_user_secret": true, + "master_user_secret_kms_key_id": true, + "monitoring_role_arn": true, + "multi_az": true, + "nchar_character_set_name": true, + "network_type": true, + "option_group_name": true, + "parameter_group_name": true, + "performance_insights_kms_key_id": true, + "performance_insights_retention_period": true, + "port": true, + "replica_mode": true, + "replicas": true, + "resource_id": true, + "restore_to_point_in_time": [], + "s3_import": [], + "snapshot_identifier": true, + "status": true, + "storage_throughput": true, + "storage_type": true, + "tags_all": true, + "timezone": true, + "vpc_security_group_ids": true + }, + "before_sensitive": false, + "after_sensitive": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": ">= 5.32.0", + "expressions": { + "region": { + "constant_value": "us-west-2" + } + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_db_instance.bad_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "bad_mysql_instance", + "provider_config_key": "aws", + "expressions": { + "allocated_storage": { + "constant_value": 5 + }, + "engine": { + "constant_value": "mysql" + }, + "iam_database_authentication_enabled": { + "constant_value": false + }, + "identifier": { + "constant_value": "bad-mysql-instance-01" + }, + "instance_class": { + "constant_value": "db.t3.micro" + }, + "password": { + "constant_value": "secret99" + }, + "skip_final_snapshot": { + "constant_value": true + }, + "username": { + "constant_value": "admin" + } + }, + "schema_version": 2 + } + ] + } + }, + "timestamp": "2024-10-01T11:37:51Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/test/bad-test/bad-payload-02.json b/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/test/bad-test/bad-payload-02.json new file mode 100644 index 00000000..69649932 --- /dev/null +++ b/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/test/bad-test/bad-payload-02.json @@ -0,0 +1,237 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_db_instance.bad_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "bad_mysql_instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 2, + "values": { + "allocated_storage": 5, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "identifier": "bad-mysql-instance-02", + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "secret99", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "admin" + }, + "sensitive_values": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_db_instance.bad_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "bad_mysql_instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "allocated_storage": 5, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "identifier": "bad-mysql-instance-02", + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "secret99", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "admin" + }, + "after_unknown": { + "address": true, + "arn": true, + "availability_zone": true, + "backup_retention_period": true, + "backup_target": true, + "backup_window": true, + "blue_green_update": [], + "ca_cert_identifier": true, + "character_set_name": true, + "db_name": true, + "db_subnet_group_name": true, + "domain_fqdn": true, + "endpoint": true, + "engine_lifecycle_support": true, + "engine_version": true, + "engine_version_actual": true, + "hosted_zone_id": true, + "id": true, + "identifier_prefix": true, + "iops": true, + "kms_key_id": true, + "latest_restorable_time": true, + "license_model": true, + "listener_endpoint": true, + "maintenance_window": true, + "master_user_secret": true, + "master_user_secret_kms_key_id": true, + "monitoring_role_arn": true, + "multi_az": true, + "nchar_character_set_name": true, + "network_type": true, + "option_group_name": true, + "parameter_group_name": true, + "performance_insights_kms_key_id": true, + "performance_insights_retention_period": true, + "port": true, + "replica_mode": true, + "replicas": true, + "resource_id": true, + "restore_to_point_in_time": [], + "s3_import": [], + "snapshot_identifier": true, + "status": true, + "storage_throughput": true, + "storage_type": true, + "tags_all": true, + "timezone": true, + "vpc_security_group_ids": true + }, + "before_sensitive": false, + "after_sensitive": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": ">= 5.32.0", + "expressions": { + "region": { + "constant_value": "us-west-2" + } + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_db_instance.bad_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "bad_mysql_instance", + "provider_config_key": "aws", + "expressions": { + "allocated_storage": { + "constant_value": 5 + }, + "engine": { + "constant_value": "mysql" + }, + "identifier": { + "constant_value": "bad-mysql-instance-02" + }, + "instance_class": { + "constant_value": "db.t3.micro" + }, + "password": { + "constant_value": "secret99" + }, + "skip_final_snapshot": { + "constant_value": true + }, + "username": { + "constant_value": "admin" + } + }, + "schema_version": 2 + } + ] + } + }, + "timestamp": "2024-10-01T11:37:49Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/test/binding.yaml b/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/test/binding.yaml new file mode 100644 index 00000000..a3dd760d --- /dev/null +++ b/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/test/binding.yaml @@ -0,0 +1,3 @@ +analyzer: + resource: + type: terraform-plan \ No newline at end of file diff --git a/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/test/chainsaw-test.yaml b/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/test/chainsaw-test.yaml new file mode 100644 index 00000000..e138c0e0 --- /dev/null +++ b/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/test/chainsaw-test.yaml @@ -0,0 +1,114 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/kyverno/chainsaw/main/.schemas/json/test-chainsaw-v1alpha1.json +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: good-test-01 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --payload ./good-test/good-payload-01.json --policy ../rds-instance-iam-authentication-enabled.yaml --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: rds-instance-iam-authentication-enabled + rules: + - rule: + name: rds-instance-iam-authentication-enabled + error: ~ + violations: ~ +--- +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: bad-test-01 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --payload ./bad-test/bad-payload-01.json --policy ../rds-instance-iam-authentication-enabled.yaml --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: rds-instance-iam-authentication-enabled + rules: + - rule: + name: rds-instance-iam-authentication-enabled + error: ~ + violations: + - message: IAM authentication should be configured for RDS instances (CHECK=spec.rules[0].assert.all[0]) + errors: + - type: FieldValueInvalid + value: false + detail: "Expected value: true" +--- +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: bad-test-02 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --payload ./bad-test/bad-payload-02.json --policy ../rds-instance-iam-authentication-enabled.yaml --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: rds-instance-iam-authentication-enabled + rules: + - rule: + name: rds-instance-iam-authentication-enabled + error: ~ + violations: + - message: IAM authentication should be configured for RDS instances (CHECK=spec.rules[0].assert.all[0]) + errors: + - type: FieldValueInvalid + value: false + detail: "Expected value: true" +--- +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: skip-test-01 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --payload ./skip-test/skip-payload-01.json --policy ../rds-instance-iam-authentication-enabled.yaml --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: rds-instance-iam-authentication-enabled + rules: ~ \ No newline at end of file diff --git a/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/test/good-test/good-01.tf b/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/test/good-test/good-01.tf new file mode 100644 index 00000000..0c19ed99 --- /dev/null +++ b/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/test/good-test/good-01.tf @@ -0,0 +1,25 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_db_instance" "good_mysql_instance" { + identifier = "good-mysql-instance" + instance_class = "db.t3.micro" + engine = "mysql" + username = "admin" + password = "secret99" + allocated_storage = 5 + skip_final_snapshot = true + iam_database_authentication_enabled = true +} diff --git a/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/test/good-test/good-payload-01.json b/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/test/good-test/good-payload-01.json new file mode 100644 index 00000000..9b7bded2 --- /dev/null +++ b/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/test/good-test/good-payload-01.json @@ -0,0 +1,240 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_db_instance.good_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "good_mysql_instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 2, + "values": { + "allocated_storage": 5, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": true, + "identifier": "good-mysql-instance", + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "secret99", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "admin" + }, + "sensitive_values": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_db_instance.good_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "good_mysql_instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "allocated_storage": 5, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "mysql", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": true, + "identifier": "good-mysql-instance", + "instance_class": "db.t3.micro", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "secret99", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "admin" + }, + "after_unknown": { + "address": true, + "arn": true, + "availability_zone": true, + "backup_retention_period": true, + "backup_target": true, + "backup_window": true, + "blue_green_update": [], + "ca_cert_identifier": true, + "character_set_name": true, + "db_name": true, + "db_subnet_group_name": true, + "domain_fqdn": true, + "endpoint": true, + "engine_lifecycle_support": true, + "engine_version": true, + "engine_version_actual": true, + "hosted_zone_id": true, + "id": true, + "identifier_prefix": true, + "iops": true, + "kms_key_id": true, + "latest_restorable_time": true, + "license_model": true, + "listener_endpoint": true, + "maintenance_window": true, + "master_user_secret": true, + "master_user_secret_kms_key_id": true, + "monitoring_role_arn": true, + "multi_az": true, + "nchar_character_set_name": true, + "network_type": true, + "option_group_name": true, + "parameter_group_name": true, + "performance_insights_kms_key_id": true, + "performance_insights_retention_period": true, + "port": true, + "replica_mode": true, + "replicas": true, + "resource_id": true, + "restore_to_point_in_time": [], + "s3_import": [], + "snapshot_identifier": true, + "status": true, + "storage_throughput": true, + "storage_type": true, + "tags_all": true, + "timezone": true, + "vpc_security_group_ids": true + }, + "before_sensitive": false, + "after_sensitive": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": ">= 5.32.0", + "expressions": { + "region": { + "constant_value": "us-west-2" + } + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_db_instance.good_mysql_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "good_mysql_instance", + "provider_config_key": "aws", + "expressions": { + "allocated_storage": { + "constant_value": 5 + }, + "engine": { + "constant_value": "mysql" + }, + "iam_database_authentication_enabled": { + "constant_value": true + }, + "identifier": { + "constant_value": "good-mysql-instance" + }, + "instance_class": { + "constant_value": "db.t3.micro" + }, + "password": { + "constant_value": "secret99" + }, + "skip_final_snapshot": { + "constant_value": true + }, + "username": { + "constant_value": "admin" + } + }, + "schema_version": 2 + } + ] + } + }, + "timestamp": "2024-10-01T11:37:47Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/test/skip-test/skip-01.tf b/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/test/skip-test/skip-01.tf new file mode 100644 index 00000000..331fdd20 --- /dev/null +++ b/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/test/skip-test/skip-01.tf @@ -0,0 +1,24 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_db_instance" "skip_instance" { + identifier = "skip-instance-01" + instance_class = "db.m5.large" + engine = "oracle-ee" # Engine is oracle-ee. Hence, this test is skipped. + username = "master_username" + password = "secure_password" + allocated_storage = 10 + skip_final_snapshot = true +} diff --git a/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/test/skip-test/skip-payload-01.json b/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/test/skip-test/skip-payload-01.json new file mode 100644 index 00000000..8f98d052 --- /dev/null +++ b/terraform/plan/rds-best-practices/rds-instance-iam-authentication-enabled/test/skip-test/skip-payload-01.json @@ -0,0 +1,237 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_db_instance.skip_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "skip_instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 2, + "values": { + "allocated_storage": 10, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "oracle-ee", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "identifier": "skip-instance-01", + "instance_class": "db.m5.large", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "secure_password", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "master_username" + }, + "sensitive_values": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_db_instance.skip_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "skip_instance", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "allocated_storage": 10, + "allow_major_version_upgrade": null, + "apply_immediately": false, + "auto_minor_version_upgrade": true, + "blue_green_update": [], + "copy_tags_to_snapshot": false, + "custom_iam_instance_profile": null, + "customer_owned_ip_enabled": null, + "dedicated_log_volume": false, + "delete_automated_backups": true, + "deletion_protection": null, + "domain": null, + "domain_auth_secret_arn": null, + "domain_dns_ips": null, + "domain_iam_role_name": null, + "domain_ou": null, + "enabled_cloudwatch_logs_exports": null, + "engine": "oracle-ee", + "final_snapshot_identifier": null, + "iam_database_authentication_enabled": null, + "identifier": "skip-instance-01", + "instance_class": "db.m5.large", + "manage_master_user_password": null, + "max_allocated_storage": null, + "monitoring_interval": 0, + "password": "secure_password", + "performance_insights_enabled": false, + "publicly_accessible": false, + "replicate_source_db": null, + "restore_to_point_in_time": [], + "s3_import": [], + "skip_final_snapshot": true, + "storage_encrypted": null, + "tags": null, + "timeouts": null, + "upgrade_storage_config": null, + "username": "master_username" + }, + "after_unknown": { + "address": true, + "arn": true, + "availability_zone": true, + "backup_retention_period": true, + "backup_target": true, + "backup_window": true, + "blue_green_update": [], + "ca_cert_identifier": true, + "character_set_name": true, + "db_name": true, + "db_subnet_group_name": true, + "domain_fqdn": true, + "endpoint": true, + "engine_lifecycle_support": true, + "engine_version": true, + "engine_version_actual": true, + "hosted_zone_id": true, + "id": true, + "identifier_prefix": true, + "iops": true, + "kms_key_id": true, + "latest_restorable_time": true, + "license_model": true, + "listener_endpoint": true, + "maintenance_window": true, + "master_user_secret": true, + "master_user_secret_kms_key_id": true, + "monitoring_role_arn": true, + "multi_az": true, + "nchar_character_set_name": true, + "network_type": true, + "option_group_name": true, + "parameter_group_name": true, + "performance_insights_kms_key_id": true, + "performance_insights_retention_period": true, + "port": true, + "replica_mode": true, + "replicas": true, + "resource_id": true, + "restore_to_point_in_time": [], + "s3_import": [], + "snapshot_identifier": true, + "status": true, + "storage_throughput": true, + "storage_type": true, + "tags_all": true, + "timezone": true, + "vpc_security_group_ids": true + }, + "before_sensitive": false, + "after_sensitive": { + "blue_green_update": [], + "listener_endpoint": [], + "master_user_secret": [], + "password": true, + "replicas": [], + "restore_to_point_in_time": [], + "s3_import": [], + "tags_all": {}, + "vpc_security_group_ids": [] + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": ">= 5.32.0", + "expressions": { + "region": { + "constant_value": "us-west-2" + } + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_db_instance.skip_instance", + "mode": "managed", + "type": "aws_db_instance", + "name": "skip_instance", + "provider_config_key": "aws", + "expressions": { + "allocated_storage": { + "constant_value": 10 + }, + "engine": { + "constant_value": "oracle-ee" + }, + "identifier": { + "constant_value": "skip-instance-01" + }, + "instance_class": { + "constant_value": "db.m5.large" + }, + "password": { + "constant_value": "secure_password" + }, + "skip_final_snapshot": { + "constant_value": true + }, + "username": { + "constant_value": "master_username" + } + }, + "schema_version": 2 + } + ] + } + }, + "timestamp": "2024-10-01T11:37:44Z", + "applyable": true, + "complete": true, + "errored": false +}