From 7c376788ec98bca5a28386445b230df90349fcf6 Mon Sep 17 00:00:00 2001 From: Saurabh Kumar Date: Thu, 2 Apr 2026 17:43:22 +0530 Subject: [PATCH] add first S3 encryption check and contributor onboarding templates --- .github/pull_request_template.md | 38 ++++++ CONTRIBUTING.md | 114 ++++++++++++++++++ README.md | 96 +++++++++++---- codebundles/aws-c7n-s3-health/README.md | 6 +- codebundles/aws-c7n-s3-health/runbook.robot | 35 +++++- .../s3-unencrypted-buckets.yaml | 6 + codebundles/aws-c7n-s3-health/sli.robot | 19 ++- 7 files changed, 290 insertions(+), 24 deletions(-) create mode 100644 .github/pull_request_template.md create mode 100644 CONTRIBUTING.md create mode 100644 codebundles/aws-c7n-s3-health/s3-unencrypted-buckets.yaml diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..e3a4d64 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,38 @@ +## Summary + +Describe what this PR changes and why. + +## Type Of Change + +- [ ] New AWS check in an existing bundle +- [ ] New codebundle +- [ ] Bug fix +- [ ] Documentation update +- [ ] Test or validation update + +## What Changed + +- [ ] Cloud Custodian policy files (`*.yaml` or `*.j2`) +- [ ] SLI logic (`sli.robot`) +- [ ] Runbook logic (`runbook.robot`) +- [ ] RunWhen templates (`.runwhen/*`) +- [ ] Bundle documentation (`README.md`) + +## Validation + +Include commands run and short outcomes. + +```text +Example: +- Ran custodian policy against test account/region +- Verified ResourceCount and resources.json output +- Verified runbook issue fields (title, severity, next steps) +``` + +## Contributor Checklist + +- [ ] I did not commit secrets or credentials. +- [ ] The change is scoped and backwards-safe for existing checks. +- [ ] New defaults and config variables are documented. +- [ ] Issue text in runbook output is actionable. +- [ ] I updated docs for any user-visible behavior changes. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..a186454 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,114 @@ +# Contributing + +Thanks for contributing to this AWS CodeCollection. + +This repository packages Cloud Custodian checks as RunWhen codebundles. A high-quality contribution should improve one of these areas: + +- Detection coverage (new AWS health/security check) +- Signal quality (better thresholds, less noise) +- Triage quality (clear runbook issues and next steps) +- Reliability (test improvements, parsing robustness, docs) + +## Prerequisites + +- Python 3.10+ +- Cloud Custodian (`c7n`), Robot Framework, and dependencies from `requirements.txt` +- AWS CLI configured with credentials for the target account/region +- Optional but recommended for end-to-end tests: + - Docker + - Terraform + - Task (`task` command) + - jq + +## Development Environment + +### Option A (recommended): Dev Container + +Open this repository in VS Code Dev Containers using `.devcontainer.json`. + +### Option B: Local environment + +```bash +python -m venv .venv +source .venv/bin/activate +pip install -r requirements.txt +``` + +## Recommended First Contribution + +Start by adding one new check to an existing bundle (for example in `codebundles/aws-c7n-s3-health`), instead of creating a new bundle from scratch. + +### Add A New Check To An Existing Bundle + +1. Add a policy file + +Create a new Cloud Custodian policy file (`*.yaml`) or template (`*.j2`) in the bundle directory. + +2. Update SLI logic + +Edit the bundle `sli.robot` to: + +- run the new policy +- read its `ResourceCount` +- incorporate it into the score or metric output + +3. Update runbook logic + +Edit `runbook.robot` to: + +- parse and summarize the new check results +- raise issues with clear title, expected/actual, severity, and next steps + +4. Update bundle documentation + +Update the bundle `README.md` with: + +- what the new check detects +- any new config variables and defaults +- expected operational impact + +5. Validate locally + +At minimum, run the policy directly and ensure it returns expected output. + +For full validation, use the bundle `.test` workflow (if present). + +## Creating A New Bundle (Second Contribution) + +When you are ready, copy a similar bundle and update all four areas consistently: + +- policy files (`*.yaml` / `*.j2`) +- `sli.robot` +- `runbook.robot` +- `.runwhen/generation-rules` and `.runwhen/templates` + +Ensure `baseName`, template names, and `pathToRobot` values align. + +## Branch And PR Workflow + +1. Fork this repository and create a feature branch. +2. Keep PRs focused on one bundle or one logical change. +3. Add tests or validation notes in the PR description. +4. Open a PR using the included template. + +## Quality Checklist + +Before opening a PR, confirm: + +- No secrets or credentials are committed. +- New policy names are unique and descriptive. +- Runbook issues include actionable remediation steps. +- Bundle README reflects new behavior and config. +- Generation templates still resolve correctly. +- Existing checks in the touched bundle continue to work. + +## Security And Credentials + +- Never commit AWS keys, tokens, or workspace secrets. +- Use local secret files only under ignored paths. +- Use least-privilege AWS IAM permissions for testing. + +## Need Help? + +- Open a draft PR early and describe your intended check. +- Include sample policy output and expected issue text for faster feedback. diff --git a/README.md b/README.md index 3397a4d..ff36494 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,90 @@

