From 5bd6ab2f8ae0671f5995dc3919241f4feee9dc7c Mon Sep 17 00:00:00 2001 From: alilek Date: Fri, 26 Jun 2026 23:23:11 +0300 Subject: [PATCH 1/6] feat(lab6): Checkov + KICS scans + custom RDS deletion protection policy --- labs/lab6/policies/custom_checks/__init__.py | 0 .../custom_checks/rds_deletion_protection.py | 24 ++ .../policies/rds-deletion-protection.yaml | 11 + submissions/lab6.md | 226 ++++++++++++++++++ 4 files changed, 261 insertions(+) create mode 100644 labs/lab6/policies/custom_checks/__init__.py create mode 100644 labs/lab6/policies/custom_checks/rds_deletion_protection.py create mode 100644 labs/lab6/policies/rds-deletion-protection.yaml create mode 100644 submissions/lab6.md diff --git a/labs/lab6/policies/custom_checks/__init__.py b/labs/lab6/policies/custom_checks/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/labs/lab6/policies/custom_checks/rds_deletion_protection.py b/labs/lab6/policies/custom_checks/rds_deletion_protection.py new file mode 100644 index 000000000..a54c7b05a --- /dev/null +++ b/labs/lab6/policies/custom_checks/rds_deletion_protection.py @@ -0,0 +1,24 @@ +from checkov.common.models.enums import CheckResult, CheckCategories +from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck + + +class RDSDeletionProtection(BaseResourceCheck): + def __init__(self): + name = "Ensure RDS instances have deletion_protection enabled" + id = "CKV_CUSTOM_1" + supported_resources = ['aws_db_instance'] + categories = [CheckCategories.GENERAL_SECURITY] + super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources) + + def scan_resource_conf(self, conf): + """ + Looks for deletion_protection configuration in aws_db_instance: + https://www.terraform.io/docs/providers/aws/r/db_instance.html + """ + if 'deletion_protection' in conf: + if conf['deletion_protection'][0] == True: + return CheckResult.PASSED + return CheckResult.FAILED + + +check = RDSDeletionProtection() \ No newline at end of file diff --git a/labs/lab6/policies/rds-deletion-protection.yaml b/labs/lab6/policies/rds-deletion-protection.yaml new file mode 100644 index 000000000..686b880ea --- /dev/null +++ b/labs/lab6/policies/rds-deletion-protection.yaml @@ -0,0 +1,11 @@ +metadata: + id: CKV_CUSTOM_1 + name: "Ensure RDS instances have deletion_protection enabled" + category: "GENERAL_SECURITY" + severity: HIGH +definition: + cond_type: "attribute" + resource_types: + - "aws_db_instance" + attribute: "deletion_protection" + value: "true" diff --git a/submissions/lab6.md b/submissions/lab6.md new file mode 100644 index 000000000..446c20aac --- /dev/null +++ b/submissions/lab6.md @@ -0,0 +1,226 @@ +\# Lab 6 — Submission + + + +\## Task 1: Checkov on Terraform + + + +\### Terraform scan + +\- \*\*Total checks:\*\* 129 (49 passed, 80 failed) + +\- \*\*Secrets scan:\*\* 2 failed (CKV\_SECRET\_2, CKV\_SECRET\_6) + + + +| Severity | Count | + +|----------|------:| + +| Critical | 1 (Hardcoded AWS credentials) | + +| High | \~30 (IAM wildcard policies, public S3, exposed security groups) | + +| Medium | \~25 (Missing encryption, logging, backups) | + +| Low | \~24 (Missing descriptions, tags, best practices) | + + + +\*Note: Checkov CE does not populate `severity` field for most rules without Bridgecrew API key. Severity estimates above are based on official Checkov documentation.\* + + + +\### Top 5 rule IDs (by frequency) + +| Rule ID | Count | What it checks | + +|---------|------:|----------------| + +| CKV\_AWS\_289 | 4 | IAM policies allow permissions management without constraints | + +| CKV\_AWS\_355 | 4 | IAM policies allow "\*" as resource for restrictable actions | + +| CKV\_AWS\_23 | 3 | Security group rules missing descriptions | + +| CKV\_AWS\_288 | 3 | IAM policies allow data exfiltration | + +| CKV\_AWS\_290 | 3 | IAM policies allow unconstrained write access | + + + +\### Module-leverage analysis (Lecture 6 slide 17) + +Looking at the top-5 Terraform rules, the \*\*single highest-leverage fix\*\* is enforcing least-privilege IAM policies at the module level. Rules CKV\_AWS\_289, CKV\_AWS\_355, CKV\_AWS\_288, and CKV\_AWS\_290 all fire because `iam.tf` contains policies with `Action = "\*"` and `Resource = "\*"`. If the IAM module enforced a policy template that requires explicit actions and scoped resources (e.g., using AWS managed policies or customer-managed policies with specific ARNs), all 14+ IAM-related findings would vanish with one architectural change. Similarly, adding a default `aws\_s3\_bucket\_public\_access\_block` resource to the S3 module with all four block flags set to `true` would eliminate CKV\_AWS\_53/54/55/56 across all buckets. + + + +\--- + + + +\## Task 2: KICS on Ansible + Pulumi + + + +\### KICS Ansible Severity breakdown + +| Severity | Count | + +|----------|------:| + +| CRITICAL | 0 | + +| HIGH | 9 | + +| MEDIUM | 0 | + +| LOW | 1 | + +| INFO | 0 | + +| \*\*Total\*\* | \*\*10\*\* | + + + +\### Top 5 KICS queries (Ansible, by frequency) + +| Query | Severity | Files | + +|-------|----------|------:| + +| Passwords And Secrets - Generic Password | HIGH | 6 | + +| Passwords And Secrets - Password in URL | HIGH | 2 | + +| Passwords And Secrets - Generic Secret | HIGH | 1 | + +| Unpinned Package Version | LOW | 1 | + + + +\### KICS Pulumi Severity breakdown + +| Severity | Count | + +|----------|------:| + +| CRITICAL | 1 (RDS publicly accessible) | + +| HIGH | 2 (DynamoDB not encrypted, hardcoded password) | + +| MEDIUM | 1 (EC2 monitoring disabled) | + +| LOW | 0 | + +| INFO | 2 | + +| \*\*Total\*\* | \*\*6\*\* | + + + +\### Checkov vs KICS — when to use which? (Lecture 6 slide 10) + +\- \*\*One thing Checkov did better for Terraform:\*\* Checkov natively understands Terraform's graph model and caught cross-resource misconfigurations like `CKV2\_AWS\_5` (security groups not attached to any resource) and `CKV2\_AWS\_6` (S3 bucket without public access block). These graph-based checks require understanding relationships between resources, which KICS cannot do because it scans files statically. + +\- \*\*One thing KICS did better for Ansible:\*\* KICS uses Rego queries that are format-agnostic and accurately parsed the Ansible playbook structure, flagging Linux hardening gaps like hardcoded passwords in `inventory.ini` and `configure.yml`. Checkov's Ansible support is limited to cloud modules, not OS configuration playbooks. + +\- \*\*Example of single-tool catch:\*\* Checkov flagged `CKV\_SECRET\_2` (AWS Access Key) in `main.tf` because it runs a dedicated secrets engine with pattern matching for AWS key formats (`AKIA...`). KICS skipped it because KICS focuses on infrastructure misconfiguration queries, not secret pattern detection. + + + +\--- + + + +\## Bonus: Custom Checkov Policy + + + +\### Policy file (`labs/lab6/policies/custom\_checks/rds\_deletion\_protection.py`) + +```python + +from checkov.common.models.enums import CheckResult, CheckCategories + +from checkov.terraform.checks.resource.base\_resource\_check import BaseResourceCheck + + + +class RDSDeletionProtection(BaseResourceCheck): + + def \_\_init\_\_(self): + + name = "Ensure RDS instances have deletion\_protection enabled" + + id = "CKV\_CUSTOM\_1" + + supported\_resources = \['aws\_db\_instance'] + + categories = \[CheckCategories.GENERAL\_SECURITY] + + super().\_\_init\_\_(name=name, id=id, categories=categories, supported\_resources=supported\_resources) + + + + def scan\_resource\_conf(self, conf): + + if 'deletion\_protection' in conf: + + if conf\['deletion\_protection']\[0] == True: + + return CheckResult.PASSED + + return CheckResult.FAILED + + + +check = RDSDeletionProtection() + +``` + + + +\### Rule fires (Proof) + +The custom policy successfully fired on both RDS instances in `database.tf`: + +```json + +{ + + "check\_id": "CKV\_CUSTOM\_1", + + "check\_name": "Ensure RDS instances have deletion\_protection enabled", + + "check\_result": { "result": "FAILED" }, + + "resource": "aws\_db\_instance.unencrypted\_db", + + "file\_path": "\\\\database.tf" + +} + +{ + + "check\_id": "CKV\_CUSTOM\_1", + + "check\_name": "Ensure RDS instances have deletion\_protection enabled", + + "check\_result": { "result": "FAILED" }, + + "resource": "aws\_db\_instance.weak\_db", + + "file\_path": "\\\\database.tf" + +} + +``` + + + +\### Why this rule matters + +Accidental database deletion causes catastrophic data loss and downtime. The 2021 GitLab outage (caused by accidental `rm -rf`) and multiple AWS RDS incidents highlight that `deletion\_protection = true` is a critical safety net against human error or compromised CI/CD pipelines. This aligns with CIS AWS Foundations Benchmark v1.5.0 (Section 2.3.1) and NIST SP 800-144 requirement for data integrity safeguards. Enforcing it via Policy-as-Code guarantees no RDS instance reaches production without this guardrail. + From 3fa6acc895d6339b58cab19b86c8c2632523aa06 Mon Sep 17 00:00:00 2001 From: alileeeek Date: Fri, 26 Jun 2026 23:25:09 +0300 Subject: [PATCH 2/6] Update lab6.md --- submissions/lab6.md | 227 +++++++++++--------------------------------- 1 file changed, 57 insertions(+), 170 deletions(-) diff --git a/submissions/lab6.md b/submissions/lab6.md index 446c20aac..6cbc63923 100644 --- a/submissions/lab6.md +++ b/submissions/lab6.md @@ -1,226 +1,113 @@ -\# Lab 6 — Submission - - - -\## Task 1: Checkov on Terraform - - - -\### Terraform scan - -\- \*\*Total checks:\*\* 129 (49 passed, 80 failed) - -\- \*\*Secrets scan:\*\* 2 failed (CKV\_SECRET\_2, CKV\_SECRET\_6) +# Lab 6 — Submission +## Task 1: Checkov on Terraform +### Terraform scan +- **Total checks:** 129 (49 passed, 80 failed) +- **Secrets scan:** 2 failed (CKV_SECRET_2, CKV_SECRET_6) | Severity | Count | - |----------|------:| - | Critical | 1 (Hardcoded AWS credentials) | +| High | ~30 (IAM wildcard policies, public S3, exposed security groups) | +| Medium | ~25 (Missing encryption, logging, backups) | +| Low | ~24 (Missing descriptions, tags, best practices) | -| High | \~30 (IAM wildcard policies, public S3, exposed security groups) | - -| Medium | \~25 (Missing encryption, logging, backups) | - -| Low | \~24 (Missing descriptions, tags, best practices) | - - - -\*Note: Checkov CE does not populate `severity` field for most rules without Bridgecrew API key. Severity estimates above are based on official Checkov documentation.\* - - - -\### Top 5 rule IDs (by frequency) +*Note: Checkov CE does not populate `severity` field for most rules without Bridgecrew API key. Severity estimates above are based on official Checkov documentation.* +### Top 5 rule IDs (by frequency) | Rule ID | Count | What it checks | - |---------|------:|----------------| +| CKV_AWS_289 | 4 | IAM policies allow permissions management without constraints | +| CKV_AWS_355 | 4 | IAM policies allow "*" as resource for restrictable actions | +| CKV_AWS_23 | 3 | Security group rules missing descriptions | +| CKV_AWS_288 | 3 | IAM policies allow data exfiltration | +| CKV_AWS_290 | 3 | IAM policies allow unconstrained write access | -| CKV\_AWS\_289 | 4 | IAM policies allow permissions management without constraints | - -| CKV\_AWS\_355 | 4 | IAM policies allow "\*" as resource for restrictable actions | - -| CKV\_AWS\_23 | 3 | Security group rules missing descriptions | - -| CKV\_AWS\_288 | 3 | IAM policies allow data exfiltration | - -| CKV\_AWS\_290 | 3 | IAM policies allow unconstrained write access | - - - -\### Module-leverage analysis (Lecture 6 slide 17) - -Looking at the top-5 Terraform rules, the \*\*single highest-leverage fix\*\* is enforcing least-privilege IAM policies at the module level. Rules CKV\_AWS\_289, CKV\_AWS\_355, CKV\_AWS\_288, and CKV\_AWS\_290 all fire because `iam.tf` contains policies with `Action = "\*"` and `Resource = "\*"`. If the IAM module enforced a policy template that requires explicit actions and scoped resources (e.g., using AWS managed policies or customer-managed policies with specific ARNs), all 14+ IAM-related findings would vanish with one architectural change. Similarly, adding a default `aws\_s3\_bucket\_public\_access\_block` resource to the S3 module with all four block flags set to `true` would eliminate CKV\_AWS\_53/54/55/56 across all buckets. - - +### Module-leverage analysis (Lecture 6 slide 17) +Looking at the top-5 Terraform rules, the **single highest-leverage fix** is enforcing least-privilege IAM policies at the module level. Rules CKV_AWS_289, CKV_AWS_355, CKV_AWS_288, and CKV_AWS_290 all fire because `iam.tf` contains policies with `Action = "*"` and `Resource = "*"`. If the IAM module enforced a policy template that requires explicit actions and scoped resources (e.g., using AWS managed policies or customer-managed policies with specific ARNs), all 14+ IAM-related findings would vanish with one architectural change. Similarly, adding a default `aws_s3_bucket_public_access_block` resource to the S3 module with all four block flags set to `true` would eliminate CKV_AWS_53/54/55/56 across all buckets. -\--- +--- +## Task 2: KICS on Ansible + Pulumi - -\## Task 2: KICS on Ansible + Pulumi - - - -\### KICS Ansible Severity breakdown - +### KICS Ansible Severity breakdown | Severity | Count | - |----------|------:| - | CRITICAL | 0 | - | HIGH | 9 | - | MEDIUM | 0 | - | LOW | 1 | - | INFO | 0 | +| **Total** | **10** | -| \*\*Total\*\* | \*\*10\*\* | - - - -\### Top 5 KICS queries (Ansible, by frequency) - +### Top 5 KICS queries (Ansible, by frequency) | Query | Severity | Files | - |-------|----------|------:| - | Passwords And Secrets - Generic Password | HIGH | 6 | - | Passwords And Secrets - Password in URL | HIGH | 2 | - | Passwords And Secrets - Generic Secret | HIGH | 1 | - | Unpinned Package Version | LOW | 1 | - - -\### KICS Pulumi Severity breakdown - +### KICS Pulumi Severity breakdown | Severity | Count | - |----------|------:| - | CRITICAL | 1 (RDS publicly accessible) | - | HIGH | 2 (DynamoDB not encrypted, hardcoded password) | - | MEDIUM | 1 (EC2 monitoring disabled) | - | LOW | 0 | - | INFO | 2 | +| **Total** | **6** | -| \*\*Total\*\* | \*\*6\*\* | - - - -\### Checkov vs KICS — when to use which? (Lecture 6 slide 10) - -\- \*\*One thing Checkov did better for Terraform:\*\* Checkov natively understands Terraform's graph model and caught cross-resource misconfigurations like `CKV2\_AWS\_5` (security groups not attached to any resource) and `CKV2\_AWS\_6` (S3 bucket without public access block). These graph-based checks require understanding relationships between resources, which KICS cannot do because it scans files statically. - -\- \*\*One thing KICS did better for Ansible:\*\* KICS uses Rego queries that are format-agnostic and accurately parsed the Ansible playbook structure, flagging Linux hardening gaps like hardcoded passwords in `inventory.ini` and `configure.yml`. Checkov's Ansible support is limited to cloud modules, not OS configuration playbooks. - -\- \*\*Example of single-tool catch:\*\* Checkov flagged `CKV\_SECRET\_2` (AWS Access Key) in `main.tf` because it runs a dedicated secrets engine with pattern matching for AWS key formats (`AKIA...`). KICS skipped it because KICS focuses on infrastructure misconfiguration queries, not secret pattern detection. - +### Checkov vs KICS — when to use which? (Lecture 6 slide 10) +- **One thing Checkov did better for Terraform:** Checkov natively understands Terraform's graph model and caught cross-resource misconfigurations like `CKV2_AWS_5` (security groups not attached to any resource) and `CKV2_AWS_6` (S3 bucket without public access block). These graph-based checks require understanding relationships between resources, which KICS cannot do because it scans files statically. +- **One thing KICS did better for Ansible:** KICS uses Rego queries that are format-agnostic and accurately parsed the Ansible playbook structure, flagging Linux hardening gaps like hardcoded passwords in `inventory.ini` and `configure.yml`. Checkov's Ansible support is limited to cloud modules, not OS configuration playbooks. +- **Example of single-tool catch:** Checkov flagged `CKV_SECRET_2` (AWS Access Key) in `main.tf` because it runs a dedicated secrets engine with pattern matching for AWS key formats (`AKIA...`). KICS skipped it because KICS focuses on infrastructure misconfiguration queries, not secret pattern detection. +--- -\--- - - - -\## Bonus: Custom Checkov Policy - - - -\### Policy file (`labs/lab6/policies/custom\_checks/rds\_deletion\_protection.py`) +## Bonus: Custom Checkov Policy +### Policy file (`labs/lab6/policies/custom_checks/rds_deletion_protection.py`) ```python - from checkov.common.models.enums import CheckResult, CheckCategories - -from checkov.terraform.checks.resource.base\_resource\_check import BaseResourceCheck - - +from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck class RDSDeletionProtection(BaseResourceCheck): - - def \_\_init\_\_(self): - - name = "Ensure RDS instances have deletion\_protection enabled" - - id = "CKV\_CUSTOM\_1" - - supported\_resources = \['aws\_db\_instance'] - - categories = \[CheckCategories.GENERAL\_SECURITY] - - super().\_\_init\_\_(name=name, id=id, categories=categories, supported\_resources=supported\_resources) - - - - def scan\_resource\_conf(self, conf): - - if 'deletion\_protection' in conf: - - if conf\['deletion\_protection']\[0] == True: - - return CheckResult.PASSED - - return CheckResult.FAILED - - + def __init__(self): + name = "Ensure RDS instances have deletion_protection enabled" + id = "CKV_CUSTOM_1" + supported_resources = ['aws_db_instance'] + categories = [CheckCategories.GENERAL_SECURITY] + super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources) + + def scan_resource_conf(self, conf): + if 'deletion_protection' in conf: + if conf['deletion_protection'][0] == True: + return CheckResult.PASSED + return CheckResult.FAILED check = RDSDeletionProtection() - ``` - - -\### Rule fires (Proof) - +### Rule fires (Proof) The custom policy successfully fired on both RDS instances in `database.tf`: - ```json - { - - "check\_id": "CKV\_CUSTOM\_1", - - "check\_name": "Ensure RDS instances have deletion\_protection enabled", - - "check\_result": { "result": "FAILED" }, - - "resource": "aws\_db\_instance.unencrypted\_db", - - "file\_path": "\\\\database.tf" - + "check_id": "CKV_CUSTOM_1", + "check_name": "Ensure RDS instances have deletion_protection enabled", + "check_result": { "result": "FAILED" }, + "resource": "aws_db_instance.unencrypted_db", + "file_path": "\\database.tf" } - { - - "check\_id": "CKV\_CUSTOM\_1", - - "check\_name": "Ensure RDS instances have deletion\_protection enabled", - - "check\_result": { "result": "FAILED" }, - - "resource": "aws\_db\_instance.weak\_db", - - "file\_path": "\\\\database.tf" - + "check_id": "CKV_CUSTOM_1", + "check_name": "Ensure RDS instances have deletion_protection enabled", + "check_result": { "result": "FAILED" }, + "resource": "aws_db_instance.weak_db", + "file_path": "\\database.tf" } - ``` - - -\### Why this rule matters - -Accidental database deletion causes catastrophic data loss and downtime. The 2021 GitLab outage (caused by accidental `rm -rf`) and multiple AWS RDS incidents highlight that `deletion\_protection = true` is a critical safety net against human error or compromised CI/CD pipelines. This aligns with CIS AWS Foundations Benchmark v1.5.0 (Section 2.3.1) and NIST SP 800-144 requirement for data integrity safeguards. Enforcing it via Policy-as-Code guarantees no RDS instance reaches production without this guardrail. - +### Why this rule matters +Accidental database deletion causes catastrophic data loss and downtime. The 2021 GitLab outage (caused by accidental `rm -rf`) and multiple AWS RDS incidents highlight that `deletion_protection = true` is a critical safety net against human error or compromised CI/CD pipelines. This aligns with CIS AWS Foundations Benchmark v1.5.0 (Section 2.3.1) and NIST SP 800-144 requirement for data integrity safeguards. Enforcing it via Policy-as-Code guarantees no RDS instance reaches production without this guardrail. From 22c9abf422bfa627a5026c321dfaf58d2a4a767f Mon Sep 17 00:00:00 2001 From: alileeeek Date: Fri, 26 Jun 2026 23:36:06 +0300 Subject: [PATCH 3/6] Update lab6.md --- submissions/lab6.md | 100 ++++++++++++++++++++------------------------ 1 file changed, 45 insertions(+), 55 deletions(-) diff --git a/submissions/lab6.md b/submissions/lab6.md index 6cbc63923..ec1ed03b0 100644 --- a/submissions/lab6.md +++ b/submissions/lab6.md @@ -1,17 +1,17 @@ # Lab 6 — Submission -## Task 1: Checkov on Terraform +## Task 1: Checkov on Terraform + Pulumi ### Terraform scan -- **Total checks:** 129 (49 passed, 80 failed) -- **Secrets scan:** 2 failed (CKV_SECRET_2, CKV_SECRET_6) +- **Total checks:** 129 (49 passed, 82 failed) +- **Breakdown:** 80 failed in Terraform resources, 2 failed in Secrets scan | Severity | Count | |----------|------:| -| Critical | 1 (Hardcoded AWS credentials) | +| Critical | 1 (Hardcoded AWS credentials in provider) | | High | ~30 (IAM wildcard policies, public S3, exposed security groups) | | Medium | ~25 (Missing encryption, logging, backups) | -| Low | ~24 (Missing descriptions, tags, best practices) | +| Low | ~26 (Missing descriptions, tags, best practices) | *Note: Checkov CE does not populate `severity` field for most rules without Bridgecrew API key. Severity estimates above are based on official Checkov documentation.* @@ -22,16 +22,26 @@ | CKV_AWS_355 | 4 | IAM policies allow "*" as resource for restrictable actions | | CKV_AWS_23 | 3 | Security group rules missing descriptions | | CKV_AWS_288 | 3 | IAM policies allow data exfiltration | -| CKV_AWS_290 | 3 | IAM policies allow unconstrained write access | +| CKV_AWS_290 | 3 | IAM policies allow write access without constraints | + +### Pulumi scan (via KICS) +| Severity | Count | +|----------|------:| +| CRITICAL | 1 (RDS publicly accessible) | +| HIGH | 2 (DynamoDB not encrypted, hardcoded password) | +| MEDIUM | 1 (EC2 monitoring disabled) | +| LOW | 0 | +| INFO | 2 | +| **Total** | **6** | ### Module-leverage analysis (Lecture 6 slide 17) Looking at the top-5 Terraform rules, the **single highest-leverage fix** is enforcing least-privilege IAM policies at the module level. Rules CKV_AWS_289, CKV_AWS_355, CKV_AWS_288, and CKV_AWS_290 all fire because `iam.tf` contains policies with `Action = "*"` and `Resource = "*"`. If the IAM module enforced a policy template that requires explicit actions and scoped resources (e.g., using AWS managed policies or customer-managed policies with specific ARNs), all 14+ IAM-related findings would vanish with one architectural change. Similarly, adding a default `aws_s3_bucket_public_access_block` resource to the S3 module with all four block flags set to `true` would eliminate CKV_AWS_53/54/55/56 across all buckets. --- -## Task 2: KICS on Ansible + Pulumi +## Task 2: KICS on Ansible -### KICS Ansible Severity breakdown +### Severity breakdown | Severity | Count | |----------|------:| | CRITICAL | 0 | @@ -41,7 +51,7 @@ Looking at the top-5 Terraform rules, the **single highest-leverage fix** is enf | INFO | 0 | | **Total** | **10** | -### Top 5 KICS queries (Ansible, by frequency) +### Top 5 KICS queries (by frequency) | Query | Severity | Files | |-------|----------|------:| | Passwords And Secrets - Generic Password | HIGH | 6 | @@ -49,16 +59,6 @@ Looking at the top-5 Terraform rules, the **single highest-leverage fix** is enf | Passwords And Secrets - Generic Secret | HIGH | 1 | | Unpinned Package Version | LOW | 1 | -### KICS Pulumi Severity breakdown -| Severity | Count | -|----------|------:| -| CRITICAL | 1 (RDS publicly accessible) | -| HIGH | 2 (DynamoDB not encrypted, hardcoded password) | -| MEDIUM | 1 (EC2 monitoring disabled) | -| LOW | 0 | -| INFO | 2 | -| **Total** | **6** | - ### Checkov vs KICS — when to use which? (Lecture 6 slide 10) - **One thing Checkov did better for Terraform:** Checkov natively understands Terraform's graph model and caught cross-resource misconfigurations like `CKV2_AWS_5` (security groups not attached to any resource) and `CKV2_AWS_6` (S3 bucket without public access block). These graph-based checks require understanding relationships between resources, which KICS cannot do because it scans files statically. - **One thing KICS did better for Ansible:** KICS uses Rego queries that are format-agnostic and accurately parsed the Ansible playbook structure, flagging Linux hardening gaps like hardcoded passwords in `inventory.ini` and `configure.yml`. Checkov's Ansible support is limited to cloud modules, not OS configuration playbooks. @@ -68,45 +68,35 @@ Looking at the top-5 Terraform rules, the **single highest-leverage fix** is enf ## Bonus: Custom Checkov Policy -### Policy file (`labs/lab6/policies/custom_checks/rds_deletion_protection.py`) -```python -from checkov.common.models.enums import CheckResult, CheckCategories -from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck - -class RDSDeletionProtection(BaseResourceCheck): - def __init__(self): - name = "Ensure RDS instances have deletion_protection enabled" - id = "CKV_CUSTOM_1" - supported_resources = ['aws_db_instance'] - categories = [CheckCategories.GENERAL_SECURITY] - super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources) - - def scan_resource_conf(self, conf): - if 'deletion_protection' in conf: - if conf['deletion_protection'][0] == True: - return CheckResult.PASSED - return CheckResult.FAILED - -check = RDSDeletionProtection() +### Policy file (`labs/lab6/policies/rds-deletion-protection.yaml`) +```yaml +metadata: + id: CKV_CUSTOM_1 + name: "Ensure RDS instances have deletion_protection enabled" + category: GENERAL_SECURITY + severity: HIGH +definition: + cond_type: attribute + resource_types: + - aws_db_instance + attribute: deletion_protection + value: true + operator: equals ``` -### Rule fires (Proof) -The custom policy successfully fired on both RDS instances in `database.tf`: +### Rule fires +Output of `jq '[.[] | .results.failed_checks[] | select(.check_id == "CKV_CUSTOM_1") | {resource: .resource, file: .file_path}]'`: ```json -{ - "check_id": "CKV_CUSTOM_1", - "check_name": "Ensure RDS instances have deletion_protection enabled", - "check_result": { "result": "FAILED" }, - "resource": "aws_db_instance.unencrypted_db", - "file_path": "\\database.tf" -} -{ - "check_id": "CKV_CUSTOM_1", - "check_name": "Ensure RDS instances have deletion_protection enabled", - "check_result": { "result": "FAILED" }, - "resource": "aws_db_instance.weak_db", - "file_path": "\\database.tf" -} +[ + { + "resource": "aws_db_instance.unencrypted_db", + "file": "\\database.tf" + }, + { + "resource": "aws_db_instance.weak_db", + "file": "\\database.tf" + } +] ``` ### Why this rule matters From 88d3881ed6d57e8f2498305e97d0fab6d7b4cb2b Mon Sep 17 00:00:00 2001 From: alileeeek Date: Fri, 26 Jun 2026 23:47:37 +0300 Subject: [PATCH 4/6] Delete labs/lab6/policies/custom_checks directory --- labs/lab6/policies/custom_checks/__init__.py | 0 .../custom_checks/rds_deletion_protection.py | 24 ------------------- 2 files changed, 24 deletions(-) delete mode 100644 labs/lab6/policies/custom_checks/__init__.py delete mode 100644 labs/lab6/policies/custom_checks/rds_deletion_protection.py diff --git a/labs/lab6/policies/custom_checks/__init__.py b/labs/lab6/policies/custom_checks/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/labs/lab6/policies/custom_checks/rds_deletion_protection.py b/labs/lab6/policies/custom_checks/rds_deletion_protection.py deleted file mode 100644 index a54c7b05a..000000000 --- a/labs/lab6/policies/custom_checks/rds_deletion_protection.py +++ /dev/null @@ -1,24 +0,0 @@ -from checkov.common.models.enums import CheckResult, CheckCategories -from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck - - -class RDSDeletionProtection(BaseResourceCheck): - def __init__(self): - name = "Ensure RDS instances have deletion_protection enabled" - id = "CKV_CUSTOM_1" - supported_resources = ['aws_db_instance'] - categories = [CheckCategories.GENERAL_SECURITY] - super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources) - - def scan_resource_conf(self, conf): - """ - Looks for deletion_protection configuration in aws_db_instance: - https://www.terraform.io/docs/providers/aws/r/db_instance.html - """ - if 'deletion_protection' in conf: - if conf['deletion_protection'][0] == True: - return CheckResult.PASSED - return CheckResult.FAILED - - -check = RDSDeletionProtection() \ No newline at end of file From b3557698e17c238501d6a7a0a9e7119a98324ec1 Mon Sep 17 00:00:00 2001 From: alileeeek Date: Fri, 3 Jul 2026 02:39:00 +0300 Subject: [PATCH 5/6] feat(lab6): update submission report per new requirements --- submissions/lab6.md | 78 ++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 44 deletions(-) diff --git a/submissions/lab6.md b/submissions/lab6.md index ec1ed03b0..67b62bb6c 100644 --- a/submissions/lab6.md +++ b/submissions/lab6.md @@ -1,57 +1,50 @@ # Lab 6 — Submission -## Task 1: Checkov on Terraform + Pulumi +## Task 1: Checkov on Terraform -### Terraform scan -- **Total checks:** 129 (49 passed, 82 failed) -- **Breakdown:** 80 failed in Terraform resources, 2 failed in Secrets scan - -| Severity | Count | -|----------|------:| -| Critical | 1 (Hardcoded AWS credentials in provider) | -| High | ~30 (IAM wildcard policies, public S3, exposed security groups) | -| Medium | ~25 (Missing encryption, logging, backups) | -| Low | ~26 (Missing descriptions, tags, best practices) | - -*Note: Checkov CE does not populate `severity` field for most rules without Bridgecrew API key. Severity estimates above are based on official Checkov documentation.* +### Terraform scan (passed/failed per framework) +| Framework | Passed | Failed | +|-----------|-------:|-------:| +| terraform | 49 | 80 | +| secrets | 0 | 2 | +| **Total** | **49** | **82** | ### Top 5 rule IDs (by frequency) | Rule ID | Count | What it checks | |---------|------:|----------------| -| CKV_AWS_289 | 4 | IAM policies allow permissions management without constraints | +| CKV_AWS_289 | 4 | IAM policies allow permissions management / resource exposure without constraints | | CKV_AWS_355 | 4 | IAM policies allow "*" as resource for restrictable actions | | CKV_AWS_23 | 3 | Security group rules missing descriptions | | CKV_AWS_288 | 3 | IAM policies allow data exfiltration | | CKV_AWS_290 | 3 | IAM policies allow write access without constraints | -### Pulumi scan (via KICS) -| Severity | Count | -|----------|------:| -| CRITICAL | 1 (RDS publicly accessible) | -| HIGH | 2 (DynamoDB not encrypted, hardcoded password) | -| MEDIUM | 1 (EC2 monitoring disabled) | -| LOW | 0 | -| INFO | 2 | -| **Total** | **6** | - ### Module-leverage analysis (Lecture 6 slide 17) -Looking at the top-5 Terraform rules, the **single highest-leverage fix** is enforcing least-privilege IAM policies at the module level. Rules CKV_AWS_289, CKV_AWS_355, CKV_AWS_288, and CKV_AWS_290 all fire because `iam.tf` contains policies with `Action = "*"` and `Resource = "*"`. If the IAM module enforced a policy template that requires explicit actions and scoped resources (e.g., using AWS managed policies or customer-managed policies with specific ARNs), all 14+ IAM-related findings would vanish with one architectural change. Similarly, adding a default `aws_s3_bucket_public_access_block` resource to the S3 module with all four block flags set to `true` would eliminate CKV_AWS_53/54/55/56 across all buckets. +The **single highest-leverage fix** is enforcing least-privilege IAM policies at the module level. Rules CKV_AWS_289, CKV_AWS_355, CKV_AWS_288, and CKV_AWS_290 all fire because `iam.tf` contains policies with `Action = "*"` and `Resource = "*"`. If the shared IAM policy module dropped the `Resource: "*"` wildcard and required explicit actions and scoped resource ARNs (e.g., using AWS managed policies or customer-managed policies with specific ARNs), all 14+ IAM-related findings would collapse into a single module-level fix. Similarly, adding a default `aws_s3_bucket_public_access_block` resource to the S3 module with all four block flags set to `true` would eliminate CKV_AWS_53/54/55/56 across all buckets. --- -## Task 2: KICS on Ansible +## Task 2: KICS on Ansible + Pulumi -### Severity breakdown +### Ansible — severity breakdown | Severity | Count | |----------|------:| -| CRITICAL | 0 | | HIGH | 9 | | MEDIUM | 0 | | LOW | 1 | | INFO | 0 | | **Total** | **10** | -### Top 5 KICS queries (by frequency) +### Pulumi — severity breakdown +| Severity | Count | +|----------|------:| +| CRITICAL | 1 | +| HIGH | 2 | +| MEDIUM | 1 | +| LOW | 0 | +| INFO | 2 | +| **Total** | **6** | + +### Top 5 KICS queries — Ansible (by frequency) | Query | Severity | Files | |-------|----------|------:| | Passwords And Secrets - Generic Password | HIGH | 6 | @@ -61,17 +54,17 @@ Looking at the top-5 Terraform rules, the **single highest-leverage fix** is enf ### Checkov vs KICS — when to use which? (Lecture 6 slide 10) - **One thing Checkov did better for Terraform:** Checkov natively understands Terraform's graph model and caught cross-resource misconfigurations like `CKV2_AWS_5` (security groups not attached to any resource) and `CKV2_AWS_6` (S3 bucket without public access block). These graph-based checks require understanding relationships between resources, which KICS cannot do because it scans files statically. -- **One thing KICS did better for Ansible:** KICS uses Rego queries that are format-agnostic and accurately parsed the Ansible playbook structure, flagging Linux hardening gaps like hardcoded passwords in `inventory.ini` and `configure.yml`. Checkov's Ansible support is limited to cloud modules, not OS configuration playbooks. +- **One thing KICS did better for Ansible:** KICS uses Rego queries that are format-agnostic and accurately parsed the Ansible playbook structure, flagging Linux hardening gaps like hardcoded passwords in `inventory.ini` and `configure.yml` (9 HIGH findings). Checkov's Ansible support is limited to cloud modules, not OS configuration playbooks. - **Example of single-tool catch:** Checkov flagged `CKV_SECRET_2` (AWS Access Key) in `main.tf` because it runs a dedicated secrets engine with pattern matching for AWS key formats (`AKIA...`). KICS skipped it because KICS focuses on infrastructure misconfiguration queries, not secret pattern detection. --- ## Bonus: Custom Checkov Policy -### Policy file (`labs/lab6/policies/rds-deletion-protection.yaml`) +### Policy file (`labs/lab6/policies/my-custom-policy.yaml`) ```yaml metadata: - id: CKV_CUSTOM_1 + id: CKV2_CUSTOM_1 name: "Ensure RDS instances have deletion_protection enabled" category: GENERAL_SECURITY severity: HIGH @@ -85,18 +78,15 @@ definition: ``` ### Rule fires -Output of `jq '[.[] | .results.failed_checks[] | select(.check_id == "CKV_CUSTOM_1") | {resource: .resource, file: .file_path}]'`: -```json -[ - { - "resource": "aws_db_instance.unencrypted_db", - "file": "\\database.tf" - }, - { - "resource": "aws_db_instance.weak_db", - "file": "\\database.tf" - } -] +The custom policy successfully fired on both RDS instances in `database.tf`: +``` +Check ID: CKV2_CUSTOM_1 +Resource: aws_db_instance.unencrypted_db (database.tf:5-37) +Result: FAILED — deletion_protection = false + +Check ID: CKV2_CUSTOM_1 +Resource: aws_db_instance.weak_db (database.tf:40-69) +Result: FAILED — deletion_protection attribute not set ``` ### Why this rule matters From 312cef090752916634ad7b0d2c96135553e8e2e0 Mon Sep 17 00:00:00 2001 From: alileeeek Date: Fri, 3 Jul 2026 02:40:28 +0300 Subject: [PATCH 6/6] feat(lab6): add custom Checkov YAML policy --- labs/lab6/policies/my-custom-policy.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 labs/lab6/policies/my-custom-policy.yaml diff --git a/labs/lab6/policies/my-custom-policy.yaml b/labs/lab6/policies/my-custom-policy.yaml new file mode 100644 index 000000000..b2d1ab165 --- /dev/null +++ b/labs/lab6/policies/my-custom-policy.yaml @@ -0,0 +1,12 @@ +metadata: + id: CKV2_CUSTOM_1 + name: "Ensure RDS instances have deletion_protection enabled" + category: GENERAL_SECURITY + severity: HIGH +definition: + cond_type: attribute + resource_types: + - aws_db_instance + attribute: deletion_protection + value: true + operator: equals