Unit 1: How a cloud account is laid out · Lesson 3 of 5 · 20 min
Filter the API like a pro
Use --query, --output and jq to pull exactly the fields an audit needs.
mission
- You are
- Security engineer at Brightwell.
- Situation
- Raw JSON from the API is long. You need answers like who owns this bucket or which machines allow old metadata calls.
- Goal
- Turn long API responses into one line per resource.
- Hand in
- A one-line command that prints every bucket with its owner tag.
One response, three filters
{ "TagSet": [
{ "Key": "data", "Value": "learner-pii" },
{ "Key": "owner", "Value": "growth" } ] }3 lines. aws s3api get-bucket-tagging --bucket brightwell-learner-exports, before any filter
Count with length()
aws iam list-users --query 'length(Users)'
7
defender tip --query runs JMESPath on the response before printing, so it works the same for every service.
Pull one tag
Tags carry ownership and data class. An auditor reads them constantly.
aws s3api get-bucket-tagging --bucket brightwell-learner-exports { "TagSet": [ { "Key": "data", "Value": "learner-pii" }, { "Key": "owner", "Value": "growth" } ] } aws s3api get-bucket-tagging --bucket brightwell-learner-exports --query 'TagSet[?Key==`owner`].Value' --output text growth
you should see The bucket holds learner personal data and the growth team owns it.
Build a table
A hash with named keys makes a readable table. Here you check which machines still allow the old metadata service.
aws ec2 describe-instances --query 'Reservations[].Instances[].{name: Tags[?Key==`Name`]|[0].Value, tokens: MetadataOptions.HttpTokens}' --output table
------------------------------
| DescribeInstances |
+---------------+------------+
| name | tokens |
+---------------+------------+
| web-1 | required |
| web-2 | required |
| jump-1 | required |
| dev-box-1 | optional |
| report-win-1 | optional |
| tutor-api-1 | required |
| db-1 | required |
+---------------+------------+
you should see Two machines say optional. You will fix those in the network unit.
Reach for jq when the shape gets awkward
jq can split strings and build text, which JMESPath cannot. Here it shortens role ARNs to role names.
aws lambda list-functions | jq -r '.Functions[] | "\(.FunctionName)\t\(.Role | split("/") | last)"'
invoice-generator invoice-fn-role
tutor-assistant tutor-assistant-role
thumbnailer thumbnailer-role
Loop over every bucket
Many checks are per resource. A shell loop with a filtered call per item is the auditor's workhorse.
for b in $(aws s3api list-buckets --query 'Buckets[].Name' --output text); do echo "$b $(aws s3api get-bucket-tagging --bucket $b --query 'TagSet[?Key==`owner`].Value' --output text)"; done
brightwell-website web
brightwell-course-media content
brightwell-learner-exports growth
brightwell-backups platform
brightwell-tutor-knowledge ai
brightwell-deploy-artifacts platform
brightwell-logs security
you should see Seven lines, one per bucket, each with an owner you can contact about a finding.
What a defender takes away
- 1
--queryfilters on the client with JMESPath.[?Key==owner]keeps matching items. - 2
--output textprints values ready for shell loops.--output tableis for humans. - 3Use jq when you need string work or the output feeds a script.
- 4Loop per resource, print one line each, and keep the output for your report.
Questions
0 of 3 solved
Answer each one from what you find on your lab machine.