diff --git a/.github/workflows/chainsaw-e2e.yaml b/.github/workflows/chainsaw-e2e.yaml index 2f85c850..fe278405 100644 --- a/.github/workflows/chainsaw-e2e.yaml +++ b/.github/workflows/chainsaw-e2e.yaml @@ -39,7 +39,7 @@ jobs: run: make wait-for-kyverno - name: Install chainsaw - uses: kyverno/action-install-chainsaw@v0.1.6 + uses: kyverno/action-install-chainsaw@7ad918efe13995d01bafa59aef8203a5246f5d04 # v0.2.7 - name: Verify Chainsaw Installation run: chainsaw version @@ -77,7 +77,7 @@ jobs: run: make wait-for-kyverno - name: Install chainsaw - uses: kyverno/action-install-chainsaw@v0.1.6 + uses: kyverno/action-install-chainsaw@7ad918efe13995d01bafa59aef8203a5246f5d04 # v0.2.7 - name: Verify Chainsaw Installation run: chainsaw version @@ -110,7 +110,7 @@ jobs: run: make wait-for-kyverno - name: Install chainsaw - uses: kyverno/action-install-chainsaw@v0.1.6 + uses: kyverno/action-install-chainsaw@7ad918efe13995d01bafa59aef8203a5246f5d04 # v0.2.7 - name: Verify Chainsaw Installation run: chainsaw version @@ -143,7 +143,7 @@ jobs: run: make wait-for-kyverno - name: Install chainsaw - uses: kyverno/action-install-chainsaw@v0.1.6 + uses: kyverno/action-install-chainsaw@7ad918efe13995d01bafa59aef8203a5246f5d04 # v0.2.7 - name: Verify Chainsaw Installation run: chainsaw version diff --git a/terraform/config/eks-best-practices/check-control-plane-logging/README.md b/terraform/config/eks-best-practices/check-control-plane-logging/README.md new file mode 100644 index 00000000..abe0bdd8 --- /dev/null +++ b/terraform/config/eks-best-practices/check-control-plane-logging/README.md @@ -0,0 +1,86 @@ +# Check Control Plane Logging for Amazon EKS + +Enabling Amazon EKS control plane logging for all log types is a best practice for enhancing the security, monitoring, troubleshooting, performance optimization, and operational management of your Kubernetes clusters. By capturing comprehensive logs of control plane activities, you can effectively manage and secure your EKS infrastructure while ensuring compliance with regulatory requirements and industry standards. + +To enable control plane logging for all types in Amazon EKS, ensure that **enabled_cluster_log_types** includes all these types: "api", "audit", "authenticator", "controllerManager" and "scheduler". You can read more about the log types [here](https://docs.aws.amazon.com/eks/latest/userguide/control-plane-logs.html) + +## Policy Details: + +- **Policy Name:** check-control-plane-logging +- **Check Description:** Ensure Amazon EKS control plane logging is enabled for all log types +- **Policy Category:** EKS Best Practices + +### 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 `nctl` installed on the machine + +1. **Test the Policy with nctl:** + ``` + nctl scan terraform --resources tf-config.tf --policy policy.yaml + ``` + + a. **Test Policy Against Valid Terraform Config File:** + ``` + nctl scan terraform --resources test/good.tf --policies check-control-plane-logging.yaml --details + ``` + + This produces the output: + ``` + Version: v4.2.2 + Fetching policies... + Loading policies... + - found 1 policies + Running analysis... + • no errors + Results... + +--------------------+------+------+------+-------+------+ + | CATEGORY | FAIL | WARN | PASS | ERROR | SKIP | + +--------------------+------+------+------+-------+------+ + | EKS Best Practices | 0 | 0 | 1 | 0 | 0 | + +--------------------+------+------+------+-------+------+ + Rule Results : (Fail: 0, Warn: 0, Pass: 1, Error: 0, Skip: 0) + Failed Rules Severity : (Critical: 0, High: 0, Medium: 0, Low: 0, Info: 0) + + +-----------------------------+-----------------------------+--------------+---------+--------+ + | POLICY | RULE | RESOURCE | MESSAGE | RESULT | + +-----------------------------+-----------------------------+--------------+---------+--------+ + | check-control-plane-logging | check-control-plane-logging | test/good.tf | | pass | + +-----------------------------+-----------------------------+--------------+---------+--------+ + Done! + ``` + + b. **Test Against Invalid Terraform Config File:** + ``` + nctl scan terraform --resources test/bad-01.tf --policies check-control-plane-logging.yaml --details + ``` + + This produces the output: + ``` + Version: v4.2.2 + Fetching policies... + Loading policies... + - found 1 policies + Running analysis... + • no errors + Results... + +--------------------+------+------+------+-------+------+ + | CATEGORY | FAIL | WARN | PASS | ERROR | SKIP | + +--------------------+------+------+------+-------+------+ + | EKS Best Practices | 1 | 0 | 0 | 0 | 0 | + +--------------------+------+------+------+-------+------+ + Rule Results : (Fail: 1, Warn: 0, Pass: 0, Error: 0, Skip: 0) + Failed Rules Severity : (Critical: 0, High: 0, Medium: 1, Low: 0, Info: 0) + + +-----------------------------+-----------------------------+----------------+--------------------------------+--------+ + | POLICY | RULE | RESOURCE | MESSAGE | RESULT | + +-----------------------------+-----------------------------+----------------+--------------------------------+--------+ + | check-control-plane-logging | check-control-plane-logging | test/bad-01.tf | EKS control plane logging must | fail | + | | | | be enabled for all log types | | + +-----------------------------+-----------------------------+----------------+--------------------------------+--------+ + Done! 1 policy violation(s) detected. + ``` + +--- diff --git a/terraform/config/eks-best-practices/check-control-plane-logging/check-control-plane-logging.yaml b/terraform/config/eks-best-practices/check-control-plane-logging/check-control-plane-logging.yaml new file mode 100644 index 00000000..b4b17f9f --- /dev/null +++ b/terraform/config/eks-best-practices/check-control-plane-logging/check-control-plane-logging.yaml @@ -0,0 +1,32 @@ +apiVersion: json.kyverno.io/v1alpha1 +kind: ValidatingPolicy +metadata: + name: check-control-plane-logging + annotations: + policies.kyverno.io/title: Check Control Plane Logging + policies.kyverno.io/category: EKS Best Practices + policies.kyverno.io/severity: medium + policies.kyverno.io/description: >- + Enabling Amazon EKS control plane logging for all log types is a best practice + for enhancing the security, monitoring, troubleshooting, performance optimization, and operational management of your Kubernetes clusters. + By capturing comprehensive logs of control plane activities, you can effectively manage and secure your + EKS infrastructure while ensuring compliance with regulatory requirements and industry standards. +spec: + rules: + - name: check-control-plane-logging + match: + all: + - ($analyzer.resource.type): terraform-config + - (resource.aws_eks_cluster != null): true + assert: + all: + - message: EKS control plane logging must be enabled for all log types + check: + ~.(resource.aws_eks_cluster.values(@)[]): + (enabled_cluster_log_types || `[]`): + (contains(@, 'api')): true + (contains(@, 'audit')): true + (contains(@, 'authenticator')): true + (contains(@, 'controllerManager')): true + (contains(@, 'scheduler')): true + diff --git a/terraform/config/eks-best-practices/check-control-plane-logging/test/bad-01.tf b/terraform/config/eks-best-practices/check-control-plane-logging/test/bad-01.tf new file mode 100644 index 00000000..6d023634 --- /dev/null +++ b/terraform/config/eks-best-practices/check-control-plane-logging/test/bad-01.tf @@ -0,0 +1,27 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 4.16" + } + } + + required_version = ">= 1.2.0" +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_eks_cluster" "example" { + name = "example-cluster" + role_arn = "arn:aws:iam::123456789012:role/eks-cluster-role" + + vpc_config { + subnet_ids = ["subnet-0123456789abcdef0", "subnet-0123456789abcdef1"] + } +} + +output "cluster_id" { + value = aws_eks_cluster.example.id +} diff --git a/terraform/config/eks-best-practices/check-control-plane-logging/test/bad-02.tf b/terraform/config/eks-best-practices/check-control-plane-logging/test/bad-02.tf new file mode 100644 index 00000000..f32057a1 --- /dev/null +++ b/terraform/config/eks-best-practices/check-control-plane-logging/test/bad-02.tf @@ -0,0 +1,29 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 4.16" + } + } + + required_version = ">= 1.2.0" +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_eks_cluster" "example" { + name = "example-cluster" + role_arn = "arn:aws:iam::123456789012:role/eks-cluster-role" + + vpc_config { + subnet_ids = ["subnet-0123456789abcdef0", "subnet-0123456789abcdef1"] + } + + enabled_cluster_log_types = ["api", "scheduler"] +} + +output "cluster_id" { + value = aws_eks_cluster.example.id +} diff --git a/terraform/config/eks-best-practices/check-control-plane-logging/test/bad-payload-01.json b/terraform/config/eks-best-practices/check-control-plane-logging/test/bad-payload-01.json new file mode 100644 index 00000000..b5498512 --- /dev/null +++ b/terraform/config/eks-best-practices/check-control-plane-logging/test/bad-payload-01.json @@ -0,0 +1,47 @@ +{ + "output": { + "cluster_id": [ + { + "value": "${aws_eks_cluster.example.id}" + } + ] + }, + "provider": { + "aws": [ + { + "region": "us-west-2" + } + ] + }, + "resource": { + "aws_eks_cluster": { + "example": [ + { + "name": "example-cluster", + "role_arn": "arn:aws:iam::123456789012:role/eks-cluster-role", + "vpc_config": [ + { + "subnet_ids": [ + "subnet-0123456789abcdef0", + "subnet-0123456789abcdef1" + ] + } + ] + } + ] + } + }, + "terraform": [ + { + "required_providers": [ + { + "aws": { + "source": "hashicorp/aws", + "version": "~\u003e 4.16" + } + } + ], + "required_version": "\u003e= 1.2.0" + } + ] +} \ No newline at end of file diff --git a/terraform/config/eks-best-practices/check-control-plane-logging/test/bad-payload-02.json b/terraform/config/eks-best-practices/check-control-plane-logging/test/bad-payload-02.json new file mode 100644 index 00000000..b1dd2a3e --- /dev/null +++ b/terraform/config/eks-best-practices/check-control-plane-logging/test/bad-payload-02.json @@ -0,0 +1,51 @@ +{ + "output": { + "cluster_id": [ + { + "value": "${aws_eks_cluster.example.id}" + } + ] + }, + "provider": { + "aws": [ + { + "region": "us-west-2" + } + ] + }, + "resource": { + "aws_eks_cluster": { + "example": [ + { + "enabled_cluster_log_types": [ + "api", + "scheduler" + ], + "name": "example-cluster", + "role_arn": "arn:aws:iam::123456789012:role/eks-cluster-role", + "vpc_config": [ + { + "subnet_ids": [ + "subnet-0123456789abcdef0", + "subnet-0123456789abcdef1" + ] + } + ] + } + ] + } + }, + "terraform": [ + { + "required_providers": [ + { + "aws": { + "source": "hashicorp/aws", + "version": "~\u003e 4.16" + } + } + ], + "required_version": "\u003e= 1.2.0" + } + ] +} \ No newline at end of file diff --git a/terraform/config/eks-best-practices/check-control-plane-logging/test/binding.yaml b/terraform/config/eks-best-practices/check-control-plane-logging/test/binding.yaml new file mode 100644 index 00000000..5d03d04f --- /dev/null +++ b/terraform/config/eks-best-practices/check-control-plane-logging/test/binding.yaml @@ -0,0 +1,3 @@ +analyzer: + resource: + type: terraform-config \ No newline at end of file diff --git a/terraform/config/eks-best-practices/check-control-plane-logging/test/chainsaw-test.yaml b/terraform/config/eks-best-practices/check-control-plane-logging/test/chainsaw-test.yaml new file mode 100644 index 00000000..8e58d6af --- /dev/null +++ b/terraform/config/eks-best-practices/check-control-plane-logging/test/chainsaw-test.yaml @@ -0,0 +1,111 @@ +#yaml-language-server: $schema=https://raw.githubusercontent.com/kyverno/chainsaw/main/.schemas/json/test-chainsaw-v1alpha1.json +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: good-test-01 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --payload ./good-payload.json --policy ../check-control-plane-logging.yaml --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-control-plane-logging + rules: + - rule: + name: check-control-plane-logging + error: ~ + violations: ~ +--- +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: bad-test-01 +spec: + steps: + - name: kyverno-json + try: + - script: + bindings: + - name: logTypesToBeEnabledInTheFailedPayload + value: + - api + - audit + - authenticator + - controllerManager + - scheduler + content: | + set -e + kyverno-json scan --policy ../check-control-plane-logging.yaml --payload ./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-control-plane-logging + rules: + - rule: + name: check-control-plane-logging + error: ~ + violations: + - (contains(message, 'EKS control plane logging must be enabled for all log types')): true + ~.(errors): + type: FieldValueInvalid + value: false + detail: 'Expected value: true' + (join(' ', errors[].field[]))->disabledLogTypesInThePayload: + ~.($logTypesToBeEnabledInTheFailedPayload): + (contains($disabledLogTypesInThePayload, @)): true +--- +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: bad-test-02 +spec: + steps: + - name: kyverno-json + try: + - script: + bindings: + - name: logTypesToBeEnabledInTheFailedPayload + value: + - audit + - authenticator + - controllerManager + content: | + set -e + kyverno-json scan --policy ../check-control-plane-logging.yaml --payload ./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: check-control-plane-logging + rules: + - rule: + name: check-control-plane-logging + error: ~ + violations: + - (contains(message, 'EKS control plane logging must be enabled for all log types')): true + ~.(errors): + type: FieldValueInvalid + value: false + detail: 'Expected value: true' + (join(' ', errors[].field[]))->disabledLogTypesInThePayload: + ~.($logTypesToBeEnabledInTheFailedPayload): + (contains($disabledLogTypesInThePayload, @)): true \ No newline at end of file diff --git a/terraform/config/eks-best-practices/check-control-plane-logging/test/good-payload.json b/terraform/config/eks-best-practices/check-control-plane-logging/test/good-payload.json new file mode 100644 index 00000000..ec1b0c7f --- /dev/null +++ b/terraform/config/eks-best-practices/check-control-plane-logging/test/good-payload.json @@ -0,0 +1,54 @@ +{ + "output": { + "cluster_id": [ + { + "value": "${aws_eks_cluster.example.id}" + } + ] + }, + "provider": { + "aws": [ + { + "region": "us-west-2" + } + ] + }, + "resource": { + "aws_eks_cluster": { + "example": [ + { + "enabled_cluster_log_types": [ + "api", + "audit", + "authenticator", + "controllerManager", + "scheduler" + ], + "name": "example-cluster", + "role_arn": "arn:aws:iam::123456789012:role/eks-cluster-role", + "vpc_config": [ + { + "subnet_ids": [ + "subnet-0123456789abcdef0", + "subnet-0123456789abcdef1" + ] + } + ] + } + ] + } + }, + "terraform": [ + { + "required_providers": [ + { + "aws": { + "source": "hashicorp/aws", + "version": "~\u003e 4.16" + } + } + ], + "required_version": "\u003e= 1.2.0" + } + ] +} \ No newline at end of file diff --git a/terraform/config/eks-best-practices/check-control-plane-logging/test/good.tf b/terraform/config/eks-best-practices/check-control-plane-logging/test/good.tf new file mode 100644 index 00000000..e4dac58c --- /dev/null +++ b/terraform/config/eks-best-practices/check-control-plane-logging/test/good.tf @@ -0,0 +1,29 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 4.16" + } + } + + required_version = ">= 1.2.0" +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_eks_cluster" "example" { + name = "example-cluster" + role_arn = "arn:aws:iam::123456789012:role/eks-cluster-role" + + vpc_config { + subnet_ids = ["subnet-0123456789abcdef0", "subnet-0123456789abcdef1"] + } + + enabled_cluster_log_types = ["api", "audit", "authenticator", "controllerManager", "scheduler"] +} + +output "cluster_id" { + value = aws_eks_cluster.example.id +} diff --git a/terraform/config/eks-best-practices/check-nodegroup-remote-access/README.md b/terraform/config/eks-best-practices/check-nodegroup-remote-access/README.md new file mode 100644 index 00000000..a6a4d4d9 --- /dev/null +++ b/terraform/config/eks-best-practices/check-nodegroup-remote-access/README.md @@ -0,0 +1,85 @@ +# Check Nodegroup Remote Access + +As a general security measure, it's crucial to ensure that your AWS EKS node group does not have implicit SSH access from 0.0.0.0/0, thus not being accessible over the internet. This protects your EKS node group from unauthorized access by external entities. + +## Policy Details: + +- **Policy Name:** check-nodegroup-remote-access +- **Check Description:** Ensure AWS EKS node group does not have implicit SSH access from 0.0.0.0/0 +- **Policy Category:** EKS Best Practices + +### 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 `nctl` installed on the machine + +1. **Test the Policy with nctl:** + ``` + nctl scan terraform --resources tf-config.tf --policy policy.yaml + ``` + + a. **Test Policy Against Valid Terraform Config File:** + ``` + nctl scan terraform --resources test/good-01.tf --policies check-nodegroup-remote-access.yaml --details + ``` + + This produces the output: + ``` + Version: v4.2.2 + Fetching policies... + Loading policies... + - found 1 policies + Running analysis... + • no errors + Results... + +--------------------+------+------+------+-------+------+ + | CATEGORY | FAIL | WARN | PASS | ERROR | SKIP | + +--------------------+------+------+------+-------+------+ + | EKS Best Practices | 0 | 0 | 1 | 0 | 0 | + +--------------------+------+------+------+-------+------+ + Rule Results : (Fail: 0, Warn: 0, Pass: 1, Error: 0, Skip: 0) + Failed Rules Severity : (Critical: 0, High: 0, Medium: 0, Low: 0, Info: 0) + + +-------------------------------+-------------------------------+-----------------+---------+--------+ + | POLICY | RULE | RESOURCE | MESSAGE | RESULT | + +-------------------------------+-------------------------------+-----------------+---------+--------+ + | check-nodegroup-remote-access | check-nodegroup-remote-access | test/good-01.tf | | pass | + +-------------------------------+-------------------------------+-----------------+---------+--------+ + Done! + ``` + + b. **Test Against Invalid Terraform Config File:** + ``` + nctl scan terraform --resources test/bad-01.tf --policies check-nodegroup-remote-access.yaml --details + ``` + + This produces the output: + ``` + Version: v4.2.2 + Fetching policies... + Loading policies... + - found 1 policies + Running analysis... + • no errors + Results... + +--------------------+------+------+------+-------+------+ + | CATEGORY | FAIL | WARN | PASS | ERROR | SKIP | + +--------------------+------+------+------+-------+------+ + | EKS Best Practices | 1 | 0 | 0 | 0 | 0 | + +--------------------+------+------+------+-------+------+ + Rule Results : (Fail: 1, Warn: 0, Pass: 0, Error: 0, Skip: 0) + Failed Rules Severity : (Critical: 0, High: 1, Medium: 0, Low: 0, Info: 0) + + +-------------------------------+-------------------------------+----------------+--------------------------------+--------+ + | POLICY | RULE | RESOURCE | MESSAGE | RESULT | + +-------------------------------+-------------------------------+----------------+--------------------------------+--------+ + | check-nodegroup-remote-access | check-nodegroup-remote-access | test/bad-01.tf | AWS EKS node group should not | fail | + | | | | have implicit SSH access from | | + | | | | 0.0.0.0/0 | | + +-------------------------------+-------------------------------+----------------+--------------------------------+--------+ + Done! 1 policy violation(s) detected. + ``` + +--- \ No newline at end of file diff --git a/terraform/config/eks-best-practices/check-nodegroup-remote-access/check-nodegroup-remote-access.yaml b/terraform/config/eks-best-practices/check-nodegroup-remote-access/check-nodegroup-remote-access.yaml new file mode 100644 index 00000000..8a2609c7 --- /dev/null +++ b/terraform/config/eks-best-practices/check-nodegroup-remote-access/check-nodegroup-remote-access.yaml @@ -0,0 +1,27 @@ +apiVersion: json.kyverno.io/v1alpha1 +kind: ValidatingPolicy +metadata: + name: check-nodegroup-remote-access + annotations: + policies.kyverno.io/title: Ensure AWS EKS node group does not have implicit SSH access from 0.0.0.0/0 + policies.kyverno.io/category: EKS Best Practices + policies.kyverno.io/severity: high + policies.kyverno.io/description: >- + Restricting SSH access prevents unauthorized users from gaining direct access to the underlying nodes of the Kubernetes cluster. + By limiting access to specific trusted networks or entities, organizations can reduce the + risk of potential security breaches and unauthorized modifications to the cluster infrastructure. +spec: + rules: + - name: check-nodegroup-remote-access + match: + all: + - ($analyzer.resource.type): terraform-config + - (resource.aws_eks_node_group != null): true + assert: + all: + - message: AWS EKS node group should not have implicit SSH access from 0.0.0.0/0 + check: + ~.(resource.aws_eks_node_group.values(@)[]): + ~.(remote_access || `[]`): + (contains(keys(@), 'ec2_ssh_key') && !contains(keys(@), 'source_security_group_ids')): false + diff --git a/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/bad-01.tf b/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/bad-01.tf new file mode 100644 index 00000000..87c32196 --- /dev/null +++ b/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/bad-01.tf @@ -0,0 +1,56 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 4.16" + } + } + + required_version = ">= 1.2.0" +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_iam_role" "example" { + name = "example-role" + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [{ + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "eks.amazonaws.com" + } + }] + }) +} + +resource "aws_eks_cluster" "example" { + name = "example-cluster" + role_arn = aws_iam_role.example.arn + + vpc_config { + subnet_ids = ["subnet-12345", "subnet-67890"] + } +} + +# remote_access block is present with ec2_ssh_key and without source_security_group_ids +resource "aws_eks_node_group" "bad_example" { + cluster_name = aws_eks_cluster.example.name + node_role_arn = aws_iam_role.example.arn + subnet_ids = ["subnet-12345", "subnet-67890"] + node_group_name = "bad-example-node-group" + + scaling_config { + desired_size = 1 + max_size = 2 + min_size = 1 + } + + remote_access { + ec2_ssh_key = "some-key" + } +} diff --git a/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/bad-02.tf b/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/bad-02.tf new file mode 100644 index 00000000..ba03ceb8 --- /dev/null +++ b/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/bad-02.tf @@ -0,0 +1,70 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 4.16" + } + } + + required_version = ">= 1.2.0" +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_iam_role" "example" { + name = "example-role" + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [{ + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "eks.amazonaws.com" + } + }] + }) +} + +resource "aws_eks_cluster" "example" { + name = "example-cluster" + role_arn = aws_iam_role.example.arn + + vpc_config { + subnet_ids = ["subnet-12345", "subnet-67890"] + } +} + +# remote_access block is not present +resource "aws_eks_node_group" "good_example_1" { + cluster_name = aws_eks_cluster.example.name + node_role_arn = aws_iam_role.example.arn + subnet_ids = ["subnet-12345", "subnet-67890"] + node_group_name = "good-example-node-group" + + scaling_config { + desired_size = 1 + max_size = 2 + min_size = 1 + } +} + +# remote_access block is present with ec2_ssh_key and without source_security_group_ids +resource "aws_eks_node_group" "bad_example" { + cluster_name = aws_eks_cluster.example.name + node_role_arn = aws_iam_role.example.arn + subnet_ids = ["subnet-12345", "subnet-67890"] + node_group_name = "bad-example-node-group" + + scaling_config { + desired_size = 1 + max_size = 2 + min_size = 1 + } + + remote_access { + ec2_ssh_key = "some-key" + } +} diff --git a/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/bad-payload-01.json b/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/bad-payload-01.json new file mode 100644 index 00000000..78b830f8 --- /dev/null +++ b/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/bad-payload-01.json @@ -0,0 +1,73 @@ +{ + "provider": { + "aws": [ + { + "region": "us-west-2" + } + ] + }, + "resource": { + "aws_eks_cluster": { + "example": [ + { + "name": "example-cluster", + "role_arn": "${aws_iam_role.example.arn}", + "vpc_config": [ + { + "subnet_ids": [ + "subnet-12345", + "subnet-67890" + ] + } + ] + } + ] + }, + "aws_eks_node_group": { + "bad_example": [ + { + "cluster_name": "${aws_eks_cluster.example.name}", + "node_group_name": "bad-example-node-group", + "node_role_arn": "${aws_iam_role.example.arn}", + "remote_access": [ + { + "ec2_ssh_key": "some-key" + } + ], + "scaling_config": [ + { + "desired_size": 1, + "max_size": 2, + "min_size": 1 + } + ], + "subnet_ids": [ + "subnet-12345", + "subnet-67890" + ] + } + ] + }, + "aws_iam_role": { + "example": [ + { + "assume_role_policy": "${jsonencode({\n Version = \"2012-10-17\"\n Statement = [{\n Action = \"sts:AssumeRole\"\n Effect = \"Allow\"\n Principal = {\n Service = \"eks.amazonaws.com\"\n }\n }]\n })}", + "name": "example-role" + } + ] + } + }, + "terraform": [ + { + "required_providers": [ + { + "aws": { + "source": "hashicorp/aws", + "version": "~\u003e 4.16" + } + } + ], + "required_version": "\u003e= 1.2.0" + } + ] +} \ No newline at end of file diff --git a/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/bad-payload-02.json b/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/bad-payload-02.json new file mode 100644 index 00000000..f827b8af --- /dev/null +++ b/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/bad-payload-02.json @@ -0,0 +1,91 @@ +{ + "provider": { + "aws": [ + { + "region": "us-west-2" + } + ] + }, + "resource": { + "aws_eks_cluster": { + "example": [ + { + "name": "example-cluster", + "role_arn": "${aws_iam_role.example.arn}", + "vpc_config": [ + { + "subnet_ids": [ + "subnet-12345", + "subnet-67890" + ] + } + ] + } + ] + }, + "aws_eks_node_group": { + "bad_example": [ + { + "cluster_name": "${aws_eks_cluster.example.name}", + "node_group_name": "bad-example-node-group", + "node_role_arn": "${aws_iam_role.example.arn}", + "remote_access": [ + { + "ec2_ssh_key": "some-key" + } + ], + "scaling_config": [ + { + "desired_size": 1, + "max_size": 2, + "min_size": 1 + } + ], + "subnet_ids": [ + "subnet-12345", + "subnet-67890" + ] + } + ], + "good_example_1": [ + { + "cluster_name": "${aws_eks_cluster.example.name}", + "node_group_name": "good-example-node-group", + "node_role_arn": "${aws_iam_role.example.arn}", + "scaling_config": [ + { + "desired_size": 1, + "max_size": 2, + "min_size": 1 + } + ], + "subnet_ids": [ + "subnet-12345", + "subnet-67890" + ] + } + ] + }, + "aws_iam_role": { + "example": [ + { + "assume_role_policy": "${jsonencode({\n Version = \"2012-10-17\"\n Statement = [{\n Action = \"sts:AssumeRole\"\n Effect = \"Allow\"\n Principal = {\n Service = \"eks.amazonaws.com\"\n }\n }]\n })}", + "name": "example-role" + } + ] + } + }, + "terraform": [ + { + "required_providers": [ + { + "aws": { + "source": "hashicorp/aws", + "version": "~\u003e 4.16" + } + } + ], + "required_version": "\u003e= 1.2.0" + } + ] +} \ No newline at end of file diff --git a/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/binding.yaml b/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/binding.yaml new file mode 100644 index 00000000..5d03d04f --- /dev/null +++ b/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/binding.yaml @@ -0,0 +1,3 @@ +analyzer: + resource: + type: terraform-config \ No newline at end of file diff --git a/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/chainsaw-test.yaml b/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/chainsaw-test.yaml new file mode 100644 index 00000000..045c1146 --- /dev/null +++ b/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/chainsaw-test.yaml @@ -0,0 +1,172 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/kyverno/chainsaw/main/.schemas/json/test-chainsaw-v1alpha1.json +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: good-test-01 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --payload ./good-payload-01.json --policy ../check-nodegroup-remote-access.yaml --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-nodegroup-remote-access + rules: + - rule: + name: check-nodegroup-remote-access + error: ~ + violations: ~ +--- +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: good-test-02 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --payload ./good-payload-02.json --policy ../check-nodegroup-remote-access.yaml --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-nodegroup-remote-access + rules: + - rule: + name: check-nodegroup-remote-access + 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 --payload ./good-payload-03.json --policy ../check-nodegroup-remote-access.yaml --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-nodegroup-remote-access + rules: + - rule: + name: check-nodegroup-remote-access + 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 --payload ./good-payload-04.json --policy ../check-nodegroup-remote-access.yaml --output json --bindings ./binding.yaml + check: + ($error): ~ + (json_parse($stdout)): + - results: + - policy: + apiVersion: json.kyverno.io/v1alpha1 + kind: ValidatingPolicy + metadata: + name: check-nodegroup-remote-access + rules: + - rule: + name: check-nodegroup-remote-access + error: ~ + violations: ~ +--- +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: bad-test-01 +spec: + steps: + - name: kyverno-json + try: + - script: + content: | + set -e + kyverno-json scan --policy ../check-nodegroup-remote-access.yaml --payload ./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-nodegroup-remote-access + rules: + - rule: + name: check-nodegroup-remote-access + error: ~ + violations: + - (contains(message, 'AWS EKS node group should not have implicit SSH access from 0.0.0.0/0')): true + errors: + - type: FieldValueInvalid + value: true + detail: 'Expected value: false' +--- +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 ../check-nodegroup-remote-access.yaml --payload ./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: check-nodegroup-remote-access + rules: + - rule: + name: check-nodegroup-remote-access + error: ~ + violations: + - (contains(message, 'AWS EKS node group should not have implicit SSH access from 0.0.0.0/0')): true + errors: + - type: FieldValueInvalid + value: true + detail: 'Expected value: false' diff --git a/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/good-01.tf b/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/good-01.tf new file mode 100644 index 00000000..30aa8c66 --- /dev/null +++ b/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/good-01.tf @@ -0,0 +1,76 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 4.16" + } + } + + required_version = ">= 1.2.0" +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_iam_role" "example" { + name = "example-role" + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [{ + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "eks.amazonaws.com" + } + }] + }) +} + +resource "aws_iam_role_policy_attachment" "example" { + role = aws_iam_role.example.name + policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy" +} + +resource "aws_eks_cluster" "example" { + name = "example-cluster" + role_arn = aws_iam_role.example.arn + + vpc_config { + subnet_ids = ["subnet-12345", "subnet-67890"] + } +} + +# remote_access block is not present +resource "aws_eks_node_group" "good_example_1" { + cluster_name = aws_eks_cluster.example.name + node_role_arn = aws_iam_role.example.arn + subnet_ids = ["subnet-12345", "subnet-67890"] + node_group_name = "good-example-node-group" + + scaling_config { + desired_size = 1 + max_size = 2 + min_size = 1 + } +} + +# remote_access block is present with ec2_ssh_key and with source_security_group_ids +resource "aws_eks_node_group" "good_example_2" { + cluster_name = aws_eks_cluster.example.name + node_role_arn = aws_iam_role.example.arn + subnet_ids = ["subnet-12345", "subnet-67890"] + node_group_name = "good-example-2-node-group" + + scaling_config { + desired_size = 2 + max_size = 4 + min_size = 2 + } + + remote_access { + ec2_ssh_key = "some-key" + source_security_group_ids = ["sg-12345678"] + } +} diff --git a/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/good-02.tf b/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/good-02.tf new file mode 100644 index 00000000..29e43d02 --- /dev/null +++ b/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/good-02.tf @@ -0,0 +1,59 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 4.16" + } + } + + required_version = ">= 1.2.0" +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_iam_role" "example" { + name = "example-role" + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [{ + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "eks.amazonaws.com" + } + }] + }) +} + +resource "aws_eks_cluster" "example" { + name = "example-cluster" + role_arn = aws_iam_role.example.arn + + vpc_config { + subnet_ids = ["subnet-12345", "subnet-67890"] + } +} + +# remote_access block is present with ec2_ssh_key and with source_security_group_ids +resource "aws_eks_node_group" "good_example" { + cluster_name = aws_eks_cluster.example.name + node_role_arn = aws_iam_role.example.arn + subnet_ids = ["subnet-12345", "subnet-67890"] + node_group_name = "good-example-node-group" + + scaling_config { + desired_size = 1 + max_size = 2 + min_size = 1 + } + + remote_access { + ec2_ssh_key = "some-key" + source_security_group_ids = ["sg-12345678"] + } +} + + diff --git a/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/good-03.tf b/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/good-03.tf new file mode 100644 index 00000000..f6011053 --- /dev/null +++ b/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/good-03.tf @@ -0,0 +1,58 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 4.16" + } + } + + required_version = ">= 1.2.0" +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_iam_role" "example" { + name = "example-role" + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [{ + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "eks.amazonaws.com" + } + }] + }) +} + +resource "aws_eks_cluster" "example" { + name = "example-cluster" + role_arn = aws_iam_role.example.arn + + vpc_config { + subnet_ids = ["subnet-12345", "subnet-67890"] + } +} + +# remote_access block is present without ec2_ssh_key and without source_security_group_ids +resource "aws_eks_node_group" "good_example" { + cluster_name = aws_eks_cluster.example.name + node_role_arn = aws_iam_role.example.arn + subnet_ids = ["subnet-12345", "subnet-67890"] + node_group_name = "good-example-node-group" + + scaling_config { + desired_size = 1 + max_size = 2 + min_size = 1 + } + + remote_access { + + } +} + + diff --git a/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/good-04.tf b/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/good-04.tf new file mode 100644 index 00000000..d5520550 --- /dev/null +++ b/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/good-04.tf @@ -0,0 +1,58 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 4.16" + } + } + + required_version = ">= 1.2.0" +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_iam_role" "example" { + name = "example-role" + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [{ + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "eks.amazonaws.com" + } + }] + }) +} + +resource "aws_eks_cluster" "example" { + name = "example-cluster" + role_arn = aws_iam_role.example.arn + + vpc_config { + subnet_ids = ["subnet-12345", "subnet-67890"] + } +} + +# remote_access block is present without ec2_ssh_key and with source_security_group_ids +resource "aws_eks_node_group" "good_example" { + cluster_name = aws_eks_cluster.example.name + node_role_arn = aws_iam_role.example.arn + subnet_ids = ["subnet-12345", "subnet-67890"] + node_group_name = "good-example-node-group" + + scaling_config { + desired_size = 1 + max_size = 2 + min_size = 1 + } + + remote_access { + source_security_group_ids = ["sg-12345678"] + } +} + + diff --git a/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/good-payload-01.json b/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/good-payload-01.json new file mode 100644 index 00000000..96b2f841 --- /dev/null +++ b/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/good-payload-01.json @@ -0,0 +1,102 @@ +{ + "provider": { + "aws": [ + { + "region": "us-west-2" + } + ] + }, + "resource": { + "aws_eks_cluster": { + "example": [ + { + "name": "example-cluster", + "role_arn": "${aws_iam_role.example.arn}", + "vpc_config": [ + { + "subnet_ids": [ + "subnet-12345", + "subnet-67890" + ] + } + ] + } + ] + }, + "aws_eks_node_group": { + "good_example_1": [ + { + "cluster_name": "${aws_eks_cluster.example.name}", + "node_group_name": "good-example-node-group", + "node_role_arn": "${aws_iam_role.example.arn}", + "scaling_config": [ + { + "desired_size": 1, + "max_size": 2, + "min_size": 1 + } + ], + "subnet_ids": [ + "subnet-12345", + "subnet-67890" + ] + } + ], + "good_example_2": [ + { + "cluster_name": "${aws_eks_cluster.example.name}", + "node_group_name": "good-example-2-node-group", + "node_role_arn": "${aws_iam_role.example.arn}", + "remote_access": [ + { + "ec2_ssh_key": "some-key", + "source_security_group_ids": [ + "sg-12345678" + ] + } + ], + "scaling_config": [ + { + "desired_size": 2, + "max_size": 4, + "min_size": 2 + } + ], + "subnet_ids": [ + "subnet-12345", + "subnet-67890" + ] + } + ] + }, + "aws_iam_role": { + "example": [ + { + "assume_role_policy": "${jsonencode({\n Version = \"2012-10-17\"\n Statement = [{\n Action = \"sts:AssumeRole\"\n Effect = \"Allow\"\n Principal = {\n Service = \"eks.amazonaws.com\"\n }\n }]\n })}", + "name": "example-role" + } + ] + }, + "aws_iam_role_policy_attachment": { + "example": [ + { + "policy_arn": "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy", + "role": "${aws_iam_role.example.name}" + } + ] + } + }, + "terraform": [ + { + "required_providers": [ + { + "aws": { + "source": "hashicorp/aws", + "version": "~\u003e 4.16" + } + } + ], + "required_version": "\u003e= 1.2.0" + } + ] +} \ No newline at end of file diff --git a/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/good-payload-02.json b/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/good-payload-02.json new file mode 100644 index 00000000..5388cccb --- /dev/null +++ b/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/good-payload-02.json @@ -0,0 +1,76 @@ +{ + "provider": { + "aws": [ + { + "region": "us-west-2" + } + ] + }, + "resource": { + "aws_eks_cluster": { + "example": [ + { + "name": "example-cluster", + "role_arn": "${aws_iam_role.example.arn}", + "vpc_config": [ + { + "subnet_ids": [ + "subnet-12345", + "subnet-67890" + ] + } + ] + } + ] + }, + "aws_eks_node_group": { + "good_example": [ + { + "cluster_name": "${aws_eks_cluster.example.name}", + "node_group_name": "good-example-node-group", + "node_role_arn": "${aws_iam_role.example.arn}", + "remote_access": [ + { + "ec2_ssh_key": "some-key", + "source_security_group_ids": [ + "sg-12345678" + ] + } + ], + "scaling_config": [ + { + "desired_size": 1, + "max_size": 2, + "min_size": 1 + } + ], + "subnet_ids": [ + "subnet-12345", + "subnet-67890" + ] + } + ] + }, + "aws_iam_role": { + "example": [ + { + "assume_role_policy": "${jsonencode({\n Version = \"2012-10-17\"\n Statement = [{\n Action = \"sts:AssumeRole\"\n Effect = \"Allow\"\n Principal = {\n Service = \"eks.amazonaws.com\"\n }\n }]\n })}", + "name": "example-role" + } + ] + } + }, + "terraform": [ + { + "required_providers": [ + { + "aws": { + "source": "hashicorp/aws", + "version": "~\u003e 4.16" + } + } + ], + "required_version": "\u003e= 1.2.0" + } + ] +} \ No newline at end of file diff --git a/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/good-payload-03.json b/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/good-payload-03.json new file mode 100644 index 00000000..2ec230e8 --- /dev/null +++ b/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/good-payload-03.json @@ -0,0 +1,71 @@ +{ + "provider": { + "aws": [ + { + "region": "us-west-2" + } + ] + }, + "resource": { + "aws_eks_cluster": { + "example": [ + { + "name": "example-cluster", + "role_arn": "${aws_iam_role.example.arn}", + "vpc_config": [ + { + "subnet_ids": [ + "subnet-12345", + "subnet-67890" + ] + } + ] + } + ] + }, + "aws_eks_node_group": { + "good_example": [ + { + "cluster_name": "${aws_eks_cluster.example.name}", + "node_group_name": "good-example-node-group", + "node_role_arn": "${aws_iam_role.example.arn}", + "remote_access": [ + {} + ], + "scaling_config": [ + { + "desired_size": 1, + "max_size": 2, + "min_size": 1 + } + ], + "subnet_ids": [ + "subnet-12345", + "subnet-67890" + ] + } + ] + }, + "aws_iam_role": { + "example": [ + { + "assume_role_policy": "${jsonencode({\n Version = \"2012-10-17\"\n Statement = [{\n Action = \"sts:AssumeRole\"\n Effect = \"Allow\"\n Principal = {\n Service = \"eks.amazonaws.com\"\n }\n }]\n })}", + "name": "example-role" + } + ] + } + }, + "terraform": [ + { + "required_providers": [ + { + "aws": { + "source": "hashicorp/aws", + "version": "~\u003e 4.16" + } + } + ], + "required_version": "\u003e= 1.2.0" + } + ] +} \ No newline at end of file diff --git a/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/good-payload-04.json b/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/good-payload-04.json new file mode 100644 index 00000000..bea4ebf0 --- /dev/null +++ b/terraform/config/eks-best-practices/check-nodegroup-remote-access/test/good-payload-04.json @@ -0,0 +1,75 @@ +{ + "provider": { + "aws": [ + { + "region": "us-west-2" + } + ] + }, + "resource": { + "aws_eks_cluster": { + "example": [ + { + "name": "example-cluster", + "role_arn": "${aws_iam_role.example.arn}", + "vpc_config": [ + { + "subnet_ids": [ + "subnet-12345", + "subnet-67890" + ] + } + ] + } + ] + }, + "aws_eks_node_group": { + "good_example": [ + { + "cluster_name": "${aws_eks_cluster.example.name}", + "node_group_name": "good-example-node-group", + "node_role_arn": "${aws_iam_role.example.arn}", + "remote_access": [ + { + "source_security_group_ids": [ + "sg-12345678" + ] + } + ], + "scaling_config": [ + { + "desired_size": 1, + "max_size": 2, + "min_size": 1 + } + ], + "subnet_ids": [ + "subnet-12345", + "subnet-67890" + ] + } + ] + }, + "aws_iam_role": { + "example": [ + { + "assume_role_policy": "${jsonencode({\n Version = \"2012-10-17\"\n Statement = [{\n Action = \"sts:AssumeRole\"\n Effect = \"Allow\"\n Principal = {\n Service = \"eks.amazonaws.com\"\n }\n }]\n })}", + "name": "example-role" + } + ] + } + }, + "terraform": [ + { + "required_providers": [ + { + "aws": { + "source": "hashicorp/aws", + "version": "~\u003e 4.16" + } + } + ], + "required_version": "\u003e= 1.2.0" + } + ] +} \ No newline at end of file diff --git a/terraform/config/eks-best-practices/check-public-access-cidr/README.md b/terraform/config/eks-best-practices/check-public-access-cidr/README.md new file mode 100644 index 00000000..cd11f765 --- /dev/null +++ b/terraform/config/eks-best-practices/check-public-access-cidr/README.md @@ -0,0 +1,86 @@ +# Check Public Access Cidr + +When you create a new cluster, Amazon EKS creates an endpoint for the managed Kubernetes API server that you use to communicate with your cluster (using Kubernetes management tools such as kubectl). By default, this API server endpoint receives requests from all (**0.0.0.0/0**) IP addresses. Disallowing access to **0.0.0.0/0** endpoint is a fundamental security measure that helps protect your EKS clusters from unauthorized access, security threats, and compliance violations. + +You can read more about it [here](https://docs.aws.amazon.com/eks/latest/userguide/cluster-endpoint.html) + +## Policy Details: + +- **Policy Name:** check-public-access-cidr +- **Check Description:** Ensuring that the Amazon EKS public endpoint is not accessible to 0.0.0.0/0 +- **Policy Category:** EKS Best Practices + +### 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 `nctl` installed on the machine + +1. **Test the Policy with nctl:** + ``` + nctl scan terraform --resources tf-config.tf --policy policy.yaml + ``` + + a. **Test Policy Against Valid Terraform Config File:** + ``` + nctl scan terraform --resources test/good-01.tf --policies check-public-access-cidr.yaml --details + ``` + + This produces the output: + ``` + Version: v4.2.2 + Fetching policies... + Loading policies... + - found 1 policies + Running analysis... + • no errors + Results... + +--------------------+------+------+------+-------+------+ + | CATEGORY | FAIL | WARN | PASS | ERROR | SKIP | + +--------------------+------+------+------+-------+------+ + | EKS Best Practices | 0 | 0 | 1 | 0 | 0 | + +--------------------+------+------+------+-------+------+ + Rule Results : (Fail: 0, Warn: 0, Pass: 1, Error: 0, Skip: 0) + Failed Rules Severity : (Critical: 0, High: 0, Medium: 0, Low: 0, Info: 0) + + +--------------------------+--------------------------+-----------------+---------+--------+ + | POLICY | RULE | RESOURCE | MESSAGE | RESULT | + +--------------------------+--------------------------+-----------------+---------+--------+ + | check-public-access-cidr | check-public-access-cidr | test/good-01.tf | | pass | + +--------------------------+--------------------------+-----------------+---------+--------+ + Done! + ``` + + b. **Test Against Invalid Terraform Config File:** + ``` + nctl scan terraform --resources test/bad-01.tf --policies check-public-access-cidr.yaml --details + ``` + + This produces the output: + ``` + Version: v4.2.2 + Fetching policies... + Loading policies... + - found 1 policies + Running analysis... + • no errors + Results... + +--------------------+------+------+------+-------+------+ + | CATEGORY | FAIL | WARN | PASS | ERROR | SKIP | + +--------------------+------+------+------+-------+------+ + | EKS Best Practices | 1 | 0 | 0 | 0 | 0 | + +--------------------+------+------+------+-------+------+ + Rule Results : (Fail: 1, Warn: 0, Pass: 0, Error: 0, Skip: 0) + Failed Rules Severity : (Critical: 0, High: 1, Medium: 0, Low: 0, Info: 0) + + +--------------------------+--------------------------+----------------+--------------------------------+--------+ + | POLICY | RULE | RESOURCE | MESSAGE | RESULT | + +--------------------------+--------------------------+----------------+--------------------------------+--------+ + | check-public-access-cidr | check-public-access-cidr | test/bad-01.tf | Public endpoint should not be | fail | + | | | | accessible to 0.0.0.0/0 | | + +--------------------------+--------------------------+----------------+--------------------------------+--------+ + Done! 1 policy violation(s) detected. + ``` + +--- \ No newline at end of file diff --git a/terraform/config/eks-best-practices/check-public-access-cidr/check-public-access-cidr.yaml b/terraform/config/eks-best-practices/check-public-access-cidr/check-public-access-cidr.yaml new file mode 100644 index 00000000..f45e1339 --- /dev/null +++ b/terraform/config/eks-best-practices/check-public-access-cidr/check-public-access-cidr.yaml @@ -0,0 +1,26 @@ +apiVersion: json.kyverno.io/v1alpha1 +kind: ValidatingPolicy +metadata: + name: check-public-access-cidr + annotations: + policies.kyverno.io/title: Ensure Amazon EKS public endpoint not accessible to 0.0.0.0/0 + policies.kyverno.io/category: EKS Best Practices + policies.kyverno.io/severity: high + policies.kyverno.io/description: >- + Ensuring that the Amazon EKS public endpoint is not accessible to 0.0.0.0/0 is a fundamental security measure that + helps protect your EKS clusters from unauthorized access, security threats, and compliance violations. +spec: + rules: + - name: check-public-access-cidr + match: + all: + - ($analyzer.resource.type): terraform-config + - (resource.aws_eks_cluster != null): true + assert: + all: + - message: Public endpoint should not be accessible to 0.0.0.0/0 + check: + ~.(resource.aws_eks_cluster.values(@)[]): + ~.(vpc_config[?endpoint_public_access == null || endpoint_public_access == `true`]): + (public_access_cidrs != null && !contains(public_access_cidrs, '0.0.0.0/0')): true + diff --git a/terraform/config/eks-best-practices/check-public-access-cidr/test/bad-01.tf b/terraform/config/eks-best-practices/check-public-access-cidr/test/bad-01.tf new file mode 100644 index 00000000..8c62057d --- /dev/null +++ b/terraform/config/eks-best-practices/check-public-access-cidr/test/bad-01.tf @@ -0,0 +1,54 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 4.16" + } + } + + required_version = ">= 1.2.0" +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_iam_role" "example_role" { + name = "example_role" + + assume_role_policy = <- + Disabling the public endpoint minimizes the risk of unauthorized access and potential security breaches by reducing the attack surface of the EKS control plane. + It protects against external threats and enforces network segmentation, restricting access to only trusted entities within the network environment. + This measure helps organizations meet compliance requirements, maintains operational security, and safeguards the reliability and performance of Kubernetes clusters. +spec: + rules: + - name: check-public-endpoint + match: + all: + - ($analyzer.resource.type): terraform-config + - (resource.aws_eks_cluster != null): true + assert: + all: + - message: Public access to EKS cluster endpoint must be explicitly set to false + check: + ~.(resource.aws_eks_cluster.values(@)[]): + ~.(vpc_config): + (endpoint_public_access != null && endpoint_public_access == `false`): true + diff --git a/terraform/config/eks-best-practices/check-public-endpoint/test/bad-01.tf b/terraform/config/eks-best-practices/check-public-endpoint/test/bad-01.tf new file mode 100644 index 00000000..7b1c80f8 --- /dev/null +++ b/terraform/config/eks-best-practices/check-public-endpoint/test/bad-01.tf @@ -0,0 +1,44 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 4.16" + } + } + + required_version = ">= 1.2.0" +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_iam_role" "example_role" { + name = "example_role" + + assume_role_policy = <- + Secrets encryption is essential to encrypt sensitive data, such as secrets and credentials stored within Kubernetes, adding an additional layer of protection against unauthorized access +spec: + rules: + - name: check-secrets-encryption + match: + all: + - ($analyzer.resource.type): terraform-config + - (resource.aws_eks_cluster != null): true + assert: + all: + - message: Encryption config must be present for all clusters + check: + ~.(resource.aws_eks_cluster.values(@)[]): + (contains(keys(@), 'encryption_config')): true + - message: Secrets must be encrypted to avoid unauthorized access + check: + ~.(resource.aws_eks_cluster.values(@)[].encryption_config[]): + (contains(resources, 'secrets')): true + diff --git a/terraform/config/eks-best-practices/check-secrets-encryption/test/bad-01.tf b/terraform/config/eks-best-practices/check-secrets-encryption/test/bad-01.tf new file mode 100644 index 00000000..134ed8fc --- /dev/null +++ b/terraform/config/eks-best-practices/check-secrets-encryption/test/bad-01.tf @@ -0,0 +1,72 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 4.16" + } + } + + required_version = ">= 1.2.0" +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_kms_key" "example" { + description = "KMS key for EKS cluster encryption" +} + +resource "aws_iam_role" "example_role" { + name = "example_role" + + assume_role_policy = <- + This policy checks that EKS clusters are on a supported Kubernetes version +spec: + rules: + - name: check-supported-k8s-version + match: + all: + - ($analyzer.resource.type): terraform-config + - (resource.aws_eks_cluster != null): true + context: + - name: supported_k8s_versions + variable: + - '1.23' + - '1.24' + - '1.25' + - '1.26' + - '1.27' + - '1.28' + - '1.29' + - '1.30' + assert: + all: + - message: "Version specified must be one of these suppported versions ['1.23', '1.24', '1.25', '1.26', '1.27', '1.28', '1.29', '1.30']" + check: + ~.(resource.aws_eks_cluster.values(@)[].version): + (contains($supported_k8s_versions, @)): true + diff --git a/terraform/config/eks-best-practices/check-supported-k8s-version/test/bad-payload.json b/terraform/config/eks-best-practices/check-supported-k8s-version/test/bad-payload.json new file mode 100644 index 00000000..b8e5ddff --- /dev/null +++ b/terraform/config/eks-best-practices/check-supported-k8s-version/test/bad-payload.json @@ -0,0 +1,48 @@ +{ + "provider": { + "aws": [ + { + "region": "us-west-2" + } + ] + }, + "resource": { + "aws_eks_cluster": { + "example": [ + { + "name": "example", + "role_arn": "${aws_iam_role.example_role.arn}", + "version": "1.21", + "vpc_config": [ + { + "subnet_ids": [ + "subnet-01" + ] + } + ] + } + ] + }, + "aws_iam_role": { + "example_role": [ + { + "assume_role_policy": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Action\": \"sts:AssumeRole\",\n \"Effect\": \"Allow\",\n \"Principal\": {\n \"Service\": \"eks.amazonaws.com\"\n }\n }\n ]\n}\n", + "name": "example_role" + } + ] + } + }, + "terraform": [ + { + "required_providers": [ + { + "aws": { + "source": "hashicorp/aws", + "version": "~\u003e 4.16" + } + } + ], + "required_version": "\u003e= 1.2.0" + } + ] +} \ No newline at end of file diff --git a/terraform/config/eks-best-practices/check-supported-k8s-version/test/bad.tf b/terraform/config/eks-best-practices/check-supported-k8s-version/test/bad.tf new file mode 100644 index 00000000..c7747d3e --- /dev/null +++ b/terraform/config/eks-best-practices/check-supported-k8s-version/test/bad.tf @@ -0,0 +1,45 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 4.16" + } + } + + required_version = ">= 1.2.0" +} + +provider "aws" { + region = "us-west-2" +} + +resource "aws_iam_role" "example_role" { + name = "example_role" + + assume_role_policy = <