Scenario: CloudFormation IaC Scanning as GitHub Action¶
Prerequisites¶
- Vision One API-Key with the following permissions:
- Cloud Posture
- View
- Cloud Posture
- GitHub Account.
- Forked playground-one-template-scanner.
About GitHub Actions¶
GitHub Actions is a continuous integration and continuous delivery (CI/CD) platform that allows you to automate your build, test, and deployment pipeline on GitHub.
GitHub Actions goes beyond just DevOps and lets you run workflows when other events happen in your repository. For example, you can run a workflow to automatically add the appropriate labels whenever someone creates a new issue in your repository.
You can configure a GitHub Actions workflow to be triggered when an event occurs in your repository, such as a pull request being opened, an issue being created or a push happened. Your workflow contains one or more jobs which can run in sequential order or in parallel. Each job will run inside its own virtual machine runner, or inside a container, and has one or more steps that either run a script that you define or run an action, which is a reusable extension that can simplify your workflow.
Workflows are defined as YAML files in the .github/workflows directory in a repository, and a repository can have multiple workflows, each of which can perform a different set of tasks.
In this scenario we're going to create a workflow to automatically scan a Cloudformation template with Vision One Cloud Posture Template Scanning. The scan will check the configuration for misconfigurations.
The logic implemented in this Action template is as follows:
- Prepare the Cloudformation environment with rain.
- Use the template scanner to scan for misconfigurations.
- Upload scan artifacts.
- Eventually fail the action if the findings threshold has been exceeded.
Fork the Scenario Repo¶
The first step is to fork the scenarios GitHub repo. For this go to github.com and sign in or create a free account if you need to.
Next, you want to create a Fork of the scenarios repo. A fork is basically a copy of a repository. Forking a repository allows you to freely experiment with changes without affecting the original project.
To do this navigate to the repo playground-one-template-scanner and click on the Fork
-button in the upper right.
On the next screen you change the name to something shorter like action
. Then press [Create fork]
which will bring you back to your account.
The Repo¶
The repo containes a hidden directory .github/workflows
with some yaml
-files, a cfn
and an infra
-directory.
The cfn
holds an example CloudFormation template for the scan, whereby the infra
directory contains some Terraform modules which would create a VPC, subnets, security groups, etc.
The Workflow¶
In the following section we'll review the different GitHub Actions for CloudFormation scanning of this repo.
Let's go through it.
name: CloudFormation Scan
# A push --tags on the repo triggers the workflow
on:
push:
tags: [ v* ]
env:
# Vision One API Key
API_KEY: ${{ secrets.API_KEY }}
# Region in which Vision One serves your organisation
REGION: "" # Examples: "eu." "sg." Leave blank if running in us.
# Scan result threshold (fail on risk-level or higher)
# THRESHOLD: any
# THRESHOLD: critical
THRESHOLD: high
# THRESHOLD: medium
# THRESHOLD: low
jobs:
docker:
runs-on: ubuntu-latest
steps:
# Prepare and authenticate to AWS using the given credentials
- name: Checkout
uses: actions/checkout@v4
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}
# CloudFormation scan
- name: CloudFormation Scan
run: |
contents=$(cat cfn/template.json | jq '.' -MRs)
payload="{\"type\":\"cloudformation-template\",\"content\":${contents}}"
printf '%s' ${payload} > data.txt
# # Scan template
curl -s -X POST \
-H "Authorization: Bearer ${API_KEY}" \
-H "Content-Type: application/json;charset=utf-8" \
https://api.${REGION}xdr.trendmicro.com/beta/cloudPosture/scanTemplate \
-d @data.txt > result.json
# Extract findings risk-level
risk_levels=$(cat result.json | jq -r '.scanResults[] | select(.status == "FAILURE") | .riskLevel')
fail=0
[ "${THRESHOLD}" = "any" ] && \
[ ! -z "${risk_levels}" ] && fail=1
[ "${THRESHOLD}" = "critical" ] && \
[[ ${risk_levels} == *CRITICAL* ]] && fail=2
[ "${THRESHOLD}" = "high" ] && \
([[ ${risk_levels} == *CRITICAL* ]] || [[ ${risk_levels} == *HIGH* ]]) && fail=3
[ "${THRESHOLD}" = "medium" ] && \
([[ ${risk_levels} == *CRITICAL* ]] || [[ ${risk_levels} == *HIGH* ]] || [[ ${risk_levels} == *MEDIUM* ]]) && fail=4
[ "${THRESHOLD}" = "low" ] && \
([[ ${risk_levels} == *CRITICAL* ]] || [[ ${risk_levels} == *HIGH* ]] || [[ ${risk_levels} == *MEDIUM* ]] || [[ ${risk_levels} == *LOW* ]]) && fail=5
[ $fail -ne 0 ] && echo !!! Threshold exceeded !!! > exceeded || true
# rm -f data.txt
# Upload Scan Result if available
- name: Upload Scan Result Artifact
uses: actions/upload-artifact@v4
with:
name: scan-result
path: result.json
retention-days: 30
- name: Upload Scan Result Artifact
uses: actions/upload-artifact@v4
with:
name: data
path: data.txt
retention-days: 30
# Fail the workflow if theshold reached
- name: Fail Scan
run: |
ls -l
if [ -f "exceeded" ]; then exit 1; fi
Secrets¶
For simplicity, authentication to AWS is done via access and secret access key. Alternative and likely better variants are described here.
The workflow requires a secret to be set. For that navigate to Settings --> Security --> Secrets and variables --> Actions --> Secrets
.
Add the following secrets:
- API_KEY:
<Your Cloud One API Key>
- AWS_ACCESS_KEY_ID
- AWS_SECRET_ACCESS_KEY
Template¶
Adapt the environment variables in the env:
-section as required.
Variable | Purpose |
---|---|
REGION |
Vision One Region of choice (e.g. "eu." "sg." Leave blank if running in us). |
THRESHOLD |
Defines the fail condition of the action in relation to discovered vulnerabilities. A threshold of critical does allow any number of vulnerabilities up to the criticality high . |
Allowed values for the THRESHOLD
are:
any
: No vulnerabilities allowed.critical
: Max risk-level of discovered findings ishigh
.high
: Max risk-level of discovered findings ismedium
.medium
: Max risk-level of discovered findings islow
.low
: Max risk-level of discovered findings isnegligible
.
If the THRESHOLD
is not set, vulnerabilities will not fail the pipeline.
The workflow will trigger on git push --tags
.
Actions¶
Navigate to Actions
and enable Workflows for the forked repository.
Test it¶
Create a Tag¶
To trigger the action we simply create a tag.
Navigate to Releases
on the right and then click on [Create a new release]
.
Next, click on [Choose a tag]
and type v0.1
. A new button called [Create new tag]
should get visible. Click on it.
Leave the rest as it is and finally click on the green button [Publish release]
. This will trigger the action workflow.
CLI:
git tag v0.1 && git push --tags
Check the Action¶
Now, navigate to the tab Actions
and review the actions output. Click on CloudFormation Scan
.
You should now see three main sections:
cloudformation-template-scan-shell.yaml
: Clicking ondocker
reveals the output of the steps from the workflow (and where it failed).- Annotations: Telling you in this case that the process completed with exit code 1.
- Artifacts: These are the artifacts created by the action. There should be a
scan-result
.
Feel free to review the scan results to find out why the action did fail.
🎉 Success 🎉