- Join Slack + Join Slack

-Open in GitHub Codespaces +# aws-c7ncodecollection -# codecollection-template -A hello-world-style template for codecollection authors to get started writing codebundles. This template contains the minimum file structure expected by the RunWhen platform. +AWS health and governance CodeCollection for RunWhen, powered by Cloud Custodian (c7n) and Robot Framework. -[![Build](https://github.com/runwhen-contrib/codecollection-template/actions/workflows/build.yaml/badge.svg)](https://github.com/runwhen-contrib/codecollection-template/actions/workflows/build.yaml) +Each codebundle in this repository does two things: -## Getting Started -Looking to be a contributor for CodeCollections or start your own? We'd love to collaborate! Head on over to our [public docs](https://docs.runwhen.com/public/v/runwhen-authors/codecollection-development/getting-started/running-your-first-codebundle) to get started. +- Produces an SLI score/metric for a class of AWS risks. +- Produces runbook output with issue-level triage details. -File Structure overview of devcontainer: +## What Is Included + +The repository currently includes the following codebundles under `codebundles/`: + +- `aws-c7n-acm-health`: expired, pending validation, failed, soon-to-expire, and unused certificates. +- `aws-c7n-ebs-health`: unattached volumes, unencrypted volumes, and unused snapshots. +- `aws-c7n-ec2-health`: stale instances, long-stopped instances, and invalid Auto Scaling Groups. +- `aws-c7n-monitoring-health`: CloudTrail and CloudWatch logging hygiene checks. +- `aws-c7n-network-health`: insecure security-group ingress, unused EIP/ELB, missing VPC flow logs. +- `aws-c7n-rds-health`: backup-disabled, public, and unencrypted RDS instances. +- `aws-c7n-s3-health`: public S3 bucket exposure checks. + +## Repository Layout + +- `codebundles/`: runnable checks, runbooks, and RunWhen metadata templates. +- `libraries/CloudCustodian/Core/`: shared Python helper keywords used by Robot suites. +- `.github/workflows/score.yaml`: automated scoring/suggestion workflow for codebundles. +- `.github/workflows/release.yaml`: scheduled/manual release workflow. + +## How A Bundle Works + +Inside each bundle, you will usually see: + +- One or more Cloud Custodian policies (`*.yaml`) and/or templates (`*.j2`). +- `sli.robot`: computes and pushes a metric. +- `runbook.robot`: parses findings and raises actionable issues. +- `.runwhen/generation-rules/` and `.runwhen/templates/`: SLX/SLI/Runbook generation for the RunWhen platform. +- `.test/`: optional Terraform and Taskfile-based end-to-end test harness. + +## Quickstart (Contributor) + +### 1) Clone and open the repository + +```bash +git clone https://github.com/Saurabhtbj1201/aws-c7ncodecollection.git +cd aws-c7ncodecollection ``` --/app/ - |- auth/ #store secrets here, it should already be properly gitignored for you - |- codecollection/ - | |- codebundles/ # stores codebundles that can be run - | |- libraries/ # stores python keyword libraries used by codebundles - |- dev_facade/ # provides interfaces equivalent to those used on the platform, but just dry runs the keywords to assist with development - ... + +### 2) Choose your environment + +- Recommended: use the dev container configuration in `.devcontainer.json`. +- Alternative: set up a local Python environment and install dependencies: + +```bash +python -m venv .venv +source .venv/bin/activate +pip install -r requirements.txt +``` + +### 3) Provide AWS credentials for read-only checks + +Most bundles require at least: + +```bash +export AWS_ACCESS_KEY_ID="..." +export AWS_SECRET_ACCESS_KEY="..." +export AWS_DEFAULT_REGION="us-west-2" +export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text) ``` -The included script `ro` wraps the `robot` RobotFramework binary, and includes some extra functionality to write logs to a consistent location for viewing in a HTTP server at http://localhost:3000/ that is always running as part of the devcontainer. +### 4) Start with one existing check + +The easiest first path is to add a new policy/check to an existing bundle (commonly `aws-c7n-s3-health` or `aws-c7n-ec2-health`) before creating a brand-new bundle. + +## Contributing + +See `CONTRIBUTING.md` for a step-by-step guide, checklist, and PR workflow. + +## Notes For Windows Contributors -### Quickstart +The `.test/Taskfile.yaml` flows use shell utilities (`source`, `awk`, `jq`, `column`) and are easiest to run in a Linux devcontainer or WSL shell. -Navigate to the codebundle directory -`cd codecollection/codebundles/hello_world/` +## Related Documentation -Run the codebundle -`ro sli.robot` +- RunWhen author docs: https://docs.runwhen.com/public/v/runwhen-authors/codecollection-development/getting-started/running-your-first-codebundle diff --git a/codebundles/aws-c7n-s3-health/README.md b/codebundles/aws-c7n-s3-health/README.md index a1ff1cd..f107028 100644 --- a/codebundles/aws-c7n-s3-health/README.md +++ b/codebundles/aws-c7n-s3-health/README.md @@ -5,8 +5,12 @@ This codebundle starts out as an example of integrating the custodian (c7n) cli ## SLI A simple SLI that counts S3 buckets that are public. Uses the custodian cli. +This bundle now evaluates: +- S3 buckets with public access enabled +- S3 buckets missing default encryption + ## TaskSet -Similar to the SLI, but produces a report on the specific resources and raises issues for each public bucket. +Similar to the SLI, but produces a report on the specific resources and raises issues for each bucket that is public or unencrypted. ## Required Configuration diff --git a/codebundles/aws-c7n-s3-health/runbook.robot b/codebundles/aws-c7n-s3-health/runbook.robot index 081474e..de8a2dc 100644 --- a/codebundles/aws-c7n-s3-health/runbook.robot +++ b/codebundles/aws-c7n-s3-health/runbook.robot @@ -23,7 +23,7 @@ List S3 Buckets With Public Access in AWS Account `${AWS_ACCOUNT_NAME}` RW.Core.Add Pre To Report ${c7n_output.stdout} # Note: This actual data needs to be parsed to be usable in the report. Json data in a report like this isn't super useful. ${parsed_results}= CloudCustodian.Core.Parse Custodian Results # Note: This just an example of simple parsing with a custom keyword. - ... input_dir=${OUTPUT_DIR}/aws-c7n-s3-health + ... input_dir=${OUTPUT_DIR}/aws-c7n-s3-health/s3-public-buckets RW.Core.Add Pre To Report ${parsed_results} # Convert custodian json output to a list. @@ -48,6 +48,39 @@ List S3 Buckets With Public Access in AWS Account `${AWS_ACCOUNT_NAME}` END END +List S3 Buckets Without Default Encryption in AWS Account `${AWS_ACCOUNT_NAME}` + [Documentation] Fetch total number of S3 buckets without default encryption and raise an issue for each bucket. + [Tags] s3 storage aws security encryption data:config + ${c7n_output}= RW.CLI.Run Cli + ... cmd=custodian run -r ${AWS_REGION} --output-dir ${OUTPUT_DIR}/aws-c7n-s3-health ${CURDIR}/s3-unencrypted-buckets.yaml + ... env=${env} + ${report_data}= RW.CLI.Run Cli + ... cmd=cat ${OUTPUT_DIR}/aws-c7n-s3-health/s3-unencrypted-buckets/resources.json + + ${parsed_results}= CloudCustodian.Core.Parse Custodian Results + ... input_dir=${OUTPUT_DIR}/aws-c7n-s3-health/s3-unencrypted-buckets + RW.Core.Add Pre To Report ${parsed_results} + + TRY + ${bucket_list}= Evaluate json.loads(r'''${report_data.stdout}''') json + EXCEPT + Log Failed to load JSON payload, defaulting to empty list. WARN + ${bucket_list}= Create List + END + + IF len(@{bucket_list}) > 0 + FOR ${item} IN @{bucket_list} + RW.Core.Add Issue + ... severity=2 + ... expected=AWS S3 Buckets in AWS Account `${AWS_ACCOUNT_NAME}` should have default encryption enabled + ... actual=AWS S3 Bucket `${item["Name"]}` in AWS Account `${AWS_ACCOUNT_NAME}` does not have default encryption enabled + ... title=AWS S3 Bucket `${item["Name"]}` in AWS Account `${AWS_ACCOUNT_NAME}` is missing default encryption + ... reproduce_hint=${c7n_output.cmd} + ... details=${item} + ... next_steps=Enable default encryption on AWS S3 bucket `${item["Name"]}`. + END + END + ** Keywords *** diff --git a/codebundles/aws-c7n-s3-health/s3-unencrypted-buckets.yaml b/codebundles/aws-c7n-s3-health/s3-unencrypted-buckets.yaml new file mode 100644 index 0000000..5eab538 --- /dev/null +++ b/codebundles/aws-c7n-s3-health/s3-unencrypted-buckets.yaml @@ -0,0 +1,6 @@ +policies: + - name: s3-unencrypted-buckets + resource: aws.s3 + filters: + - type: bucket-encryption + state: false diff --git a/codebundles/aws-c7n-s3-health/sli.robot b/codebundles/aws-c7n-s3-health/sli.robot index b9e616f..57eb7e0 100644 --- a/codebundles/aws-c7n-s3-health/sli.robot +++ b/codebundles/aws-c7n-s3-health/sli.robot @@ -19,7 +19,24 @@ Count S3 Buckets With Public Access in AWS Account `${AWS_ACCOUNT_NAME}` ... env=${env} ${count}= RW.CLI.Run Cli ... cmd=cat ${OUTPUT_DIR}/aws-c7n-s3-health/s3-public-buckets/metadata.json | jq '.metrics[] | select(.MetricName == "ResourceCount") | .Value' - RW.Core.Push Metric ${count.stdout} + ${public_bucket_count}= Evaluate int(${count.stdout}) + Set Global Variable ${public_bucket_count} + +Count S3 Buckets Without Default Encryption in AWS Account `${AWS_ACCOUNT_NAME}` + [Documentation] Fetch total number of S3 buckets without default encryption enabled. + [Tags] s3 storage aws security encryption data:config + ${c7n_output}= RW.CLI.Run Cli + ... cmd=custodian run -r ${AWS_REGION} --output-dir ${OUTPUT_DIR}/aws-c7n-s3-health ${CURDIR}/s3-unencrypted-buckets.yaml + ... env=${env} + ${count}= RW.CLI.Run Cli + ... cmd=cat ${OUTPUT_DIR}/aws-c7n-s3-health/s3-unencrypted-buckets/metadata.json | jq '.metrics[] | select(.MetricName == "ResourceCount") | .Value' + ${unencrypted_bucket_count}= Evaluate int(${count.stdout}) + Set Global Variable ${unencrypted_bucket_count} + +Generate S3 Health Metric + [Documentation] Combine insecure bucket findings into a single metric. + ${s3_unhealthy_bucket_count}= Evaluate int(${public_bucket_count}) + int(${unencrypted_bucket_count}) + RW.Core.Push Metric ${s3_unhealthy_bucket_count}