Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -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.
114 changes: 114 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -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.
96 changes: 75 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,90 @@
<p align="center">
<a href="https://runwhen.slack.com/join/shared_invite/zt-1l7t3tdzl-IzB8gXDsWtHkT8C5nufm2A">
<img src="https://img.shields.io/badge/Join%20Slack-%23E01563.svg?&style=for-the-badge&logo=slack&logoColor=white" alt="Join Slack">
<img src="https://img.shields.io/badge/Join%20Slack-%23E01563.svg?&style=for-the-badge&logo=slack&logoColor=white" alt="Join Slack" />
</a>
</p>
<a href='https://codespaces.new/runwhen-contrib/codecollection-template?quickstart=1'><img src='https://github.com/codespaces/badge.svg' alt='Open in GitHub Codespaces' style='max-width: 100%;'></a>

# 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
6 changes: 5 additions & 1 deletion codebundles/aws-c7n-s3-health/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
35 changes: 34 additions & 1 deletion codebundles/aws-c7n-s3-health/runbook.robot
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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 ***
Expand Down
6 changes: 6 additions & 0 deletions codebundles/aws-c7n-s3-health/s3-unencrypted-buckets.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
policies:
- name: s3-unencrypted-buckets
resource: aws.s3
filters:
- type: bucket-encryption
state: false
19 changes: 18 additions & 1 deletion codebundles/aws-c7n-s3-health/sli.robot
Original file line number Diff line number Diff line change
Expand Up @@ -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}



Expand Down