Filtering and risk checks¶
VPC filter¶
-v/--vpc-id=ID keeps one VPC. With live AWS access the filter is applied server-side in DescribeSecurityGroups; with
--source-file it is applied to the file's contents.
aws_security_viz --region us-west-1 -f aws.html --vpc-id=vpc-12345
Source and target filters¶
-u/--source-filter and -t/--target-filter take a group id (sg-...) or a group name. Both are matched after the
graph is built.
-t <group>keeps every route that can arrive at the group.-u <group>keeps everything reachable from the group.- Together they keep only groups on a path from the source to the target.
aws_security_viz -o security_groups.json -t sg-appgrp -f viz.json
aws_security_viz -o security_groups.json -t app -f viz.json
A filter that matches nothing is an error, and a name shared by several groups is an error that asks for a group id:
[ERROR] no group or peer matches 'nosuch'
Peers such as CIDR ranges are nodes too, so -u 0.0.0.0/0 is valid.
Exclusion patterns¶
:exclude: in opts.yml takes regular expressions, matched without anchors against group names and against the names
of rule peers. Matching groups and peers are dropped from the graph. See Configuration.
Several regions¶
--region us-east-1,eu-west-1 or --all-regions queries more than one region. Nodes are grouped by region, then VPC. A
region that fails with UnauthorizedOperation, AuthFailure or OptInRequired is skipped with a warning; the run
fails only if every region fails. --region and --all-regions are ignored, with a warning, when --source-file is
used.
What counts as risky¶
An edge is risky when all of these hold:
- It is an ingress rule. Egress is never risky.
- The peer is
0.0.0.0/0(IPv4) or::/0(IPv6). - The rule is either all traffic (protocol
-1), or protocol TCP (tcpor6) whose port range includes a risky port.
The default risky ports are 22, 3389, 3306, 5432, 1433, 6379, 9200 and 27017. Change them with :risky_ports: in
opts.yml; an entry that is not a port number from 1 to 65535 is an error.
The check is narrower than "an open port". UDP and ICMP rules, ranges that exclude every risky port, and rules open to a specific CIDR are not flagged. It runs on the real rule, before CIDR group mapping, merging and obfuscation, so a renamed peer or a merged label cannot hide a risky rule.
Risky edges are drawn as thick dashed crimson edges, flagged risky in JSON and HTML data, and counted on stderr:
[WARN] 1 risky edge: public ingress (0.0.0.0/0 or ::/0) on a sensitive port or all traffic
With none, the tool prints [INFO] no risky public ingress found.
Failing a CI job¶
--fail-on-risk exits with status 2 when at least one risky edge exists. The output file is still written, so a job can
upload it as an artifact. Exit status 1 means the tool itself failed, so a pipeline can tell "risk found" from "tool
failed". See exit codes.
aws_security_viz -o security_groups.json --fail-on-risk -f viz.json
echo $?
[WARN] 1 risky edge: public ingress (0.0.0.0/0 or ::/0) on a sensitive port or all traffic
2
Filters change the result. --fail-on-risk counts only the risky edges that survive filtering, so restricting the graph
with -u, -t or --vpc-id can turn a failing run into a passing one:
aws_security_viz -o security_groups.json --fail-on-risk -u app -f viz.json
echo $?
[INFO] no risky public ingress found
0
GitHub Actions example¶
This job assumes an IAM role through OIDC (no stored keys), runs the published image, and uploads the HTML report even
when the check fails. Replace <account_id>, <role_name> and <version>. Pin the actions to commit SHAs in your own
workflows.
name: security-groups
on:
schedule:
- cron: "0 6 * * 1"
workflow_dispatch:
permissions:
contents: read
id-token: write
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::<account_id>:role/<role_name>
aws-region: us-west-1
- name: Check for public ingress
run: |
mkdir out
docker run --rm --user "$(id -u):$(id -g)" \
-e AWS_REGION -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_SESSION_TOKEN \
-v "$PWD/out:/work" ghcr.io/anaynayak/aws-security-viz:<version> \
--all-regions --fail-on-risk -f /work/security-groups.html
- uses: actions/upload-artifact@v4
if: always()
with:
name: security-groups
path: out/security-groups.html
The role needs the actions in Credentials and IAM.