diff --git a/terraform/plan/ecs-best-practices/check-awsvpc-network-mode/README.md b/terraform/plan/ecs-best-practices/check-awsvpc-network-mode/README.md new file mode 100644 index 00000000..28861c1f --- /dev/null +++ b/terraform/plan/ecs-best-practices/check-awsvpc-network-mode/README.md @@ -0,0 +1,81 @@ +# Check `awsvpc` network mode + +When you're running containers on AWS, managing the networking becomes crucial, especially when leveraging the benefits of hosting multiple containers on a single host. There are various network modes to choose from: + +1. **Host mode:** This is the most basic network mode in Amazon ECS. It essentially shares the host's networking stack with the containers. + +2. **Bridge mode:** This mode employs a virtual network bridge to establish a layer between the host and the container's networking. + +3. **AWSVPC mode:** Here, Amazon ECS generates and oversees an Elastic Network Interface (ENI) for each task, providing each task with a distinct private IP address within the VPC. + +By default, the network mode for ECS tasks is set to `bridge`. However, we will opt for the `awsvpc` network mode here. This choice is strategic, as it facilitates controlled traffic flow between tasks and enhances security. `awsvpc` offers task-level network isolation for tasks running on Amazon EC2. Importantly, it's the exclusive network mode allowing the assignment of security groups to tasks. + +To formalize our approach, it's prudent to establish a policy that ensures the usage of 'awsvpc' network mode. This policy aligns with our security strategy by adding an extra layer of protection through task-level isolation and the ability to apply security groups at the task level. Therefore, adopting and enforcing this policy safeguards our containerized infrastructure while optimizing networking capabilities on AWS. + +### Policy Validation Testing Instructions + +To evaluate and test the policy ensuring the presence of the `awsvpc` network mode in the Terraform plan payload, follow the steps outlined below: + +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:** + ``` + kyverno-json scan --payload payload.json --policy policy.yaml + ``` + + a. **Test Policy Against Valid Payload:** + ``` + kyverno-json scan --policy check-awsvpc-network-mode.yaml --payload test/good-payload.json --bindings test/binding.yaml + ``` + + This produces the output: + ``` + Loading policies ... + Loading bindings ... + - analyzer -> map[resource:map[type:terraform-plan]] + Loading payload ... + Pre processing ... + Running ( evaluating 1 resource against 1 policy ) ... + - check-awsvpc-network-mode / check-awsvpc-network-mode / PASSED + Done + ``` + + b. **Test Against Invalid Payload:** + ``` + kyverno-json scan --policy check-awsvpc-network-mode.yaml --payload test/bad-payload.json --bindings test/binding.yaml + ``` + + This produces the output: + ``` + Loading policies ... + Loading bindings ... + - analyzer -> map[resource:map[type:terraform-plan]] + Loading payload ... + Pre processing ... + Running ( evaluating 1 resource against 1 policy ) ... + - check-awsvpc-network-mode / check-awsvpc-network-mode / FAILED + -> ECS services and tasks are required to use awsvpc network mode. + -> all[0].check.~.(planned_values.root_module.resources[?type=='aws_ecs_task_definition'].values)[0].network_mode: Invalid value: "bridge": Expected value: "awsvpc" + Done + ``` + +--- + +These instructions are designed to systematically assess the compliance of Terraform plans with the defined policy. Following these steps ensures a thorough examination of the `awsvpc` network mode presence in the payload, allowing for effective validation and adherence to the specified policy. \ No newline at end of file diff --git a/terraform/plan/ecs-best-practices/check-awsvpc-network-mode/check-awsvpc-network-mode.yaml b/terraform/plan/ecs-best-practices/check-awsvpc-network-mode/check-awsvpc-network-mode.yaml new file mode 100644 index 00000000..4695487e --- /dev/null +++ b/terraform/plan/ecs-best-practices/check-awsvpc-network-mode/check-awsvpc-network-mode.yaml @@ -0,0 +1,28 @@ +apiVersion: json.kyverno.io/v1alpha1 +kind: ValidatingPolicy +metadata: + name: check-awsvpc-network-mode + labels: + ecs.aws.network.kyverno.io: awsvpc + annotations: + policies.kyverno.io/title: Check awsvpc network mode + policies.kyverno.io/category: ECS Best Practices + policies.kyverno.io/severity: medium + policies.kyverno.io/description: >- + The awsvpc network mode restricts the flow of traffic between different + tasks or between your tasks and other services that run within your Amazon VPC. + The awsvpc network mode provides task-level network isolation for tasks + that run on Amazon EC2. +spec: + rules: + - name: check-awsvpc-network-mode + match: + all: + - ($analyzer.resource.type): terraform-plan + - (planned_values.root_module.resources[?type=='aws_ecs_task_definition'] | length(@) > `0`): true + assert: + all: + - message: ECS services and tasks are required to use awsvpc network mode. + check: + ~.(planned_values.root_module.resources[?type=='aws_ecs_task_definition'].values): + network_mode: awsvpc diff --git a/terraform/plan/ecs-best-practices/check-awsvpc-network-mode/test/bad-payload.json b/terraform/plan/ecs-best-practices/check-awsvpc-network-mode/test/bad-payload.json new file mode 100644 index 00000000..a7c794c5 --- /dev/null +++ b/terraform/plan/ecs-best-practices/check-awsvpc-network-mode/test/bad-payload.json @@ -0,0 +1,173 @@ +{ + "format_version": "1.2", + "terraform_version": "1.6.6-dev", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_ecs_task_definition.task", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "task", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 1, + "values": { + "container_definitions": "[{\"cpu\":512,\"essential\":true,\"image\":\"nginx:1.23.1\",\"memory\":2048,\"name\":\"foo-task\",\"portMappings\":[{\"containerPort\":80,\"hostPort\":80}]}]", + "cpu": "512", + "ephemeral_storage": [], + "execution_role_arn": null, + "family": "service", + "inference_accelerator": [], + "ipc_mode": null, + "memory": "2048", + "network_mode": "bridge", + "pid_mode": null, + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "EC2" + ], + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "task_role_arn": null, + "volume": [] + }, + "sensitive_values": { + "ephemeral_storage": [], + "inference_accelerator": [], + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + false + ], + "runtime_platform": [], + "tags_all": {}, + "volume": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_ecs_task_definition.task", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "task", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "container_definitions": "[{\"cpu\":512,\"essential\":true,\"image\":\"nginx:1.23.1\",\"memory\":2048,\"name\":\"foo-task\",\"portMappings\":[{\"containerPort\":80,\"hostPort\":80}]}]", + "cpu": "512", + "ephemeral_storage": [], + "execution_role_arn": null, + "family": "service", + "inference_accelerator": [], + "ipc_mode": null, + "memory": "2048", + "network_mode": "awsvpc", + "pid_mode": null, + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + "EC2" + ], + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "task_role_arn": null, + "volume": [] + }, + "after_unknown": { + "arn": true, + "arn_without_revision": true, + "ephemeral_storage": [], + "id": true, + "inference_accelerator": [], + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + false + ], + "revision": true, + "runtime_platform": [], + "tags_all": true, + "volume": [] + }, + "before_sensitive": false, + "after_sensitive": { + "ephemeral_storage": [], + "inference_accelerator": [], + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": [ + false + ], + "runtime_platform": [], + "tags_all": {}, + "volume": [] + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": "~> 4.0", + "expressions": { + "region": { + "constant_value": "us-west-1" + } + } + }, + "docker": { + "name": "docker", + "full_name": "registry.terraform.io/kreuzwerker/docker", + "version_constraint": "~> 2.20.0" + } + }, + "root_module": { + "resources": [ + { + "address": "aws_ecs_task_definition.task", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "task", + "provider_config_key": "aws", + "expressions": { + "container_definitions": { + "constant_value": " [\n {\n \"name\" : \"foo-task\",\n \"image\" : \"nginx:1.23.1\",\n \"cpu\" : 512,\n \"memory\" : 2048,\n \"essential\" : true,\n \"portMappings\" : [\n {\n \"containerPort\" : 80,\n \"hostPort\" : 80\n }\n ]\n }\n ]\n" + }, + "cpu": { + "constant_value": 512 + }, + "family": { + "constant_value": "service" + }, + "memory": { + "constant_value": 2048 + }, + "network_mode": { + "constant_value": "awsvpc" + }, + "requires_compatibilities": { + "constant_value": [ + "EC2" + ] + } + }, + "schema_version": 1 + } + ] + } + }, + "timestamp": "2024-01-15T13:25:27Z", + "errored": false +} diff --git a/terraform/plan/ecs-best-practices/check-awsvpc-network-mode/test/bad.tf b/terraform/plan/ecs-best-practices/check-awsvpc-network-mode/test/bad.tf new file mode 100644 index 00000000..78cdbb45 --- /dev/null +++ b/terraform/plan/ecs-best-practices/check-awsvpc-network-mode/test/bad.tf @@ -0,0 +1,46 @@ +resource "aws_ecs_task_definition" "task" { + family = "service" + network_mode = "bridge" + requires_compatibilities = ["EC2"] + cpu = 512 + memory = 2048 + container_definitions = < 4.0", + "expressions": { + "region": { + "constant_value": "us-west-1" + } + } + }, + "docker": { + "name": "docker", + "full_name": "registry.terraform.io/kreuzwerker/docker", + "version_constraint": "~> 2.20.0" + } + }, + "root_module": { + "resources": [ + { + "address": "aws_ecs_task_definition.task", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "task", + "provider_config_key": "aws", + "expressions": { + "container_definitions": { + "constant_value": " [\n {\n \"name\" : \"foo-task\",\n \"image\" : \"nginx:1.23.1\",\n \"cpu\" : 512,\n \"memory\" : 2048,\n \"essential\" : true,\n \"portMappings\" : [\n {\n \"containerPort\" : 80,\n \"hostPort\" : 80\n }\n ]\n }\n ]\n" + }, + "cpu": { + "constant_value": 512 + }, + "family": { + "constant_value": "service" + }, + "memory": { + "constant_value": 2048 + }, + "network_mode": { + "constant_value": "awsvpc" + }, + "requires_compatibilities": { + "constant_value": [ + "EC2" + ] + } + }, + "schema_version": 1 + } + ] + } + }, + "timestamp": "2024-01-15T13:25:27Z", + "errored": false + } + \ No newline at end of file diff --git a/terraform/plan/ecs-best-practices/check-awsvpc-network-mode/test/good.tf b/terraform/plan/ecs-best-practices/check-awsvpc-network-mode/test/good.tf new file mode 100644 index 00000000..31055154 --- /dev/null +++ b/terraform/plan/ecs-best-practices/check-awsvpc-network-mode/test/good.tf @@ -0,0 +1,46 @@ +resource "aws_ecs_task_definition" "task" { + family = "service" + network_mode = "awsvpc" + requires_compatibilities = ["EC2"] + cpu = 512 + memory = 2048 + container_definitions = < payload.json + ``` + +4. **Test the Policy with Kyverno:** + ``` + kyverno-json scan --payload payload.json --policy policy.yaml + ``` + + a. **Test Policy Against Valid Payload:** + ``` + kyverno-json scan --policy check-ecs-exec-logging.yaml --payload test/good-test/good-payload-01.json --bindings test/binding.yaml + ``` + + This produces the output: + ``` + Loading policies ... + Loading bindings ... + - analyzer -> map[resource:map[type:terraform-plan]] + Loading payload ... + Pre processing ... + Running ( evaluating 1 resource against 1 policy ) ... + - check-ecs-exec-logging / check-ecs-exec-logging / PASSED + Done + ``` + + b. **Test Against Invalid Payload:** + ``` + kyverno-json scan --policy check-ecs-exec-logging.yaml --payload test/bad-test/bad-payload-01.json --bindings test/binding.yaml + ``` + + This produces the output: + ``` + Loading policies ... + Loading bindings ... + - analyzer -> map[resource:map[type:terraform-plan]] + Loading payload ... + Pre processing ... + Running ( evaluating 1 resource against 1 policy ) ... + - check-ecs-exec-logging / check-ecs-exec-logging / FAILED + -> ECS Exec must have logging enabled + -> all[0].check.~.(planned_values.root_module.resources[?type=='aws_ecs_cluster'])[0].values.~.(configuration[].execute_command_configuration[])[0].(logging != 'NONE'): Invalid value: false: Expected value: true + Done + ``` + +--- diff --git a/terraform/plan/ecs-best-practices/check-ecs-exec-logging/check-ecs-exec-logging.yaml b/terraform/plan/ecs-best-practices/check-ecs-exec-logging/check-ecs-exec-logging.yaml new file mode 100644 index 00000000..dfa9cf52 --- /dev/null +++ b/terraform/plan/ecs-best-practices/check-ecs-exec-logging/check-ecs-exec-logging.yaml @@ -0,0 +1,33 @@ +apiVersion: json.kyverno.io/v1alpha1 +kind: ValidatingPolicy +metadata: + name: check-ecs-exec-logging + annotations: + policies.kyverno.io/title: Check ECS Cluster Logging + policies.kyverno.io/category: ECS Best Practices + policies.kyverno.io/severity: medium + policies.kyverno.io/description: >- + With Amazon ECS Exec, you can directly interact with containers without needing to + first interact with the host container operating system, open inbound ports, or manage SSH keys. + You can use ECS Exec to run commands in or get a shell to a container running on an Amazon EC2 instance or on AWS Fargate. + This makes it easier to collect diagnostic information and quickly troubleshoot errors. + For example, in a development context, you can use ECS Exec to easily interact with various process in your containers and troubleshoot your applications. + And in production scenarios, you can use it to gain break-glass access to your containers to debug issues. + You can audit which user accessed the container using the `ExecuteCommand` event in AWS CloudTrail and log each command (and their output) to Amazon S3 or Amazon CloudWatch Logs. + Amazon ECS provides a default configuration for logging commands run using ECS Exec by sending logs to CloudWatch Logs using the `awslogs` log driver that's configured in your task definition. + This policy validates if logging is enabled for the commands executed in the ECS Cluster. It fails if logging is set to None. +spec: + rules: + - name: check-ecs-exec-logging + match: + all: + - ($analyzer.resource.type): terraform-plan + - (planned_values.root_module.resources[?type=='aws_ecs_cluster'] | length(@) > `0`): true + assert: + all: + - message: ECS Exec must have logging enabled + check: + ~.(planned_values.root_module.resources[?type=='aws_ecs_cluster']): + values: + ~.(configuration[].execute_command_configuration[]): + (logging != 'NONE'): true diff --git a/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/bad-test/bad-01.tf b/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/bad-test/bad-01.tf new file mode 100644 index 00000000..87d8c7fb --- /dev/null +++ b/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/bad-test/bad-01.tf @@ -0,0 +1,29 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_cloudwatch_log_group" "example" { + name = "example" +} + +resource "aws_ecs_cluster" "test" { + name = "example" + + configuration { + execute_command_configuration { + logging = "NONE" + } + } +} + diff --git a/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/bad-test/bad-payload-01.json b/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/bad-test/bad-payload-01.json new file mode 100644 index 00000000..1b3a5549 --- /dev/null +++ b/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/bad-test/bad-payload-01.json @@ -0,0 +1,223 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_cloudwatch_log_group.example", + "mode": "managed", + "type": "aws_cloudwatch_log_group", + "name": "example", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 0, + "values": { + "kms_key_id": null, + "name": "example", + "retention_in_days": 0, + "skip_destroy": false, + "tags": null + }, + "sensitive_values": { + "tags_all": {} + } + }, + { + "address": "aws_ecs_cluster.test", + "mode": "managed", + "type": "aws_ecs_cluster", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 0, + "values": { + "configuration": [ + { + "execute_command_configuration": [ + { + "kms_key_id": null, + "log_configuration": [], + "logging": "NONE" + } + ], + "managed_storage_configuration": [] + } + ], + "name": "example", + "service_connect_defaults": [], + "tags": null + }, + "sensitive_values": { + "configuration": [ + { + "execute_command_configuration": [ + { + "log_configuration": [] + } + ], + "managed_storage_configuration": [] + } + ], + "service_connect_defaults": [], + "setting": [], + "tags_all": {} + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_cloudwatch_log_group.example", + "mode": "managed", + "type": "aws_cloudwatch_log_group", + "name": "example", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "kms_key_id": null, + "name": "example", + "retention_in_days": 0, + "skip_destroy": false, + "tags": null + }, + "after_unknown": { + "arn": true, + "id": true, + "log_group_class": true, + "name_prefix": true, + "tags_all": true + }, + "before_sensitive": false, + "after_sensitive": { + "tags_all": {} + } + } + }, + { + "address": "aws_ecs_cluster.test", + "mode": "managed", + "type": "aws_ecs_cluster", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "configuration": [ + { + "execute_command_configuration": [ + { + "kms_key_id": null, + "log_configuration": [], + "logging": "NONE" + } + ], + "managed_storage_configuration": [] + } + ], + "name": "example", + "service_connect_defaults": [], + "tags": null + }, + "after_unknown": { + "arn": true, + "configuration": [ + { + "execute_command_configuration": [ + { + "log_configuration": [] + } + ], + "managed_storage_configuration": [] + } + ], + "id": true, + "service_connect_defaults": [], + "setting": true, + "tags_all": true + }, + "before_sensitive": false, + "after_sensitive": { + "configuration": [ + { + "execute_command_configuration": [ + { + "log_configuration": [] + } + ], + "managed_storage_configuration": [] + } + ], + "service_connect_defaults": [], + "setting": [], + "tags_all": {} + } + } + } + ], + "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_cloudwatch_log_group.example", + "mode": "managed", + "type": "aws_cloudwatch_log_group", + "name": "example", + "provider_config_key": "aws", + "expressions": { + "name": { + "constant_value": "example" + } + }, + "schema_version": 0 + }, + { + "address": "aws_ecs_cluster.test", + "mode": "managed", + "type": "aws_ecs_cluster", + "name": "test", + "provider_config_key": "aws", + "expressions": { + "configuration": [ + { + "execute_command_configuration": [ + { + "logging": { + "constant_value": "NONE" + } + } + ] + } + ], + "name": { + "constant_value": "example" + } + }, + "schema_version": 0 + } + ] + } + }, + "timestamp": "2024-09-05T18:28:33Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/binding.yaml b/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/binding.yaml new file mode 100644 index 00000000..a3dd760d --- /dev/null +++ b/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/binding.yaml @@ -0,0 +1,3 @@ +analyzer: + resource: + type: terraform-plan \ No newline at end of file diff --git a/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/chainsaw-test.yaml b/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/chainsaw-test.yaml new file mode 100644 index 00000000..56c089d5 --- /dev/null +++ b/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/chainsaw-test.yaml @@ -0,0 +1,140 @@ +# 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 --policy ../check-ecs-exec-logging.yaml --payload ./good-test/good-payload-01.json --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-ecs-exec-logging + rules: + - rule: + name: check-ecs-exec-logging + 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 --policy ../check-ecs-exec-logging.yaml --payload ./good-test/good-payload-02.json --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-ecs-exec-logging + rules: + - rule: + name: check-ecs-exec-logging + error: ~ + violations: ~ +--- +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: good-test-03 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --policy ../check-ecs-exec-logging.yaml --payload ./good-test/good-payload-03.json --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-ecs-exec-logging + rules: + - rule: + name: check-ecs-exec-logging + error: ~ + violations: ~ +--- +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: good-test-04 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --policy ../check-ecs-exec-logging.yaml --payload ./good-test/good-payload-04.json --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-ecs-exec-logging + rules: + - rule: + name: check-ecs-exec-logging + 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 --policy ../check-ecs-exec-logging.yaml --payload ./bad-test/bad-payload-01.json --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-ecs-exec-logging + rules: + - rule: + name: check-ecs-exec-logging + error: ~ + violations: + - (contains(message, 'ECS Exec must have logging enabled')): true + errors: + - type: FieldValueInvalid + value: false + detail: 'Expected value: true' diff --git a/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/good-test/good-01.tf b/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/good-test/good-01.tf new file mode 100644 index 00000000..16277658 --- /dev/null +++ b/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/good-test/good-01.tf @@ -0,0 +1,33 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_cloudwatch_log_group" "example" { + name = "example" +} + +resource "aws_ecs_cluster" "test" { + name = "example" + + configuration { + execute_command_configuration { + logging = "OVERRIDE" + log_configuration { + cloud_watch_encryption_enabled = true + cloud_watch_log_group_name = aws_cloudwatch_log_group.example.name + } + } + } +} + diff --git a/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/good-test/good-02.tf b/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/good-test/good-02.tf new file mode 100644 index 00000000..678bf7e0 --- /dev/null +++ b/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/good-test/good-02.tf @@ -0,0 +1,29 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_cloudwatch_log_group" "example" { + name = "example" +} + +resource "aws_ecs_cluster" "test" { + name = "example" + + configuration { + execute_command_configuration { + logging = "DEFAULT" + } + } +} + diff --git a/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/good-test/good-03.tf b/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/good-test/good-03.tf new file mode 100644 index 00000000..5acee0de --- /dev/null +++ b/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/good-test/good-03.tf @@ -0,0 +1,28 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_cloudwatch_log_group" "example" { + name = "example" +} + +resource "aws_ecs_cluster" "test" { + name = "example" + + configuration { + execute_command_configuration { + } + } +} + diff --git a/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/good-test/good-04.tf b/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/good-test/good-04.tf new file mode 100644 index 00000000..7ca09edb --- /dev/null +++ b/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/good-test/good-04.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_cloudwatch_log_group" "example" { + name = "example" +} + +resource "aws_ecs_cluster" "test" { + name = "example" +} + diff --git a/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/good-test/good-payload-01.json b/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/good-test/good-payload-01.json new file mode 100644 index 00000000..bc119eb4 --- /dev/null +++ b/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/good-test/good-payload-01.json @@ -0,0 +1,266 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_cloudwatch_log_group.example", + "mode": "managed", + "type": "aws_cloudwatch_log_group", + "name": "example", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 0, + "values": { + "kms_key_id": null, + "name": "example", + "retention_in_days": 0, + "skip_destroy": false, + "tags": null + }, + "sensitive_values": { + "tags_all": {} + } + }, + { + "address": "aws_ecs_cluster.test", + "mode": "managed", + "type": "aws_ecs_cluster", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 0, + "values": { + "configuration": [ + { + "execute_command_configuration": [ + { + "kms_key_id": null, + "log_configuration": [ + { + "cloud_watch_encryption_enabled": true, + "cloud_watch_log_group_name": "example", + "s3_bucket_encryption_enabled": null, + "s3_bucket_name": null, + "s3_key_prefix": null + } + ], + "logging": "OVERRIDE" + } + ], + "managed_storage_configuration": [] + } + ], + "name": "example", + "service_connect_defaults": [], + "tags": null + }, + "sensitive_values": { + "configuration": [ + { + "execute_command_configuration": [ + { + "log_configuration": [ + {} + ] + } + ], + "managed_storage_configuration": [] + } + ], + "service_connect_defaults": [], + "setting": [], + "tags_all": {} + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_cloudwatch_log_group.example", + "mode": "managed", + "type": "aws_cloudwatch_log_group", + "name": "example", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "kms_key_id": null, + "name": "example", + "retention_in_days": 0, + "skip_destroy": false, + "tags": null + }, + "after_unknown": { + "arn": true, + "id": true, + "log_group_class": true, + "name_prefix": true, + "tags_all": true + }, + "before_sensitive": false, + "after_sensitive": { + "tags_all": {} + } + } + }, + { + "address": "aws_ecs_cluster.test", + "mode": "managed", + "type": "aws_ecs_cluster", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "configuration": [ + { + "execute_command_configuration": [ + { + "kms_key_id": null, + "log_configuration": [ + { + "cloud_watch_encryption_enabled": true, + "cloud_watch_log_group_name": "example", + "s3_bucket_encryption_enabled": null, + "s3_bucket_name": null, + "s3_key_prefix": null + } + ], + "logging": "OVERRIDE" + } + ], + "managed_storage_configuration": [] + } + ], + "name": "example", + "service_connect_defaults": [], + "tags": null + }, + "after_unknown": { + "arn": true, + "configuration": [ + { + "execute_command_configuration": [ + { + "log_configuration": [ + {} + ] + } + ], + "managed_storage_configuration": [] + } + ], + "id": true, + "service_connect_defaults": [], + "setting": true, + "tags_all": true + }, + "before_sensitive": false, + "after_sensitive": { + "configuration": [ + { + "execute_command_configuration": [ + { + "log_configuration": [ + {} + ] + } + ], + "managed_storage_configuration": [] + } + ], + "service_connect_defaults": [], + "setting": [], + "tags_all": {} + } + } + } + ], + "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_cloudwatch_log_group.example", + "mode": "managed", + "type": "aws_cloudwatch_log_group", + "name": "example", + "provider_config_key": "aws", + "expressions": { + "name": { + "constant_value": "example" + } + }, + "schema_version": 0 + }, + { + "address": "aws_ecs_cluster.test", + "mode": "managed", + "type": "aws_ecs_cluster", + "name": "test", + "provider_config_key": "aws", + "expressions": { + "configuration": [ + { + "execute_command_configuration": [ + { + "log_configuration": [ + { + "cloud_watch_encryption_enabled": { + "constant_value": true + }, + "cloud_watch_log_group_name": { + "references": [ + "aws_cloudwatch_log_group.example.name", + "aws_cloudwatch_log_group.example" + ] + } + } + ], + "logging": { + "constant_value": "OVERRIDE" + } + } + ] + } + ], + "name": { + "constant_value": "example" + } + }, + "schema_version": 0 + } + ] + } + }, + "relevant_attributes": [ + { + "resource": "aws_cloudwatch_log_group.example", + "attribute": [ + "name" + ] + } + ], + "timestamp": "2024-09-05T19:05:59Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/good-test/good-payload-02.json b/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/good-test/good-payload-02.json new file mode 100644 index 00000000..578672fb --- /dev/null +++ b/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/good-test/good-payload-02.json @@ -0,0 +1,223 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_cloudwatch_log_group.example", + "mode": "managed", + "type": "aws_cloudwatch_log_group", + "name": "example", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 0, + "values": { + "kms_key_id": null, + "name": "example", + "retention_in_days": 0, + "skip_destroy": false, + "tags": null + }, + "sensitive_values": { + "tags_all": {} + } + }, + { + "address": "aws_ecs_cluster.test", + "mode": "managed", + "type": "aws_ecs_cluster", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 0, + "values": { + "configuration": [ + { + "execute_command_configuration": [ + { + "kms_key_id": null, + "log_configuration": [], + "logging": "DEFAULT" + } + ], + "managed_storage_configuration": [] + } + ], + "name": "example", + "service_connect_defaults": [], + "tags": null + }, + "sensitive_values": { + "configuration": [ + { + "execute_command_configuration": [ + { + "log_configuration": [] + } + ], + "managed_storage_configuration": [] + } + ], + "service_connect_defaults": [], + "setting": [], + "tags_all": {} + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_cloudwatch_log_group.example", + "mode": "managed", + "type": "aws_cloudwatch_log_group", + "name": "example", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "kms_key_id": null, + "name": "example", + "retention_in_days": 0, + "skip_destroy": false, + "tags": null + }, + "after_unknown": { + "arn": true, + "id": true, + "log_group_class": true, + "name_prefix": true, + "tags_all": true + }, + "before_sensitive": false, + "after_sensitive": { + "tags_all": {} + } + } + }, + { + "address": "aws_ecs_cluster.test", + "mode": "managed", + "type": "aws_ecs_cluster", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "configuration": [ + { + "execute_command_configuration": [ + { + "kms_key_id": null, + "log_configuration": [], + "logging": "DEFAULT" + } + ], + "managed_storage_configuration": [] + } + ], + "name": "example", + "service_connect_defaults": [], + "tags": null + }, + "after_unknown": { + "arn": true, + "configuration": [ + { + "execute_command_configuration": [ + { + "log_configuration": [] + } + ], + "managed_storage_configuration": [] + } + ], + "id": true, + "service_connect_defaults": [], + "setting": true, + "tags_all": true + }, + "before_sensitive": false, + "after_sensitive": { + "configuration": [ + { + "execute_command_configuration": [ + { + "log_configuration": [] + } + ], + "managed_storage_configuration": [] + } + ], + "service_connect_defaults": [], + "setting": [], + "tags_all": {} + } + } + } + ], + "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_cloudwatch_log_group.example", + "mode": "managed", + "type": "aws_cloudwatch_log_group", + "name": "example", + "provider_config_key": "aws", + "expressions": { + "name": { + "constant_value": "example" + } + }, + "schema_version": 0 + }, + { + "address": "aws_ecs_cluster.test", + "mode": "managed", + "type": "aws_ecs_cluster", + "name": "test", + "provider_config_key": "aws", + "expressions": { + "configuration": [ + { + "execute_command_configuration": [ + { + "logging": { + "constant_value": "DEFAULT" + } + } + ] + } + ], + "name": { + "constant_value": "example" + } + }, + "schema_version": 0 + } + ] + } + }, + "timestamp": "2024-09-05T19:07:02Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/good-test/good-payload-03.json b/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/good-test/good-payload-03.json new file mode 100644 index 00000000..521c8370 --- /dev/null +++ b/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/good-test/good-payload-03.json @@ -0,0 +1,219 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_cloudwatch_log_group.example", + "mode": "managed", + "type": "aws_cloudwatch_log_group", + "name": "example", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 0, + "values": { + "kms_key_id": null, + "name": "example", + "retention_in_days": 0, + "skip_destroy": false, + "tags": null + }, + "sensitive_values": { + "tags_all": {} + } + }, + { + "address": "aws_ecs_cluster.test", + "mode": "managed", + "type": "aws_ecs_cluster", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 0, + "values": { + "configuration": [ + { + "execute_command_configuration": [ + { + "kms_key_id": null, + "log_configuration": [], + "logging": "DEFAULT" + } + ], + "managed_storage_configuration": [] + } + ], + "name": "example", + "service_connect_defaults": [], + "tags": null + }, + "sensitive_values": { + "configuration": [ + { + "execute_command_configuration": [ + { + "log_configuration": [] + } + ], + "managed_storage_configuration": [] + } + ], + "service_connect_defaults": [], + "setting": [], + "tags_all": {} + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_cloudwatch_log_group.example", + "mode": "managed", + "type": "aws_cloudwatch_log_group", + "name": "example", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "kms_key_id": null, + "name": "example", + "retention_in_days": 0, + "skip_destroy": false, + "tags": null + }, + "after_unknown": { + "arn": true, + "id": true, + "log_group_class": true, + "name_prefix": true, + "tags_all": true + }, + "before_sensitive": false, + "after_sensitive": { + "tags_all": {} + } + } + }, + { + "address": "aws_ecs_cluster.test", + "mode": "managed", + "type": "aws_ecs_cluster", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "configuration": [ + { + "execute_command_configuration": [ + { + "kms_key_id": null, + "log_configuration": [], + "logging": "DEFAULT" + } + ], + "managed_storage_configuration": [] + } + ], + "name": "example", + "service_connect_defaults": [], + "tags": null + }, + "after_unknown": { + "arn": true, + "configuration": [ + { + "execute_command_configuration": [ + { + "log_configuration": [] + } + ], + "managed_storage_configuration": [] + } + ], + "id": true, + "service_connect_defaults": [], + "setting": true, + "tags_all": true + }, + "before_sensitive": false, + "after_sensitive": { + "configuration": [ + { + "execute_command_configuration": [ + { + "log_configuration": [] + } + ], + "managed_storage_configuration": [] + } + ], + "service_connect_defaults": [], + "setting": [], + "tags_all": {} + } + } + } + ], + "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_cloudwatch_log_group.example", + "mode": "managed", + "type": "aws_cloudwatch_log_group", + "name": "example", + "provider_config_key": "aws", + "expressions": { + "name": { + "constant_value": "example" + } + }, + "schema_version": 0 + }, + { + "address": "aws_ecs_cluster.test", + "mode": "managed", + "type": "aws_ecs_cluster", + "name": "test", + "provider_config_key": "aws", + "expressions": { + "configuration": [ + { + "execute_command_configuration": [ + {} + ] + } + ], + "name": { + "constant_value": "example" + } + }, + "schema_version": 0 + } + ] + } + }, + "timestamp": "2024-09-05T19:07:58Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/good-test/good-payload-04.json b/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/good-test/good-payload-04.json new file mode 100644 index 00000000..a5fa8eb1 --- /dev/null +++ b/terraform/plan/ecs-best-practices/check-ecs-exec-logging/test/good-test/good-payload-04.json @@ -0,0 +1,163 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_cloudwatch_log_group.example", + "mode": "managed", + "type": "aws_cloudwatch_log_group", + "name": "example", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 0, + "values": { + "kms_key_id": null, + "name": "example", + "retention_in_days": 0, + "skip_destroy": false, + "tags": null + }, + "sensitive_values": { + "tags_all": {} + } + }, + { + "address": "aws_ecs_cluster.test", + "mode": "managed", + "type": "aws_ecs_cluster", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 0, + "values": { + "configuration": [], + "name": "example", + "service_connect_defaults": [], + "tags": null + }, + "sensitive_values": { + "configuration": [], + "service_connect_defaults": [], + "setting": [], + "tags_all": {} + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_cloudwatch_log_group.example", + "mode": "managed", + "type": "aws_cloudwatch_log_group", + "name": "example", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "kms_key_id": null, + "name": "example", + "retention_in_days": 0, + "skip_destroy": false, + "tags": null + }, + "after_unknown": { + "arn": true, + "id": true, + "log_group_class": true, + "name_prefix": true, + "tags_all": true + }, + "before_sensitive": false, + "after_sensitive": { + "tags_all": {} + } + } + }, + { + "address": "aws_ecs_cluster.test", + "mode": "managed", + "type": "aws_ecs_cluster", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "configuration": [], + "name": "example", + "service_connect_defaults": [], + "tags": null + }, + "after_unknown": { + "arn": true, + "configuration": [], + "id": true, + "service_connect_defaults": [], + "setting": true, + "tags_all": true + }, + "before_sensitive": false, + "after_sensitive": { + "configuration": [], + "service_connect_defaults": [], + "setting": [], + "tags_all": {} + } + } + } + ], + "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_cloudwatch_log_group.example", + "mode": "managed", + "type": "aws_cloudwatch_log_group", + "name": "example", + "provider_config_key": "aws", + "expressions": { + "name": { + "constant_value": "example" + } + }, + "schema_version": 0 + }, + { + "address": "aws_ecs_cluster.test", + "mode": "managed", + "type": "aws_ecs_cluster", + "name": "test", + "provider_config_key": "aws", + "expressions": { + "name": { + "constant_value": "example" + } + }, + "schema_version": 0 + } + ] + } + }, + "timestamp": "2024-09-06T03:33:28Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/ecs-best-practices/check-ecs-service-on-latest-fargate/README.md b/terraform/plan/ecs-best-practices/check-ecs-service-on-latest-fargate/README.md new file mode 100644 index 00000000..7fa54c2f --- /dev/null +++ b/terraform/plan/ecs-best-practices/check-ecs-service-on-latest-fargate/README.md @@ -0,0 +1,69 @@ +# Check ECS Service on Latest FARGATE +AWS Fargate platform versions are used to refer to a specific runtime environment for Fargate task infrastructure. +It is a combination of the kernel and container runtime versions. You select a platform version when you run a task or when you create a service to maintain a number of identical tasks. New revisions of platform versions are released as the runtime environment evolves, for example, if there are kernel or operating system updates, new features, bug fixes, or security updates. A Fargate platform version is updated by making a new platform version revision. Each task runs on one platform version revision during its lifecycle. +If you want to use the latest platform version revision, then you must start a new task. A new task that runs on Fargate always runs on the latest revision of a platform version, this ensures that tasks are always started on secure and patched infrastructure. +This policy ensures the AWS ECS services are running on the latest Fargate platform version + +### 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:** + ``` + kyverno-json scan --payload payload.json --policy policy.yaml + ``` + + a. **Test Policy Against Valid Payload:** + ``` + kyverno-json scan --policy check-ecs-service-on-latest-fargate.yaml --payload test/good-test/good-payload-01.json --bindings test/binding.yaml + ``` + + This produces the output: + ``` + Loading policies ... + Loading bindings ... + - analyzer -> map[resource:map[type:terraform-plan]] + Loading payload ... + Pre processing ... + Running ( evaluating 1 resource against 1 policy ) ... + - check-ecs-service-on-latest-fargate / check-ecs-service-on-latest-fargate / PASSED + Done + ``` + + b. **Test Against Invalid Payload:** + ``` + kyverno-json scan --policy check-ecs-service-on-latest-fargate.yaml --payload test/bad-test/bad-payload-01.json --bindings test/binding.yaml + ``` + + This produces the output: + ``` + Loading policies ... + Loading bindings ... + - analyzer -> map[resource:map[type:terraform-plan]] + Loading payload ... + Pre processing ... + Running ( evaluating 1 resource against 1 policy ) ... + - check-ecs-service-on-latest-fargate / check-ecs-service-on-latest-fargate / FAILED + -> ECS services must run on the latest Fargate platform version + -> all[0].check.~.(planned_values.root_module.resources[?type=='aws_ecs_service'])[0].values.(platform_version == null || platform_version == 'LATEST'): Invalid value: false: Expected value: true + Done + ``` + +--- diff --git a/terraform/plan/ecs-best-practices/check-ecs-service-on-latest-fargate/check-ecs-service-on-latest-fargate.yaml b/terraform/plan/ecs-best-practices/check-ecs-service-on-latest-fargate/check-ecs-service-on-latest-fargate.yaml new file mode 100644 index 00000000..31c419a8 --- /dev/null +++ b/terraform/plan/ecs-best-practices/check-ecs-service-on-latest-fargate/check-ecs-service-on-latest-fargate.yaml @@ -0,0 +1,33 @@ +apiVersion: json.kyverno.io/v1alpha1 +kind: ValidatingPolicy +metadata: + name: check-ecs-service-on-latest-fargate + annotations: + policies.kyverno.io/title: Check ECS Service on Latest FARGATE + policies.kyverno.io/category: ECS Best Practices + policies.kyverno.io/severity: medium + policies.kyverno.io/description: >- + AWS Fargate platform versions are used to refer to a specific runtime environment for Fargate task infrastructure. + It is a combination of the kernel and container runtime versions. You select a platform version when you run a task or when you create a service to maintain a number of identical tasks. + New revisions of platform versions are released as the runtime environment evolves, for example, if there are kernel or operating system updates, new features, bug fixes, or security updates. + A Fargate platform version is updated by making a new platform version revision. Each task runs on one platform version revision during its lifecycle. + If you want to use the latest platform version revision, then you must start a new task. + A new task that runs on Fargate always runs on the latest revision of a platform version, this ensures that tasks are always started on secure and patched infrastructure. + This policy ensures the AWS ECS services are running on the latest Fargate platform version +spec: + rules: + - name: check-ecs-service-on-latest-fargate + match: + all: + - ($analyzer.resource.type): terraform-plan + - (planned_values.root_module.resources[?type=='aws_ecs_service'] | length(@) > `0`): true + - ~.(planned_values.root_module.resources[?type=='aws_ecs_service']): + values: + launch_type: FARGATE + assert: + all: + - message: ECS services must run on the latest Fargate platform version + check: + ~.(planned_values.root_module.resources[?type=='aws_ecs_service']): + values: + (platform_version == null || platform_version == 'LATEST'): true diff --git a/terraform/plan/ecs-best-practices/check-ecs-service-on-latest-fargate/test/bad-test/bad-01.tf b/terraform/plan/ecs-best-practices/check-ecs-service-on-latest-fargate/test/bad-test/bad-01.tf new file mode 100644 index 00000000..ce8e9ed7 --- /dev/null +++ b/terraform/plan/ecs-best-practices/check-ecs-service-on-latest-fargate/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_ecs_cluster" "example_cluster" { + name = "example-cluster" +} + +resource "aws_ecs_service" "example" { + name = "example" + launch_type = "FARGATE" + platform_version = "1.3.0" + cluster = aws_ecs_cluster.example_cluster.id +} diff --git a/terraform/plan/ecs-best-practices/check-ecs-service-on-latest-fargate/test/bad-test/bad-payload-01.json b/terraform/plan/ecs-best-practices/check-ecs-service-on-latest-fargate/test/bad-test/bad-payload-01.json new file mode 100644 index 00000000..ea55589a --- /dev/null +++ b/terraform/plan/ecs-best-practices/check-ecs-service-on-latest-fargate/test/bad-test/bad-payload-01.json @@ -0,0 +1,264 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_ecs_cluster.example_cluster", + "mode": "managed", + "type": "aws_ecs_cluster", + "name": "example_cluster", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 0, + "values": { + "configuration": [], + "name": "example-cluster", + "service_connect_defaults": [], + "tags": null + }, + "sensitive_values": { + "configuration": [], + "service_connect_defaults": [], + "setting": [], + "tags_all": {} + } + }, + { + "address": "aws_ecs_service.example", + "mode": "managed", + "type": "aws_ecs_service", + "name": "example", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 1, + "values": { + "alarms": [], + "capacity_provider_strategy": [], + "deployment_circuit_breaker": [], + "deployment_controller": [], + "deployment_maximum_percent": 200, + "deployment_minimum_healthy_percent": 100, + "desired_count": null, + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "force_delete": null, + "force_new_deployment": null, + "health_check_grace_period_seconds": null, + "launch_type": "FARGATE", + "load_balancer": [], + "name": "example", + "network_configuration": [], + "ordered_placement_strategy": [], + "placement_constraints": [], + "platform_version": "1.3.0", + "propagate_tags": null, + "scheduling_strategy": "REPLICA", + "service_connect_configuration": [], + "service_registries": [], + "tags": null, + "task_definition": null, + "timeouts": null, + "volume_configuration": [], + "wait_for_steady_state": false + }, + "sensitive_values": { + "alarms": [], + "capacity_provider_strategy": [], + "deployment_circuit_breaker": [], + "deployment_controller": [], + "load_balancer": [], + "network_configuration": [], + "ordered_placement_strategy": [], + "placement_constraints": [], + "service_connect_configuration": [], + "service_registries": [], + "tags_all": {}, + "triggers": {}, + "volume_configuration": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_ecs_cluster.example_cluster", + "mode": "managed", + "type": "aws_ecs_cluster", + "name": "example_cluster", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "configuration": [], + "name": "example-cluster", + "service_connect_defaults": [], + "tags": null + }, + "after_unknown": { + "arn": true, + "configuration": [], + "id": true, + "service_connect_defaults": [], + "setting": true, + "tags_all": true + }, + "before_sensitive": false, + "after_sensitive": { + "configuration": [], + "service_connect_defaults": [], + "setting": [], + "tags_all": {} + } + } + }, + { + "address": "aws_ecs_service.example", + "mode": "managed", + "type": "aws_ecs_service", + "name": "example", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "alarms": [], + "capacity_provider_strategy": [], + "deployment_circuit_breaker": [], + "deployment_controller": [], + "deployment_maximum_percent": 200, + "deployment_minimum_healthy_percent": 100, + "desired_count": null, + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "force_delete": null, + "force_new_deployment": null, + "health_check_grace_period_seconds": null, + "launch_type": "FARGATE", + "load_balancer": [], + "name": "example", + "network_configuration": [], + "ordered_placement_strategy": [], + "placement_constraints": [], + "platform_version": "1.3.0", + "propagate_tags": null, + "scheduling_strategy": "REPLICA", + "service_connect_configuration": [], + "service_registries": [], + "tags": null, + "task_definition": null, + "timeouts": null, + "volume_configuration": [], + "wait_for_steady_state": false + }, + "after_unknown": { + "alarms": [], + "capacity_provider_strategy": [], + "cluster": true, + "deployment_circuit_breaker": [], + "deployment_controller": [], + "iam_role": true, + "id": true, + "load_balancer": [], + "network_configuration": [], + "ordered_placement_strategy": [], + "placement_constraints": [], + "service_connect_configuration": [], + "service_registries": [], + "tags_all": true, + "triggers": true, + "volume_configuration": [] + }, + "before_sensitive": false, + "after_sensitive": { + "alarms": [], + "capacity_provider_strategy": [], + "deployment_circuit_breaker": [], + "deployment_controller": [], + "load_balancer": [], + "network_configuration": [], + "ordered_placement_strategy": [], + "placement_constraints": [], + "service_connect_configuration": [], + "service_registries": [], + "tags_all": {}, + "triggers": {}, + "volume_configuration": [] + } + } + } + ], + "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_ecs_cluster.example_cluster", + "mode": "managed", + "type": "aws_ecs_cluster", + "name": "example_cluster", + "provider_config_key": "aws", + "expressions": { + "name": { + "constant_value": "example-cluster" + } + }, + "schema_version": 0 + }, + { + "address": "aws_ecs_service.example", + "mode": "managed", + "type": "aws_ecs_service", + "name": "example", + "provider_config_key": "aws", + "expressions": { + "cluster": { + "references": [ + "aws_ecs_cluster.example_cluster.id", + "aws_ecs_cluster.example_cluster" + ] + }, + "launch_type": { + "constant_value": "FARGATE" + }, + "name": { + "constant_value": "example" + }, + "platform_version": { + "constant_value": "1.3.0" + } + }, + "schema_version": 1 + } + ] + } + }, + "relevant_attributes": [ + { + "resource": "aws_ecs_cluster.example_cluster", + "attribute": [ + "id" + ] + } + ], + "timestamp": "2024-09-06T04:02:21Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/ecs-best-practices/check-ecs-service-on-latest-fargate/test/binding.yaml b/terraform/plan/ecs-best-practices/check-ecs-service-on-latest-fargate/test/binding.yaml new file mode 100644 index 00000000..a3dd760d --- /dev/null +++ b/terraform/plan/ecs-best-practices/check-ecs-service-on-latest-fargate/test/binding.yaml @@ -0,0 +1,3 @@ +analyzer: + resource: + type: terraform-plan \ No newline at end of file diff --git a/terraform/plan/ecs-best-practices/check-ecs-service-on-latest-fargate/test/chainsaw-test.yaml b/terraform/plan/ecs-best-practices/check-ecs-service-on-latest-fargate/test/chainsaw-test.yaml new file mode 100644 index 00000000..45b787bb --- /dev/null +++ b/terraform/plan/ecs-best-practices/check-ecs-service-on-latest-fargate/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 --policy ../check-ecs-service-on-latest-fargate.yaml --payload ./good-test/good-payload-01.json --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-ecs-service-on-latest-fargate + rules: + - rule: + name: check-ecs-service-on-latest-fargate + 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 --policy ../check-ecs-service-on-latest-fargate.yaml --payload ./good-test/good-payload-02.json --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-ecs-service-on-latest-fargate + rules: + - rule: + name: check-ecs-service-on-latest-fargate + 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 --policy ../check-ecs-service-on-latest-fargate.yaml --payload ./bad-test/bad-payload-01.json --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-ecs-service-on-latest-fargate + rules: + - rule: + name: check-ecs-service-on-latest-fargate + error: ~ + violations: + - (contains(message, 'ECS services must run on the latest Fargate platform version')): true + errors: + - type: FieldValueInvalid + value: false + detail: 'Expected value: true' diff --git a/terraform/plan/ecs-best-practices/check-ecs-service-on-latest-fargate/test/good-test/good-01.tf b/terraform/plan/ecs-best-practices/check-ecs-service-on-latest-fargate/test/good-test/good-01.tf new file mode 100644 index 00000000..9e6fa4f6 --- /dev/null +++ b/terraform/plan/ecs-best-practices/check-ecs-service-on-latest-fargate/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_ecs_cluster" "example_cluster" { + name = "example-cluster" +} + +resource "aws_ecs_service" "example" { + name = "example" + launch_type = "FARGATE" + platform_version = "LATEST" + cluster = aws_ecs_cluster.example_cluster.id +} diff --git a/terraform/plan/ecs-best-practices/check-ecs-service-on-latest-fargate/test/good-test/good-02.tf b/terraform/plan/ecs-best-practices/check-ecs-service-on-latest-fargate/test/good-test/good-02.tf new file mode 100644 index 00000000..916024b7 --- /dev/null +++ b/terraform/plan/ecs-best-practices/check-ecs-service-on-latest-fargate/test/good-test/good-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_ecs_cluster" "example_cluster" { + name = "example-cluster" +} + +resource "aws_ecs_service" "example" { + name = "example" + launch_type = "FARGATE" + cluster = aws_ecs_cluster.example_cluster.id +} diff --git a/terraform/plan/ecs-best-practices/check-ecs-service-on-latest-fargate/test/good-test/good-payload-01.json b/terraform/plan/ecs-best-practices/check-ecs-service-on-latest-fargate/test/good-test/good-payload-01.json new file mode 100644 index 00000000..11d67ce8 --- /dev/null +++ b/terraform/plan/ecs-best-practices/check-ecs-service-on-latest-fargate/test/good-test/good-payload-01.json @@ -0,0 +1,264 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_ecs_cluster.example_cluster", + "mode": "managed", + "type": "aws_ecs_cluster", + "name": "example_cluster", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 0, + "values": { + "configuration": [], + "name": "example-cluster", + "service_connect_defaults": [], + "tags": null + }, + "sensitive_values": { + "configuration": [], + "service_connect_defaults": [], + "setting": [], + "tags_all": {} + } + }, + { + "address": "aws_ecs_service.example", + "mode": "managed", + "type": "aws_ecs_service", + "name": "example", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 1, + "values": { + "alarms": [], + "capacity_provider_strategy": [], + "deployment_circuit_breaker": [], + "deployment_controller": [], + "deployment_maximum_percent": 200, + "deployment_minimum_healthy_percent": 100, + "desired_count": null, + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "force_delete": null, + "force_new_deployment": null, + "health_check_grace_period_seconds": null, + "launch_type": "FARGATE", + "load_balancer": [], + "name": "example", + "network_configuration": [], + "ordered_placement_strategy": [], + "placement_constraints": [], + "platform_version": "LATEST", + "propagate_tags": null, + "scheduling_strategy": "REPLICA", + "service_connect_configuration": [], + "service_registries": [], + "tags": null, + "task_definition": null, + "timeouts": null, + "volume_configuration": [], + "wait_for_steady_state": false + }, + "sensitive_values": { + "alarms": [], + "capacity_provider_strategy": [], + "deployment_circuit_breaker": [], + "deployment_controller": [], + "load_balancer": [], + "network_configuration": [], + "ordered_placement_strategy": [], + "placement_constraints": [], + "service_connect_configuration": [], + "service_registries": [], + "tags_all": {}, + "triggers": {}, + "volume_configuration": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_ecs_cluster.example_cluster", + "mode": "managed", + "type": "aws_ecs_cluster", + "name": "example_cluster", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "configuration": [], + "name": "example-cluster", + "service_connect_defaults": [], + "tags": null + }, + "after_unknown": { + "arn": true, + "configuration": [], + "id": true, + "service_connect_defaults": [], + "setting": true, + "tags_all": true + }, + "before_sensitive": false, + "after_sensitive": { + "configuration": [], + "service_connect_defaults": [], + "setting": [], + "tags_all": {} + } + } + }, + { + "address": "aws_ecs_service.example", + "mode": "managed", + "type": "aws_ecs_service", + "name": "example", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "alarms": [], + "capacity_provider_strategy": [], + "deployment_circuit_breaker": [], + "deployment_controller": [], + "deployment_maximum_percent": 200, + "deployment_minimum_healthy_percent": 100, + "desired_count": null, + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "force_delete": null, + "force_new_deployment": null, + "health_check_grace_period_seconds": null, + "launch_type": "FARGATE", + "load_balancer": [], + "name": "example", + "network_configuration": [], + "ordered_placement_strategy": [], + "placement_constraints": [], + "platform_version": "LATEST", + "propagate_tags": null, + "scheduling_strategy": "REPLICA", + "service_connect_configuration": [], + "service_registries": [], + "tags": null, + "task_definition": null, + "timeouts": null, + "volume_configuration": [], + "wait_for_steady_state": false + }, + "after_unknown": { + "alarms": [], + "capacity_provider_strategy": [], + "cluster": true, + "deployment_circuit_breaker": [], + "deployment_controller": [], + "iam_role": true, + "id": true, + "load_balancer": [], + "network_configuration": [], + "ordered_placement_strategy": [], + "placement_constraints": [], + "service_connect_configuration": [], + "service_registries": [], + "tags_all": true, + "triggers": true, + "volume_configuration": [] + }, + "before_sensitive": false, + "after_sensitive": { + "alarms": [], + "capacity_provider_strategy": [], + "deployment_circuit_breaker": [], + "deployment_controller": [], + "load_balancer": [], + "network_configuration": [], + "ordered_placement_strategy": [], + "placement_constraints": [], + "service_connect_configuration": [], + "service_registries": [], + "tags_all": {}, + "triggers": {}, + "volume_configuration": [] + } + } + } + ], + "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_ecs_cluster.example_cluster", + "mode": "managed", + "type": "aws_ecs_cluster", + "name": "example_cluster", + "provider_config_key": "aws", + "expressions": { + "name": { + "constant_value": "example-cluster" + } + }, + "schema_version": 0 + }, + { + "address": "aws_ecs_service.example", + "mode": "managed", + "type": "aws_ecs_service", + "name": "example", + "provider_config_key": "aws", + "expressions": { + "cluster": { + "references": [ + "aws_ecs_cluster.example_cluster.id", + "aws_ecs_cluster.example_cluster" + ] + }, + "launch_type": { + "constant_value": "FARGATE" + }, + "name": { + "constant_value": "example" + }, + "platform_version": { + "constant_value": "LATEST" + } + }, + "schema_version": 1 + } + ] + } + }, + "relevant_attributes": [ + { + "resource": "aws_ecs_cluster.example_cluster", + "attribute": [ + "id" + ] + } + ], + "timestamp": "2024-09-06T03:56:35Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/ecs-best-practices/check-ecs-service-on-latest-fargate/test/good-test/good-payload-02.json b/terraform/plan/ecs-best-practices/check-ecs-service-on-latest-fargate/test/good-test/good-payload-02.json new file mode 100644 index 00000000..5f1192a8 --- /dev/null +++ b/terraform/plan/ecs-best-practices/check-ecs-service-on-latest-fargate/test/good-test/good-payload-02.json @@ -0,0 +1,260 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_ecs_cluster.example_cluster", + "mode": "managed", + "type": "aws_ecs_cluster", + "name": "example_cluster", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 0, + "values": { + "configuration": [], + "name": "example-cluster", + "service_connect_defaults": [], + "tags": null + }, + "sensitive_values": { + "configuration": [], + "service_connect_defaults": [], + "setting": [], + "tags_all": {} + } + }, + { + "address": "aws_ecs_service.example", + "mode": "managed", + "type": "aws_ecs_service", + "name": "example", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 1, + "values": { + "alarms": [], + "capacity_provider_strategy": [], + "deployment_circuit_breaker": [], + "deployment_controller": [], + "deployment_maximum_percent": 200, + "deployment_minimum_healthy_percent": 100, + "desired_count": null, + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "force_delete": null, + "force_new_deployment": null, + "health_check_grace_period_seconds": null, + "launch_type": "FARGATE", + "load_balancer": [], + "name": "example", + "network_configuration": [], + "ordered_placement_strategy": [], + "placement_constraints": [], + "propagate_tags": null, + "scheduling_strategy": "REPLICA", + "service_connect_configuration": [], + "service_registries": [], + "tags": null, + "task_definition": null, + "timeouts": null, + "volume_configuration": [], + "wait_for_steady_state": false + }, + "sensitive_values": { + "alarms": [], + "capacity_provider_strategy": [], + "deployment_circuit_breaker": [], + "deployment_controller": [], + "load_balancer": [], + "network_configuration": [], + "ordered_placement_strategy": [], + "placement_constraints": [], + "service_connect_configuration": [], + "service_registries": [], + "tags_all": {}, + "triggers": {}, + "volume_configuration": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_ecs_cluster.example_cluster", + "mode": "managed", + "type": "aws_ecs_cluster", + "name": "example_cluster", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "configuration": [], + "name": "example-cluster", + "service_connect_defaults": [], + "tags": null + }, + "after_unknown": { + "arn": true, + "configuration": [], + "id": true, + "service_connect_defaults": [], + "setting": true, + "tags_all": true + }, + "before_sensitive": false, + "after_sensitive": { + "configuration": [], + "service_connect_defaults": [], + "setting": [], + "tags_all": {} + } + } + }, + { + "address": "aws_ecs_service.example", + "mode": "managed", + "type": "aws_ecs_service", + "name": "example", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "alarms": [], + "capacity_provider_strategy": [], + "deployment_circuit_breaker": [], + "deployment_controller": [], + "deployment_maximum_percent": 200, + "deployment_minimum_healthy_percent": 100, + "desired_count": null, + "enable_ecs_managed_tags": false, + "enable_execute_command": false, + "force_delete": null, + "force_new_deployment": null, + "health_check_grace_period_seconds": null, + "launch_type": "FARGATE", + "load_balancer": [], + "name": "example", + "network_configuration": [], + "ordered_placement_strategy": [], + "placement_constraints": [], + "propagate_tags": null, + "scheduling_strategy": "REPLICA", + "service_connect_configuration": [], + "service_registries": [], + "tags": null, + "task_definition": null, + "timeouts": null, + "volume_configuration": [], + "wait_for_steady_state": false + }, + "after_unknown": { + "alarms": [], + "capacity_provider_strategy": [], + "cluster": true, + "deployment_circuit_breaker": [], + "deployment_controller": [], + "iam_role": true, + "id": true, + "load_balancer": [], + "network_configuration": [], + "ordered_placement_strategy": [], + "placement_constraints": [], + "platform_version": true, + "service_connect_configuration": [], + "service_registries": [], + "tags_all": true, + "triggers": true, + "volume_configuration": [] + }, + "before_sensitive": false, + "after_sensitive": { + "alarms": [], + "capacity_provider_strategy": [], + "deployment_circuit_breaker": [], + "deployment_controller": [], + "load_balancer": [], + "network_configuration": [], + "ordered_placement_strategy": [], + "placement_constraints": [], + "service_connect_configuration": [], + "service_registries": [], + "tags_all": {}, + "triggers": {}, + "volume_configuration": [] + } + } + } + ], + "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_ecs_cluster.example_cluster", + "mode": "managed", + "type": "aws_ecs_cluster", + "name": "example_cluster", + "provider_config_key": "aws", + "expressions": { + "name": { + "constant_value": "example-cluster" + } + }, + "schema_version": 0 + }, + { + "address": "aws_ecs_service.example", + "mode": "managed", + "type": "aws_ecs_service", + "name": "example", + "provider_config_key": "aws", + "expressions": { + "cluster": { + "references": [ + "aws_ecs_cluster.example_cluster.id", + "aws_ecs_cluster.example_cluster" + ] + }, + "launch_type": { + "constant_value": "FARGATE" + }, + "name": { + "constant_value": "example" + } + }, + "schema_version": 1 + } + ] + } + }, + "relevant_attributes": [ + { + "resource": "aws_ecs_cluster.example_cluster", + "attribute": [ + "id" + ] + } + ], + "timestamp": "2024-09-06T03:58:28Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/ecs-best-practices/validate-ecs-container-insights-enabled/README.md b/terraform/plan/ecs-best-practices/validate-ecs-container-insights-enabled/README.md new file mode 100644 index 00000000..0f14fa0a --- /dev/null +++ b/terraform/plan/ecs-best-practices/validate-ecs-container-insights-enabled/README.md @@ -0,0 +1,95 @@ +# Validate ECS Container Insights Policy + +Container Insights plays a crucial role in AWS ECS by providing diagnostic information, including details about container restart failures, aiding in the quick identification and resolution of issues. This policy, "validate-ecs-container-insights-enabled," ensures that ECS clusters have Container Insights enabled for effective monitoring and issue isolation. + +## Policy Details: + +- **Policy Name:** validate-ecs-container-insights-enabled +- **Check Description:** Verify if ECS clusters have Container Insights enabled. + +## Why it Matters: + +Container Insights enhances the operational visibility of ECS clusters, allowing for proactive issue resolution. Enabling this feature ensures that diagnostic information is readily available, contributing to a more efficient and reliable containerized environment. + +## How It Works: + +The policy checks the ECS clusters to confirm whether Container Insights are enabled. If Container Insights are not set up for a cluster, the policy marks it as non-compliant. + +### Validation Criteria: + +- **Condition:** `containerInsights` is set to `enabled` + - **Result:** PASS + +- **Condition:** `containerInsights` is set to `disabled` + - **Result:** FAIL + +- **Condition:** `containerInsights` is not present + - **Result:** FAIL + +### Policy Validation Testing Instructions + +To evaluate and test the policy, follow the steps outlined below: + +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:** + ``` + terraform init + ``` + +2. **Create Binary Terraform Plan:** + ``` + terraform plan -out tfplan.binary + ``` + +3. **Convert Binary to JSON Payload:** + ``` + terraform show -json tfplan.binary | jq > payload.json + ``` + +4. **Test the Policy with Kyverno:** + ``` + kyverno-json scan --payload payload.json --policy policy.yaml + ``` + + a. **Test Policy Against Valid Payload:** + ``` + kyverno-json scan --policy validate-ecs-container-insights-enabled.yaml --payload test/good-payload.json --bindings test/binding.yaml + ``` + + This produces the output: + ``` + Loading policies ... + Loading bindings ... + - analyzer -> map[resource:map[type:terraform-plan]] + Loading payload ... + Pre processing ... + Running ( evaluating 1 resource against 1 policy ) ... + - validate-ecs-container-insights-enabled / validate-ecs-container-insights-enabled / PASSED + Done + ``` + + b. **Test Against Invalid Payload:** + ``` + kyverno-json scan --policy validate-ecs-container-insights-enabled.yaml --payload test/bad-payload.json --bindings test/binding.yaml + ``` + + This produces the output: + ``` + Loading policies ... + Loading bindings ... + - analyzer -> map[resource:map[type:terraform-plan]] + Loading payload ... + Pre processing ... + Running ( evaluating 1 resource against 1 policy ) ... + - validate-ecs-container-insights-enabled / validate-ecs-container-insights-enabled / FAILED + -> ECS container insights are not enabled + -> all[0].check.~.(planned_values.root_module.resources[?type == 'aws_ecs_cluster'])[0].values.(!setting): Invalid value: true: Expected value: false + Done + ``` + +--- + +By enforcing this policy, you ensure that ECS clusters adhere to best practices in containerized environments by leveraging the capabilities of Container Insights for effective monitoring and issue resolution. diff --git a/terraform/plan/ecs-best-practices/validate-ecs-container-insights-enabled/test/bad-payload.json b/terraform/plan/ecs-best-practices/validate-ecs-container-insights-enabled/test/bad-payload.json new file mode 100644 index 00000000..0b031278 --- /dev/null +++ b/terraform/plan/ecs-best-practices/validate-ecs-container-insights-enabled/test/bad-payload.json @@ -0,0 +1,110 @@ +{ + "format_version": "1.2", + "terraform_version": "1.7.0-dev", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_ecs_cluster.foo", + "mode": "managed", + "type": "aws_ecs_cluster", + "name": "foo", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 0, + "values": { + "configuration": [], + "name": "white-hart", + "service_connect_defaults": [], + "tags": null + }, + "sensitive_values": { + "capacity_providers": [], + "configuration": [], + "default_capacity_provider_strategy": [], + "service_connect_defaults": [], + "setting": [], + "tags_all": {} + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_ecs_cluster.foo", + "mode": "managed", + "type": "aws_ecs_cluster", + "name": "foo", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "configuration": [], + "name": "white-hart", + "service_connect_defaults": [], + "tags": null + }, + "after_unknown": { + "arn": true, + "capacity_providers": true, + "configuration": [], + "default_capacity_provider_strategy": true, + "id": true, + "service_connect_defaults": [], + "setting": true, + "tags_all": true + }, + "before_sensitive": false, + "after_sensitive": { + "capacity_providers": [], + "configuration": [], + "default_capacity_provider_strategy": [], + "service_connect_defaults": [], + "setting": [], + "tags_all": {} + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": "~> 4.0", + "expressions": { + "region": { + "constant_value": "us-west-1" + } + } + }, + "docker": { + "name": "docker", + "full_name": "registry.terraform.io/kreuzwerker/docker", + "version_constraint": "~> 2.20.0" + } + }, + "root_module": { + "resources": [ + { + "address": "aws_ecs_cluster.foo", + "mode": "managed", + "type": "aws_ecs_cluster", + "name": "foo", + "provider_config_key": "aws", + "expressions": { + "name": { + "constant_value": "white-hart" + } + }, + "schema_version": 0 + } + ] + } + }, + "timestamp": "2024-01-18T17:47:42Z", + "errored": false + } diff --git a/terraform/plan/ecs-best-practices/validate-ecs-container-insights-enabled/test/bad.tf b/terraform/plan/ecs-best-practices/validate-ecs-container-insights-enabled/test/bad.tf new file mode 100644 index 00000000..afc9a7ec --- /dev/null +++ b/terraform/plan/ecs-best-practices/validate-ecs-container-insights-enabled/test/bad.tf @@ -0,0 +1,25 @@ +resource "aws_ecs_cluster" "foo" { + name = "white-hart" +} + +# Setting up the configuration for using Docker and AWS providers + +terraform { + required_providers { + docker = { + source = "kreuzwerker/docker" + version = "~>2.20.0" + } + aws = { + source = "hashicorp/aws" + version = "~> 4.0" + } + } +} + +# Configuring docker and AWS as providers +provider "docker" {} + +provider "aws" { + region = "us-west-1" +} diff --git a/terraform/plan/ecs-best-practices/validate-ecs-container-insights-enabled/test/binding.yaml b/terraform/plan/ecs-best-practices/validate-ecs-container-insights-enabled/test/binding.yaml new file mode 100644 index 00000000..a3dd760d --- /dev/null +++ b/terraform/plan/ecs-best-practices/validate-ecs-container-insights-enabled/test/binding.yaml @@ -0,0 +1,3 @@ +analyzer: + resource: + type: terraform-plan \ No newline at end of file diff --git a/terraform/plan/ecs-best-practices/validate-ecs-container-insights-enabled/test/chainsaw-test.yaml b/terraform/plan/ecs-best-practices/validate-ecs-container-insights-enabled/test/chainsaw-test.yaml new file mode 100644 index 00000000..aabe69ce --- /dev/null +++ b/terraform/plan/ecs-best-practices/validate-ecs-container-insights-enabled/test/chainsaw-test.yaml @@ -0,0 +1,60 @@ +# 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 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --policy ../validate-ecs-container-insights-enabled.yaml --payload good-payload.json --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: validate-ecs-container-insights-enabled + rules: + - rule: + name: validate-ecs-container-insights-enabled + error: ~ + violations: ~ +--- +# 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: bad-test +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --policy ../validate-ecs-container-insights-enabled.yaml --payload bad-payload.json --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: validate-ecs-container-insights-enabled + rules: + - rule: + name: validate-ecs-container-insights-enabled + error: ~ + violations: + - (contains(message, 'ECS container insights are not enabled')): true + errors: + - type: FieldValueInvalid + value: true + detail: 'Expected value: false' diff --git a/terraform/plan/ecs-best-practices/validate-ecs-container-insights-enabled/test/good-payload.json b/terraform/plan/ecs-best-practices/validate-ecs-container-insights-enabled/test/good-payload.json new file mode 100644 index 00000000..949a9134 --- /dev/null +++ b/terraform/plan/ecs-best-practices/validate-ecs-container-insights-enabled/test/good-payload.json @@ -0,0 +1,138 @@ +{ + "format_version": "1.2", + "terraform_version": "1.7.0-dev", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_ecs_cluster.foo", + "mode": "managed", + "type": "aws_ecs_cluster", + "name": "foo", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 0, + "values": { + "configuration": [], + "name": "white-hart", + "service_connect_defaults": [], + "setting": [ + { + "name": "containerInsights", + "value": "enabled" + } + ], + "tags": null + }, + "sensitive_values": { + "capacity_providers": [], + "configuration": [], + "default_capacity_provider_strategy": [], + "service_connect_defaults": [], + "setting": [ + {} + ], + "tags_all": {} + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_ecs_cluster.foo", + "mode": "managed", + "type": "aws_ecs_cluster", + "name": "foo", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "configuration": [], + "name": "white-hart", + "service_connect_defaults": [], + "setting": [ + { + "name": "containerInsights", + "value": "enabled" + } + ], + "tags": null + }, + "after_unknown": { + "arn": true, + "capacity_providers": true, + "configuration": [], + "default_capacity_provider_strategy": true, + "id": true, + "service_connect_defaults": [], + "setting": [ + {} + ], + "tags_all": true + }, + "before_sensitive": false, + "after_sensitive": { + "capacity_providers": [], + "configuration": [], + "default_capacity_provider_strategy": [], + "service_connect_defaults": [], + "setting": [ + {} + ], + "tags_all": {} + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": "~> 4.0", + "expressions": { + "region": { + "constant_value": "us-west-1" + } + } + }, + "docker": { + "name": "docker", + "full_name": "registry.terraform.io/kreuzwerker/docker", + "version_constraint": "~> 2.20.0" + } + }, + "root_module": { + "resources": [ + { + "address": "aws_ecs_cluster.foo", + "mode": "managed", + "type": "aws_ecs_cluster", + "name": "foo", + "provider_config_key": "aws", + "expressions": { + "name": { + "constant_value": "white-hart" + }, + "setting": [ + { + "name": { + "constant_value": "containerInsights" + }, + "value": { + "constant_value": "enabled" + } + } + ] + }, + "schema_version": 0 + } + ] + } + }, + "timestamp": "2024-01-18T15:48:00Z", + "errored": false + } diff --git a/terraform/plan/ecs-best-practices/validate-ecs-container-insights-enabled/test/good.tf b/terraform/plan/ecs-best-practices/validate-ecs-container-insights-enabled/test/good.tf new file mode 100644 index 00000000..5052109e --- /dev/null +++ b/terraform/plan/ecs-best-practices/validate-ecs-container-insights-enabled/test/good.tf @@ -0,0 +1,30 @@ +resource "aws_ecs_cluster" "foo" { + name = "white-hart" + + setting { + name = "containerInsights" + value = "enabled" + } +} + +# Setting up the configuration for using Docker and AWS providers + +terraform { + required_providers { + docker = { + source = "kreuzwerker/docker" + version = "~>2.20.0" + } + aws = { + source = "hashicorp/aws" + version = "~> 4.0" + } + } +} + +# Configuring docker and AWS as providers +provider "docker" {} + +provider "aws" { + region = "us-west-1" +} diff --git a/terraform/plan/ecs-best-practices/validate-ecs-container-insights-enabled/validate-ecs-container-insights-enabled.yaml b/terraform/plan/ecs-best-practices/validate-ecs-container-insights-enabled/validate-ecs-container-insights-enabled.yaml new file mode 100644 index 00000000..c9d2011a --- /dev/null +++ b/terraform/plan/ecs-best-practices/validate-ecs-container-insights-enabled/validate-ecs-container-insights-enabled.yaml @@ -0,0 +1,27 @@ +apiVersion: json.kyverno.io/v1alpha1 +kind: ValidatingPolicy +metadata: + name: validate-ecs-container-insights-enabled + annotations: + policies.kyverno.io/title: Validate ECS container insights are enabled + policies.kyverno.io/category: ECS Best Practices + policies.kyverno.io/severity: medium + policies.kyverno.io/description: >- + This Policy ensures that ECS clusters have container + insights enabled. +spec: + rules: + - name: validate-ecs-container-insights-enabled + match: + all: + - ($analyzer.resource.type): terraform-plan + - (planned_values.root_module.resources[?type=='aws_ecs_cluster'] | length(@) > `0`): true + assert: + all: + - message: ECS container insights are not enabled + check: + ~.(planned_values.root_module.resources[?type == 'aws_ecs_cluster']): + values: + (!setting): false + ~.(setting || `[]`): + value: enabled diff --git a/terraform/plan/ecs-best-practices/validate-efs-volume-encryption/README.md b/terraform/plan/ecs-best-practices/validate-efs-volume-encryption/README.md new file mode 100644 index 00000000..deec6dec --- /dev/null +++ b/terraform/plan/ecs-best-practices/validate-efs-volume-encryption/README.md @@ -0,0 +1,93 @@ +# Validate EFS Volume Encryption + +Amazon EFS file systems can be used with Amazon ECS to export file system data across your fleet of container instances. To ensure encryption is enabled in transit, this policy validates whether transit_encryption is set to ENABLED in the task definition. + +## Policy Details: + +- **Policy Name:** validate-efs-volume-encryption +- **Check Description:** Ensure Transit Encryption is enabled for EFS volumes in ECS Task definitions +- **Policy Category:** AWS ECS Best Practices + +## How It Works: + +### Validation Criteria: + +**Key** : transit_encryption +**Valid Values** : ENABLED | DISABLED +**Type** : string +**Required** : No + +- **Condition:** `transit_encryption` is set to `ENABLED` + - **Result:** PASS + - **Reason:** Transit Encryption is enabled for EFS volumes in ECS Task definitions + + +- **Condition:** `transit_encryption` is set to `DISABLED` + - **Result:** FAIL + - **Reason:** Transit Encryption is disabled for EFS volumes in ECS Task definitions + +- **Condition:** `transit_encryption` is omitted + - **Result:** FAIL + - **Reason:** If `transit_encryption` is omitted, the default value of DISABLED is used. + +### Policy Validation Testing Instructions + +To evaluate and test the policy ensuring ECS task definitions meet security standards: + +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 --policy validate-efs-volume-encryption.yaml --payload test/good-payload.json --bindings test/binding.yaml + ``` + + This produces the output: + ``` + Loading policies ... + Loading bindings ... + - analyzer -> map[resource:map[type:terraform-plan]] + Loading payload ... + Pre processing ... + Running ( evaluating 1 resource against 1 policy ) ... + - validate-efs-volume-encryption / validate-efs-volume-encryption / PASSED + Done + ``` + + b. **Test Against Invalid Payload:** + ```bash + kyverno-json scan --policy validate-efs-volume-encryption.yaml --payload test/bad-payload.json --bindings test/binding.yaml + ``` + + This produces the output: + ``` + Loading policies ... + Loading bindings ... + - analyzer -> map[resource:map[type:terraform-plan]] + Loading payload ... + Pre processing ... + Running ( evaluating 1 resource against 1 policy ) ... + - validate-efs-volume-encryption / validate-efs-volume-encryption / FAILED + -> Transit Encryption is not `ENABLED` for EFS volumes in ECS Task definitions + -> all[0].check.~.(planned_values.root_module.resources[?type=='aws_ecs_task_definition'])[0].~.(values.volume[] || `[]`)[0].~.(efs_volume_configuration[] || `[]`)[0].(transit_encryption == 'ENABLED'): Invalid value: false: Expected value: true + Done + ``` + +--- \ No newline at end of file diff --git a/terraform/plan/ecs-best-practices/validate-efs-volume-encryption/test/bad-payload.json b/terraform/plan/ecs-best-practices/validate-efs-volume-encryption/test/bad-payload.json new file mode 100644 index 00000000..439e12d4 --- /dev/null +++ b/terraform/plan/ecs-best-practices/validate-efs-volume-encryption/test/bad-payload.json @@ -0,0 +1,228 @@ +{ + "format_version": "1.2", + "terraform_version": "1.7.1-dev", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_ecs_task_definition.service", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "service", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 1, + "values": { + "container_definitions": "[{\"cpu\":512,\"essential\":true,\"image\":\"nginx:1.23.1\",\"memory\":2048,\"name\":\"foo-task\",\"portMappings\":[{\"containerPort\":80,\"hostPort\":80}]}]", + "cpu": null, + "ephemeral_storage": [], + "execution_role_arn": null, + "family": "service", + "inference_accelerator": [], + "ipc_mode": null, + "memory": null, + "pid_mode": null, + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": null, + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "task_role_arn": null, + "volume": [ + { + "docker_volume_configuration": [], + "efs_volume_configuration": [ + { + "authorization_config": [], + "file_system_id": "fs-0123456789abcdef0", + "root_directory": "/opt/data", + "transit_encryption": "", + "transit_encryption_port": 2999 + } + ], + "fsx_windows_file_server_volume_configuration": [], + "host_path": "", + "name": "service-storage" + } + ] + }, + "sensitive_values": { + "ephemeral_storage": [], + "inference_accelerator": [], + "placement_constraints": [], + "proxy_configuration": [], + "runtime_platform": [], + "tags_all": {}, + "volume": [ + { + "docker_volume_configuration": [], + "efs_volume_configuration": [ + { + "authorization_config": [] + } + ], + "fsx_windows_file_server_volume_configuration": [] + } + ] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_ecs_task_definition.service", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "service", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "container_definitions": "[{\"cpu\":512,\"essential\":true,\"image\":\"nginx:1.23.1\",\"memory\":2048,\"name\":\"foo-task\",\"portMappings\":[{\"containerPort\":80,\"hostPort\":80}]}]", + "cpu": null, + "ephemeral_storage": [], + "execution_role_arn": null, + "family": "service", + "inference_accelerator": [], + "ipc_mode": null, + "memory": null, + "pid_mode": null, + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": null, + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "task_role_arn": null, + "volume": [ + { + "docker_volume_configuration": [], + "efs_volume_configuration": [ + { + "authorization_config": [], + "file_system_id": "fs-0123456789abcdef0", + "root_directory": "/opt/data", + "transit_encryption": "", + "transit_encryption_port": 2999 + } + ], + "fsx_windows_file_server_volume_configuration": [], + "host_path": "", + "name": "service-storage" + } + ] + }, + "after_unknown": { + "arn": true, + "arn_without_revision": true, + "ephemeral_storage": [], + "id": true, + "inference_accelerator": [], + "network_mode": true, + "placement_constraints": [], + "proxy_configuration": [], + "revision": true, + "runtime_platform": [], + "tags_all": true, + "volume": [ + { + "docker_volume_configuration": [], + "efs_volume_configuration": [ + { + "authorization_config": [] + } + ], + "fsx_windows_file_server_volume_configuration": [] + } + ] + }, + "before_sensitive": false, + "after_sensitive": { + "ephemeral_storage": [], + "inference_accelerator": [], + "placement_constraints": [], + "proxy_configuration": [], + "runtime_platform": [], + "tags_all": {}, + "volume": [ + { + "docker_volume_configuration": [], + "efs_volume_configuration": [ + { + "authorization_config": [] + } + ], + "fsx_windows_file_server_volume_configuration": [] + } + ] + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": "~> 4.0", + "expressions": { + "region": { + "constant_value": "us-west-1" + } + } + }, + "docker": { + "name": "docker", + "full_name": "registry.terraform.io/kreuzwerker/docker", + "version_constraint": "~> 2.20.0" + } + }, + "root_module": { + "resources": [ + { + "address": "aws_ecs_task_definition.service", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "service", + "provider_config_key": "aws", + "expressions": { + "container_definitions": { + "constant_value": " [\n {\n \"name\" : \"foo-task\",\n \"image\" : \"nginx:1.23.1\",\n \"cpu\" : 512,\n \"memory\" : 2048,\n \"essential\" : true,\n \"portMappings\" : [\n {\n \"containerPort\" : 80,\n \"hostPort\" : 80\n }\n ]\n }\n ]\n" + }, + "family": { + "constant_value": "service" + }, + "volume": [ + { + "efs_volume_configuration": [ + { + "file_system_id": { + "constant_value": "fs-0123456789abcdef0" + }, + "root_directory": { + "constant_value": "/opt/data" + }, + "transit_encryption_port": { + "constant_value": 2999 + } + } + ], + "name": { + "constant_value": "service-storage" + } + } + ] + }, + "schema_version": 1 + } + ] + } + }, + "timestamp": "2024-01-30T13:31:07Z", + "errored": false + } + \ No newline at end of file diff --git a/terraform/plan/ecs-best-practices/validate-efs-volume-encryption/test/bad-payload1.json b/terraform/plan/ecs-best-practices/validate-efs-volume-encryption/test/bad-payload1.json new file mode 100644 index 00000000..78597db2 --- /dev/null +++ b/terraform/plan/ecs-best-practices/validate-efs-volume-encryption/test/bad-payload1.json @@ -0,0 +1,230 @@ +{ + "format_version": "1.2", + "terraform_version": "1.7.1-dev", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_ecs_task_definition.service", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "service", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 1, + "values": { + "container_definitions": "[{\"cpu\":512,\"essential\":true,\"image\":\"nginx:1.23.1\",\"memory\":2048,\"name\":\"foo-task\",\"portMappings\":[{\"containerPort\":80,\"hostPort\":80}]}]", + "cpu": null, + "ephemeral_storage": [], + "execution_role_arn": null, + "family": "service", + "inference_accelerator": [], + "ipc_mode": null, + "memory": null, + "pid_mode": null, + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": null, + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "task_role_arn": null, + "volume": [ + { + "docker_volume_configuration": [], + "efs_volume_configuration": [ + { + "authorization_config": [], + "file_system_id": "fs-0123456789abcdef0", + "root_directory": "/opt/data", + "transit_encryption": "DISABLED", + "transit_encryption_port": 2999 + } + ], + "fsx_windows_file_server_volume_configuration": [], + "host_path": "", + "name": "service-storage" + } + ] + }, + "sensitive_values": { + "ephemeral_storage": [], + "inference_accelerator": [], + "placement_constraints": [], + "proxy_configuration": [], + "runtime_platform": [], + "tags_all": {}, + "volume": [ + { + "docker_volume_configuration": [], + "efs_volume_configuration": [ + { + "authorization_config": [] + } + ], + "fsx_windows_file_server_volume_configuration": [] + } + ] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_ecs_task_definition.service", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "service", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "container_definitions": "[{\"cpu\":512,\"essential\":true,\"image\":\"nginx:1.23.1\",\"memory\":2048,\"name\":\"foo-task\",\"portMappings\":[{\"containerPort\":80,\"hostPort\":80}]}]", + "cpu": null, + "ephemeral_storage": [], + "execution_role_arn": null, + "family": "service", + "inference_accelerator": [], + "ipc_mode": null, + "memory": null, + "pid_mode": null, + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": null, + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "task_role_arn": null, + "volume": [ + { + "docker_volume_configuration": [], + "efs_volume_configuration": [ + { + "authorization_config": [], + "file_system_id": "fs-0123456789abcdef0", + "root_directory": "/opt/data", + "transit_encryption": "DISABLED", + "transit_encryption_port": 2999 + } + ], + "fsx_windows_file_server_volume_configuration": [], + "host_path": "", + "name": "service-storage" + } + ] + }, + "after_unknown": { + "arn": true, + "arn_without_revision": true, + "ephemeral_storage": [], + "id": true, + "inference_accelerator": [], + "network_mode": true, + "placement_constraints": [], + "proxy_configuration": [], + "revision": true, + "runtime_platform": [], + "tags_all": true, + "volume": [ + { + "docker_volume_configuration": [], + "efs_volume_configuration": [ + { + "authorization_config": [] + } + ], + "fsx_windows_file_server_volume_configuration": [] + } + ] + }, + "before_sensitive": false, + "after_sensitive": { + "ephemeral_storage": [], + "inference_accelerator": [], + "placement_constraints": [], + "proxy_configuration": [], + "runtime_platform": [], + "tags_all": {}, + "volume": [ + { + "docker_volume_configuration": [], + "efs_volume_configuration": [ + { + "authorization_config": [] + } + ], + "fsx_windows_file_server_volume_configuration": [] + } + ] + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": "~> 4.0", + "expressions": { + "region": { + "constant_value": "us-west-1" + } + } + }, + "docker": { + "name": "docker", + "full_name": "registry.terraform.io/kreuzwerker/docker", + "version_constraint": "~> 2.20.0" + } + }, + "root_module": { + "resources": [ + { + "address": "aws_ecs_task_definition.service", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "service", + "provider_config_key": "aws", + "expressions": { + "container_definitions": { + "constant_value": " [\n {\n \"name\" : \"foo-task\",\n \"image\" : \"nginx:1.23.1\",\n \"cpu\" : 512,\n \"memory\" : 2048,\n \"essential\" : true,\n \"portMappings\" : [\n {\n \"containerPort\" : 80,\n \"hostPort\" : 80\n }\n ]\n }\n ]\n" + }, + "family": { + "constant_value": "service" + }, + "volume": [ + { + "efs_volume_configuration": [ + { + "file_system_id": { + "constant_value": "fs-0123456789abcdef0" + }, + "root_directory": { + "constant_value": "/opt/data" + }, + "transit_encryption": { + "constant_value": "DISABLED" + }, + "transit_encryption_port": { + "constant_value": 2999 + } + } + ], + "name": { + "constant_value": "service-storage" + } + } + ] + }, + "schema_version": 1 + } + ] + } + }, + "timestamp": "2024-01-30T13:27:46Z", + "errored": false +} diff --git a/terraform/plan/ecs-best-practices/validate-efs-volume-encryption/test/bad.tf b/terraform/plan/ecs-best-practices/validate-efs-volume-encryption/test/bad.tf new file mode 100644 index 00000000..98e441f1 --- /dev/null +++ b/terraform/plan/ecs-best-practices/validate-efs-volume-encryption/test/bad.tf @@ -0,0 +1,52 @@ +resource "aws_ecs_task_definition" "service" { + family = "service" + container_definitions = < 4.0", + "expressions": { + "region": { + "constant_value": "us-west-1" + } + } + }, + "docker": { + "name": "docker", + "full_name": "registry.terraform.io/kreuzwerker/docker", + "version_constraint": "~> 2.20.0" + } + }, + "root_module": { + "resources": [ + { + "address": "aws_ecs_task_definition.service", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "service", + "provider_config_key": "aws", + "expressions": { + "container_definitions": { + "constant_value": " [\n {\n \"name\" : \"foo-task\",\n \"image\" : \"nginx:1.23.1\",\n \"cpu\" : 512,\n \"memory\" : 2048,\n \"essential\" : true,\n \"portMappings\" : [\n {\n \"containerPort\" : 80,\n \"hostPort\" : 80\n }\n ]\n }\n ]\n" + }, + "family": { + "constant_value": "service" + }, + "volume": [ + { + "efs_volume_configuration": [ + { + "file_system_id": { + "constant_value": "fs-0123456789abcdef0" + }, + "root_directory": { + "constant_value": "/opt/data" + }, + "transit_encryption": { + "constant_value": "ENABLED" + }, + "transit_encryption_port": { + "constant_value": 2999 + } + } + ], + "name": { + "constant_value": "service-storage" + } + } + ] + }, + "schema_version": 1 + } + ] + } + }, + "timestamp": "2024-01-30T13:27:46Z", + "errored": false + } + \ No newline at end of file diff --git a/terraform/plan/ecs-best-practices/validate-efs-volume-encryption/test/good-payload1.json b/terraform/plan/ecs-best-practices/validate-efs-volume-encryption/test/good-payload1.json new file mode 100644 index 00000000..3ad6cd74 --- /dev/null +++ b/terraform/plan/ecs-best-practices/validate-efs-volume-encryption/test/good-payload1.json @@ -0,0 +1,146 @@ +{ + "format_version": "1.2", + "terraform_version": "1.7.2-dev", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_ecs_task_definition.service", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "service", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 1, + "values": { + "container_definitions": "[{\"cpu\":512,\"essential\":true,\"image\":\"nginx:1.23.1\",\"memory\":2048,\"name\":\"foo-task\",\"portMappings\":[{\"containerPort\":80,\"hostPort\":80}]}]", + "cpu": null, + "ephemeral_storage": [], + "execution_role_arn": null, + "family": "service", + "inference_accelerator": [], + "ipc_mode": null, + "memory": null, + "pid_mode": null, + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": null, + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "task_role_arn": null, + "volume": [] + }, + "sensitive_values": { + "ephemeral_storage": [], + "inference_accelerator": [], + "placement_constraints": [], + "proxy_configuration": [], + "runtime_platform": [], + "tags_all": {}, + "volume": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_ecs_task_definition.service", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "service", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "container_definitions": "[{\"cpu\":512,\"essential\":true,\"image\":\"nginx:1.23.1\",\"memory\":2048,\"name\":\"foo-task\",\"portMappings\":[{\"containerPort\":80,\"hostPort\":80}]}]", + "cpu": null, + "ephemeral_storage": [], + "execution_role_arn": null, + "family": "service", + "inference_accelerator": [], + "ipc_mode": null, + "memory": null, + "pid_mode": null, + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": null, + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "task_role_arn": null, + "volume": [] + }, + "after_unknown": { + "arn": true, + "arn_without_revision": true, + "ephemeral_storage": [], + "id": true, + "inference_accelerator": [], + "network_mode": true, + "placement_constraints": [], + "proxy_configuration": [], + "revision": true, + "runtime_platform": [], + "tags_all": true, + "volume": [] + }, + "before_sensitive": false, + "after_sensitive": { + "ephemeral_storage": [], + "inference_accelerator": [], + "placement_constraints": [], + "proxy_configuration": [], + "runtime_platform": [], + "tags_all": {}, + "volume": [] + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": "~> 4.0", + "expressions": { + "region": { + "constant_value": "us-west-1" + } + } + }, + "docker": { + "name": "docker", + "full_name": "registry.terraform.io/kreuzwerker/docker", + "version_constraint": "~> 2.20.0" + } + }, + "root_module": { + "resources": [ + { + "address": "aws_ecs_task_definition.service", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "service", + "provider_config_key": "aws", + "expressions": { + "container_definitions": { + "constant_value": " [\n {\n \"name\" : \"foo-task\",\n \"image\" : \"nginx:1.23.1\",\n \"cpu\" : 512,\n \"memory\" : 2048,\n \"essential\" : true,\n \"portMappings\" : [\n {\n \"containerPort\" : 80,\n \"hostPort\" : 80\n }\n ]\n }\n ]\n" + }, + "family": { + "constant_value": "service" + } + }, + "schema_version": 1 + } + ] + } + }, + "timestamp": "2024-02-05T11:06:06Z", + "errored": false + } + \ No newline at end of file diff --git a/terraform/plan/ecs-best-practices/validate-efs-volume-encryption/test/good-payload2.json b/terraform/plan/ecs-best-practices/validate-efs-volume-encryption/test/good-payload2.json new file mode 100644 index 00000000..43256807 --- /dev/null +++ b/terraform/plan/ecs-best-practices/validate-efs-volume-encryption/test/good-payload2.json @@ -0,0 +1,191 @@ +{ + "format_version": "1.2", + "terraform_version": "1.8.4", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_ecs_task_definition.service", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "service", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 1, + "values": { + "container_definitions": "[{\"cpu\":512,\"essential\":true,\"image\":\"nginx:1.23.1\",\"memory\":2048,\"name\":\"foo-task\",\"portMappings\":[{\"containerPort\":80,\"hostPort\":80}]}]", + "cpu": null, + "ephemeral_storage": [], + "execution_role_arn": null, + "family": "service", + "inference_accelerator": [], + "ipc_mode": null, + "memory": null, + "pid_mode": null, + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": null, + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "task_role_arn": null, + "volume": [ + { + "docker_volume_configuration": [], + "efs_volume_configuration": [], + "fsx_windows_file_server_volume_configuration": [], + "host_path": "/var/run/docker.sock", + "name": "dockersock" + } + ] + }, + "sensitive_values": { + "ephemeral_storage": [], + "inference_accelerator": [], + "placement_constraints": [], + "proxy_configuration": [], + "runtime_platform": [], + "tags_all": {}, + "volume": [ + { + "docker_volume_configuration": [], + "efs_volume_configuration": [], + "fsx_windows_file_server_volume_configuration": [] + } + ] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_ecs_task_definition.service", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "service", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "container_definitions": "[{\"cpu\":512,\"essential\":true,\"image\":\"nginx:1.23.1\",\"memory\":2048,\"name\":\"foo-task\",\"portMappings\":[{\"containerPort\":80,\"hostPort\":80}]}]", + "cpu": null, + "ephemeral_storage": [], + "execution_role_arn": null, + "family": "service", + "inference_accelerator": [], + "ipc_mode": null, + "memory": null, + "pid_mode": null, + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": null, + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "task_role_arn": null, + "volume": [ + { + "docker_volume_configuration": [], + "efs_volume_configuration": [], + "fsx_windows_file_server_volume_configuration": [], + "host_path": "/var/run/docker.sock", + "name": "dockersock" + } + ] + }, + "after_unknown": { + "arn": true, + "arn_without_revision": true, + "ephemeral_storage": [], + "id": true, + "inference_accelerator": [], + "network_mode": true, + "placement_constraints": [], + "proxy_configuration": [], + "revision": true, + "runtime_platform": [], + "tags_all": true, + "volume": [ + { + "docker_volume_configuration": [], + "efs_volume_configuration": [], + "fsx_windows_file_server_volume_configuration": [] + } + ] + }, + "before_sensitive": false, + "after_sensitive": { + "ephemeral_storage": [], + "inference_accelerator": [], + "placement_constraints": [], + "proxy_configuration": [], + "runtime_platform": [], + "tags_all": {}, + "volume": [ + { + "docker_volume_configuration": [], + "efs_volume_configuration": [], + "fsx_windows_file_server_volume_configuration": [] + } + ] + } + } + } + ], + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": "~\u003e 4.0", + "expressions": { + "region": { + "constant_value": "us-west-1" + } + } + }, + "docker": { + "name": "docker", + "full_name": "registry.terraform.io/kreuzwerker/docker", + "version_constraint": "~\u003e 2.20.0" + } + }, + "root_module": { + "resources": [ + { + "address": "aws_ecs_task_definition.service", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "service", + "provider_config_key": "aws", + "expressions": { + "container_definitions": { + "constant_value": " [\n {\n \"name\" : \"foo-task\",\n \"image\" : \"nginx:1.23.1\",\n \"cpu\" : 512,\n \"memory\" : 2048,\n \"essential\" : true,\n \"portMappings\" : [\n {\n \"containerPort\" : 80,\n \"hostPort\" : 80\n }\n ]\n }\n ]\n" + }, + "family": { + "constant_value": "service" + }, + "volume": [ + { + "host_path": { + "constant_value": "/var/run/docker.sock" + }, + "name": { + "constant_value": "dockersock" + } + } + ] + }, + "schema_version": 1 + } + ] + } + }, + "timestamp": "2024-06-21T11:10:33Z", + "applyable": true, + "complete": true, + "errored": false +} \ No newline at end of file diff --git a/terraform/plan/ecs-best-practices/validate-efs-volume-encryption/test/good.tf b/terraform/plan/ecs-best-practices/validate-efs-volume-encryption/test/good.tf new file mode 100644 index 00000000..d4d19a7d --- /dev/null +++ b/terraform/plan/ecs-best-practices/validate-efs-volume-encryption/test/good.tf @@ -0,0 +1,53 @@ +resource "aws_ecs_task_definition" "service" { + family = "service" + container_definitions = <- + This policy validates whether transit_encryption is set to ENABLED in the task definition. +spec: + rules: + - name: validate-efs-volume-encryption + match: + all: + - ($analyzer.resource.type): terraform-plan + - (planned_values.root_module.resources[?type=='aws_ecs_task_definition'] | length(@) > `0`): true + assert: + all: + - message: Transit Encryption is not `ENABLED` for EFS volumes in ECS Task definitions + check: + ~.(planned_values.root_module.resources[?type=='aws_ecs_task_definition']): + ~.(values.volume[] || `[]`): + ~.(efs_volume_configuration[] || `[]`): + (transit_encryption == 'ENABLED'): true + diff --git a/terraform/plan/ecs-best-practices/validate-secret-env-variables/README.md b/terraform/plan/ecs-best-practices/validate-secret-env-variables/README.md new file mode 100644 index 00000000..0019c8ea --- /dev/null +++ b/terraform/plan/ecs-best-practices/validate-secret-env-variables/README.md @@ -0,0 +1,71 @@ +# Validate Secret Env Variables + +Passing sensitive data in plaintext can cause security issues. The data might be discoverable in the AWS Management Console or through AWS APIs such as DescribeTaskDefinition.To securely inject data into containers, reference the values stored in Parameter Store, a capability of AWS Systems Manager. You can also use AWS Secrets Manager in an Amazon ECS task definition. Then, you can expose your sensitive information as environment variables or in the log configuration of a container. This policy checks if any of the environment variables passed are any of AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, or ECS_ENGINE_AUTH_DATA. + +## Policy Details: + +- **Policy Name:** validate-secret-env-variables +- **Check Description:** This policy ensures any of the environment variables passed are any of AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, or ECS_ENGINE_AUTH_DATA. +- **Policy Category:** AWS ECS 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:** + ``` + kyverno-json scan --payload payload.json --policy policy.yaml + ``` + + a. **Test Policy Against Valid Payload:** + ``` + kyverno-json scan --policy validate-secret-env-variables.yaml --payload test/good-test/good-payload-01.json --bindings test/binding.yaml + ``` + + This produces the output: + ``` + Loading policies ... + Loading bindings ... + - analyzer -> map[resource:map[type:terraform-plan]] + Loading payload ... + Pre processing ... + Running ( evaluating 1 resource against 1 policy ) ... + - validate-secret-env-variables / validate-secret-env-variables / PASSED + Done + ``` + b. **Test Against Invalid Payload:** + ```bash + kyverno-json scan --policy validate-secret-env-variables.yaml --payload test/bad-test/bad-payload-01.json --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 ) ... + - validate-secret-env-variables / validate-secret-env-variables / FAILED + -> ECS task definitions should not contain sensitive environment variables like AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, or ECS_ENGINE_AUTH_DATA. + -> all[0].check.~.(planned_values.root_module.resources[?type=='aws_ecs_task_definition'])[0].values.~.(json_parse(container_definitions))[0].~.(environment || `[]`)[0].name.(!contains(@, 'AWS_ACCESS_KEY_ID')): Invalid value: false: Expected value: true + Done + ``` +--- \ No newline at end of file diff --git a/terraform/plan/ecs-best-practices/validate-secret-env-variables/test/bad-test/bad-01.tf b/terraform/plan/ecs-best-practices/validate-secret-env-variables/test/bad-test/bad-01.tf new file mode 100644 index 00000000..d5fbee01 --- /dev/null +++ b/terraform/plan/ecs-best-practices/validate-secret-env-variables/test/bad-test/bad-01.tf @@ -0,0 +1,41 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_ecs_task_definition" "task" { + family = "service" + container_definitions = <= 5.32.0", + "expressions": { + "region": { + "constant_value": "us-west-2" + } + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_ecs_task_definition.task", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "task", + "provider_config_key": "aws", + "expressions": { + "container_definitions": { + "constant_value": " [\n {\n \"name\" : \"foo-task\",\n \"image\" : \"nginx:1.23.1\",\n \"cpu\" : 512,\n \"memory\" : 2048,\n \"essential\" : true,\n \"portMappings\" : [\n {\n \"containerPort\" : 80,\n \"hostPort\" : 80\n }\n ],\n \"environment\" : [\n {\n \"name\" : \"AWS_ACCESS_KEY_ID\",\n \"value\" : \"EXAMPLE_ACCESS_KEY\"\n }\n ]\n }\n ]\n" + }, + "family": { + "constant_value": "service" + } + }, + "schema_version": 1 + } + ] + } + }, + "timestamp": "2024-09-06T08:55:33Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/ecs-best-practices/validate-secret-env-variables/test/bad-test/bad-payload-02.json b/terraform/plan/ecs-best-practices/validate-secret-env-variables/test/bad-test/bad-payload-02.json new file mode 100644 index 00000000..1c995570 --- /dev/null +++ b/terraform/plan/ecs-best-practices/validate-secret-env-variables/test/bad-test/bad-payload-02.json @@ -0,0 +1,144 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_ecs_task_definition.task", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "task", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 1, + "values": { + "container_definitions": "[{\"cpu\":512,\"environment\":[{\"name\":\"AWS_SECRET_ACCESS_KEY\",\"value\":\"EXAMPLE_SECRET_KEY\"}],\"essential\":true,\"image\":\"nginx:1.23.1\",\"memory\":2048,\"name\":\"foo-task\",\"portMappings\":[{\"containerPort\":80,\"hostPort\":80}]}]", + "cpu": null, + "ephemeral_storage": [], + "execution_role_arn": null, + "family": "service", + "inference_accelerator": [], + "ipc_mode": null, + "memory": null, + "pid_mode": null, + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": null, + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "task_role_arn": null, + "track_latest": false, + "volume": [] + }, + "sensitive_values": { + "ephemeral_storage": [], + "inference_accelerator": [], + "placement_constraints": [], + "proxy_configuration": [], + "runtime_platform": [], + "tags_all": {}, + "volume": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_ecs_task_definition.task", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "task", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "container_definitions": "[{\"cpu\":512,\"environment\":[{\"name\":\"AWS_SECRET_ACCESS_KEY\",\"value\":\"EXAMPLE_SECRET_KEY\"}],\"essential\":true,\"image\":\"nginx:1.23.1\",\"memory\":2048,\"name\":\"foo-task\",\"portMappings\":[{\"containerPort\":80,\"hostPort\":80}]}]", + "cpu": null, + "ephemeral_storage": [], + "execution_role_arn": null, + "family": "service", + "inference_accelerator": [], + "ipc_mode": null, + "memory": null, + "pid_mode": null, + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": null, + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "task_role_arn": null, + "track_latest": false, + "volume": [] + }, + "after_unknown": { + "arn": true, + "arn_without_revision": true, + "ephemeral_storage": [], + "id": true, + "inference_accelerator": [], + "network_mode": true, + "placement_constraints": [], + "proxy_configuration": [], + "revision": true, + "runtime_platform": [], + "tags_all": true, + "volume": [] + }, + "before_sensitive": false, + "after_sensitive": { + "ephemeral_storage": [], + "inference_accelerator": [], + "placement_constraints": [], + "proxy_configuration": [], + "runtime_platform": [], + "tags_all": {}, + "volume": [] + } + } + } + ], + "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_ecs_task_definition.task", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "task", + "provider_config_key": "aws", + "expressions": { + "container_definitions": { + "constant_value": " [\n {\n \"name\" : \"foo-task\",\n \"image\" : \"nginx:1.23.1\",\n \"cpu\" : 512,\n \"memory\" : 2048,\n \"essential\" : true,\n \"portMappings\" : [\n {\n \"containerPort\" : 80,\n \"hostPort\" : 80\n }\n ],\n \"environment\" : [\n {\n \"name\" : \"AWS_SECRET_ACCESS_KEY\",\n \"value\" : \"EXAMPLE_SECRET_KEY\"\n }\n ]\n }\n ]\n" + }, + "family": { + "constant_value": "service" + } + }, + "schema_version": 1 + } + ] + } + }, + "timestamp": "2024-09-06T08:56:50Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/ecs-best-practices/validate-secret-env-variables/test/bad-test/bad-payload-03.json b/terraform/plan/ecs-best-practices/validate-secret-env-variables/test/bad-test/bad-payload-03.json new file mode 100644 index 00000000..928bc732 --- /dev/null +++ b/terraform/plan/ecs-best-practices/validate-secret-env-variables/test/bad-test/bad-payload-03.json @@ -0,0 +1,144 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_ecs_task_definition.task", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "task", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 1, + "values": { + "container_definitions": "[{\"cpu\":512,\"environment\":[{\"name\":\"ECS_ENGINE_AUTH_DATA\",\"value\":\"EXAMPLE_VALUE\"}],\"essential\":true,\"image\":\"nginx:1.23.1\",\"memory\":2048,\"name\":\"foo-task\",\"portMappings\":[{\"containerPort\":80,\"hostPort\":80}]}]", + "cpu": null, + "ephemeral_storage": [], + "execution_role_arn": null, + "family": "service", + "inference_accelerator": [], + "ipc_mode": null, + "memory": null, + "pid_mode": null, + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": null, + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "task_role_arn": null, + "track_latest": false, + "volume": [] + }, + "sensitive_values": { + "ephemeral_storage": [], + "inference_accelerator": [], + "placement_constraints": [], + "proxy_configuration": [], + "runtime_platform": [], + "tags_all": {}, + "volume": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_ecs_task_definition.task", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "task", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "container_definitions": "[{\"cpu\":512,\"environment\":[{\"name\":\"ECS_ENGINE_AUTH_DATA\",\"value\":\"EXAMPLE_VALUE\"}],\"essential\":true,\"image\":\"nginx:1.23.1\",\"memory\":2048,\"name\":\"foo-task\",\"portMappings\":[{\"containerPort\":80,\"hostPort\":80}]}]", + "cpu": null, + "ephemeral_storage": [], + "execution_role_arn": null, + "family": "service", + "inference_accelerator": [], + "ipc_mode": null, + "memory": null, + "pid_mode": null, + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": null, + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "task_role_arn": null, + "track_latest": false, + "volume": [] + }, + "after_unknown": { + "arn": true, + "arn_without_revision": true, + "ephemeral_storage": [], + "id": true, + "inference_accelerator": [], + "network_mode": true, + "placement_constraints": [], + "proxy_configuration": [], + "revision": true, + "runtime_platform": [], + "tags_all": true, + "volume": [] + }, + "before_sensitive": false, + "after_sensitive": { + "ephemeral_storage": [], + "inference_accelerator": [], + "placement_constraints": [], + "proxy_configuration": [], + "runtime_platform": [], + "tags_all": {}, + "volume": [] + } + } + } + ], + "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_ecs_task_definition.task", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "task", + "provider_config_key": "aws", + "expressions": { + "container_definitions": { + "constant_value": " [\n {\n \"name\" : \"foo-task\",\n \"image\" : \"nginx:1.23.1\",\n \"cpu\" : 512,\n \"memory\" : 2048,\n \"essential\" : true,\n \"portMappings\" : [\n {\n \"containerPort\" : 80,\n \"hostPort\" : 80\n }\n ],\n \"environment\" : [\n {\n \"name\" : \"ECS_ENGINE_AUTH_DATA\",\n \"value\" : \"EXAMPLE_VALUE\"\n }\n ]\n }\n ]\n" + }, + "family": { + "constant_value": "service" + } + }, + "schema_version": 1 + } + ] + } + }, + "timestamp": "2024-09-06T08:57:36Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/ecs-best-practices/validate-secret-env-variables/test/binding.yaml b/terraform/plan/ecs-best-practices/validate-secret-env-variables/test/binding.yaml new file mode 100644 index 00000000..a3dd760d --- /dev/null +++ b/terraform/plan/ecs-best-practices/validate-secret-env-variables/test/binding.yaml @@ -0,0 +1,3 @@ +analyzer: + resource: + type: terraform-plan \ No newline at end of file diff --git a/terraform/plan/ecs-best-practices/validate-secret-env-variables/test/chainsaw-test.yaml b/terraform/plan/ecs-best-practices/validate-secret-env-variables/test/chainsaw-test.yaml new file mode 100644 index 00000000..f7540fae --- /dev/null +++ b/terraform/plan/ecs-best-practices/validate-secret-env-variables/test/chainsaw-test.yaml @@ -0,0 +1,150 @@ +# 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 --policy ../validate-secret-env-variables.yaml --payload ./good-test/good-payload-01.json --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: validate-secret-env-variables + rules: + - rule: + name: validate-secret-env-variables + 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 --policy ../validate-secret-env-variables.yaml --payload ./good-test/good-payload-02.json --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: validate-secret-env-variables + rules: + - rule: + name: validate-secret-env-variables + 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 --policy ../validate-secret-env-variables.yaml --payload ./bad-test/bad-payload-01.json --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: validate-secret-env-variables + rules: + - rule: + name: validate-secret-env-variables + error: ~ + violations: + - (contains(message, 'ECS task definitions should not contain sensitive environment variables like AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, or ECS_ENGINE_AUTH_DATA.')): true + 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 --policy ../validate-secret-env-variables.yaml --payload ./bad-test/bad-payload-02.json --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: validate-secret-env-variables + rules: + - rule: + name: validate-secret-env-variables + error: ~ + violations: + - (contains(message, 'ECS task definitions should not contain sensitive environment variables like AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, or ECS_ENGINE_AUTH_DATA.')): true + errors: + - type: FieldValueInvalid + value: false + detail: 'Expected value: true' +--- +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: bad-test-03 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --policy ../validate-secret-env-variables.yaml --payload ./bad-test/bad-payload-03.json --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: validate-secret-env-variables + rules: + - rule: + name: validate-secret-env-variables + error: ~ + violations: + - (contains(message, 'ECS task definitions should not contain sensitive environment variables like AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, or ECS_ENGINE_AUTH_DATA.')): true + errors: + - type: FieldValueInvalid + value: false + detail: 'Expected value: true' \ No newline at end of file diff --git a/terraform/plan/ecs-best-practices/validate-secret-env-variables/test/good-test/good-01.tf b/terraform/plan/ecs-best-practices/validate-secret-env-variables/test/good-test/good-01.tf new file mode 100644 index 00000000..6b7a5a6c --- /dev/null +++ b/terraform/plan/ecs-best-practices/validate-secret-env-variables/test/good-test/good-01.tf @@ -0,0 +1,35 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.32" + } + } +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_ecs_task_definition" "task" { + family = "service" + container_definitions = <= 5.32.0", + "expressions": { + "region": { + "constant_value": "us-west-2" + } + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_ecs_task_definition.task", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "task", + "provider_config_key": "aws", + "expressions": { + "container_definitions": { + "constant_value": " [\n {\n \"name\" : \"foo-task\",\n \"image\" : \"nginx:1.23.1\",\n \"cpu\" : 512,\n \"memory\" : 2048,\n \"essential\" : true,\n \"portMappings\" : [\n {\n \"containerPort\" : 80,\n \"hostPort\" : 80\n }\n ]\n }\n ]\n" + }, + "family": { + "constant_value": "service" + } + }, + "schema_version": 1 + } + ] + } + }, + "timestamp": "2024-09-06T08:52:44Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/ecs-best-practices/validate-secret-env-variables/test/good-test/good-payload-02.json b/terraform/plan/ecs-best-practices/validate-secret-env-variables/test/good-test/good-payload-02.json new file mode 100644 index 00000000..ca729d43 --- /dev/null +++ b/terraform/plan/ecs-best-practices/validate-secret-env-variables/test/good-test/good-payload-02.json @@ -0,0 +1,144 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_ecs_task_definition.task", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "task", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 1, + "values": { + "container_definitions": "[{\"cpu\":512,\"environment\":[{\"name\":\"GOOD_KEY\",\"value\":\"abc123\"}],\"essential\":true,\"image\":\"nginx:1.23.1\",\"memory\":2048,\"name\":\"foo-task\",\"portMappings\":[{\"containerPort\":80,\"hostPort\":80}]}]", + "cpu": null, + "ephemeral_storage": [], + "execution_role_arn": null, + "family": "service", + "inference_accelerator": [], + "ipc_mode": null, + "memory": null, + "pid_mode": null, + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": null, + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "task_role_arn": null, + "track_latest": false, + "volume": [] + }, + "sensitive_values": { + "ephemeral_storage": [], + "inference_accelerator": [], + "placement_constraints": [], + "proxy_configuration": [], + "runtime_platform": [], + "tags_all": {}, + "volume": [] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_ecs_task_definition.task", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "task", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "container_definitions": "[{\"cpu\":512,\"environment\":[{\"name\":\"GOOD_KEY\",\"value\":\"abc123\"}],\"essential\":true,\"image\":\"nginx:1.23.1\",\"memory\":2048,\"name\":\"foo-task\",\"portMappings\":[{\"containerPort\":80,\"hostPort\":80}]}]", + "cpu": null, + "ephemeral_storage": [], + "execution_role_arn": null, + "family": "service", + "inference_accelerator": [], + "ipc_mode": null, + "memory": null, + "pid_mode": null, + "placement_constraints": [], + "proxy_configuration": [], + "requires_compatibilities": null, + "runtime_platform": [], + "skip_destroy": false, + "tags": null, + "task_role_arn": null, + "track_latest": false, + "volume": [] + }, + "after_unknown": { + "arn": true, + "arn_without_revision": true, + "ephemeral_storage": [], + "id": true, + "inference_accelerator": [], + "network_mode": true, + "placement_constraints": [], + "proxy_configuration": [], + "revision": true, + "runtime_platform": [], + "tags_all": true, + "volume": [] + }, + "before_sensitive": false, + "after_sensitive": { + "ephemeral_storage": [], + "inference_accelerator": [], + "placement_constraints": [], + "proxy_configuration": [], + "runtime_platform": [], + "tags_all": {}, + "volume": [] + } + } + } + ], + "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_ecs_task_definition.task", + "mode": "managed", + "type": "aws_ecs_task_definition", + "name": "task", + "provider_config_key": "aws", + "expressions": { + "container_definitions": { + "constant_value": " [\n {\n \"name\" : \"foo-task\",\n \"image\" : \"nginx:1.23.1\",\n \"cpu\" : 512,\n \"memory\" : 2048,\n \"essential\" : true,\n \"portMappings\" : [\n {\n \"containerPort\" : 80,\n \"hostPort\" : 80\n }\n ],\n \"environment\" : [\n {\n \"name\" : \"GOOD_KEY\",\n \"value\" : \"abc123\"\n }\n ]\n }\n ]\n" + }, + "family": { + "constant_value": "service" + } + }, + "schema_version": 1 + } + ] + } + }, + "timestamp": "2024-09-06T08:54:30Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/terraform/plan/ecs-best-practices/validate-secret-env-variables/validate-secret-env-variables.yaml b/terraform/plan/ecs-best-practices/validate-secret-env-variables/validate-secret-env-variables.yaml new file mode 100644 index 00000000..a15f2762 --- /dev/null +++ b/terraform/plan/ecs-best-practices/validate-secret-env-variables/validate-secret-env-variables.yaml @@ -0,0 +1,33 @@ +apiVersion: json.kyverno.io/v1alpha1 +kind: ValidatingPolicy +metadata: + name: validate-secret-env-variables + annotations: + policies.kyverno.io/title: Validate Secret Env Variables + policies.kyverno.io/category: ECS Best Practices + policies.kyverno.io/severity: medium + policies.kyverno.io/description: >- + Passing sensitive data in plaintext can cause security issues. The data might be discoverable in the AWS Management Console or through AWS APIs such as DescribeTaskDefinition. + To securely inject data into containers, reference the values stored in Parameter Store, a capability of AWS Systems Manager. You can also use AWS Secrets Manager in an Amazon ECS task definition. + Then, you can expose your sensitive information as environment variables or in the log configuration of a container. + This policy checks if any of the environment variables passed are any of AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, or ECS_ENGINE_AUTH_DATA. +spec: + rules: + - name: validate-secret-env-variables + match: + all: + - ($analyzer.resource.type): terraform-plan + - (planned_values.root_module.resources[?type=='aws_ecs_task_definition'] | length(@) > `0`): true + assert: + all: + - message: >- + ECS task definitions should not contain sensitive environment variables like AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, or ECS_ENGINE_AUTH_DATA. + check: + ~.(planned_values.root_module.resources[?type=='aws_ecs_task_definition']): + values: + ~.(json_parse(container_definitions)): + ~.(environment || `[]`): + name: + (!contains(@, 'AWS_ACCESS_KEY_ID')): true + (!contains(@, 'AWS_SECRET_ACCESS_KEY')): true + (!contains(@, 'ECS_ENGINE_AUTH_DATA')): true \ No newline at end of file