Hamburg - Advent of Sysadmin 2025
This is part of Sad Servers' Advent of Sysadmin 2025 series.
I'm doing each challenge every day and I'm publishing a quick write up for each one every day.
Spoiler alert! This gives the solution to the challenge. If you want to do it on your own, stop reading.
Challenge details
Scenario: "Hamburg": Find the AWS EC2 volume
Level: Easy
Description: We have a lot of AWS EC2 instances and EBS volumes, the description of which volumes we have saved to a file with: aws ec2 describe-volumes > aws-volumes.json.
One of the volumes attached to an ec2 instance contains important data and we need to identify which instance is attached to (its ID), but we only remember these characteristics: gp3, created before 31/09/2025 , Size < 64 , Iops < 1500, Throughput > 300.
Find the correct instance and put its "InstanceId" into the ~/mysolution file, e.g.: echo "i-00000000000000000" > ~/mysolution
Test: Running md5sum /home/admin/mysolution returns e7e34463823bf7e39358bf6bb24336d8 (we also accept the file without a new line at the end).
The "Check My Solution" button runs the script /home/admin/agent/check.sh, which you can see and execute.
Time to Solve: 30 minutes.
OS: Debian 13
Root (sudo) Access: Yes
Just by reading the challenge description, I knew I had to work with jq to find the answer.
Before launching the challenge, I started by reading the output structure of the AWS CLI describe-volumes command here: describe-volumes — AWS CLI 2.32.11 Command Reference
I ended up preparing my jq filter like this to match the search criteria:
- VolumeType == gp3
- CreateTime < 2025-09-31T00:00:002
- Size < 64
- Iops < 1500
- Throughput > 300
jq '.Volumes[] | select(.VolumeType == "gp3" and .Size < 64 and .Iops < 1500 and .Throughput > 300 and .CreateTime < "2025-09-31T00:00:002")'
cat aws-volumes.json | jq '.Volumes[] | select(.VolumeType == "gp3" and .Size < 64 and .Iops < 1500 and .Throughput > 300 and .CreateTime < "2025-09-31T00:00:002")'
{
"AvailabilityZoneId": "use2-az2",
"Iops": 1000,
"VolumeType": "gp3",
"MultiAttachEnabled": false,
"Throughput": 500,
"Operator": {
"Managed": false
},
"VolumeId": "vol-29d115ef9c3944f29",
"Size": 8,
"SnapshotId": "snap-4d14b6dc50854a9cb",
"AvailabilityZone": "us-east-2c",
"State": "in-use",
"CreateTime": "2025-09-29T16:43:18.004823Z",
"Attachments": [
{
"DeleteOnTermination": true,
"VolumeId": "vol-29d115ef9c3944f29",
"InstanceId": "i-371822c092b2470da",
"Device": "/dev/xvdc",
"State": "attached",
"AttachTime": "2025-09-29T17:41:18.004823Z"
}
],
"Encrypted": false
}
{
"AvailabilityZoneId": "use2-az3",
"Iops": 1000,
"VolumeType": "gp3",
"MultiAttachEnabled": false,
"Throughput": 500,
"Operator": {
"Managed": false
},
"VolumeId": "vol-99646e602c6e4b92a",
"Size": 16,
"SnapshotId": "snap-27b0fb199d294889b",
"AvailabilityZone": "us-east-2a",
"State": "available",
"CreateTime": "2025-09-29T01:21:18.004823Z",
"Attachments": [],
"Encrypted": false
}
I confirmed this command was working as expected. And then, I had to select the attachment instance ID to get the answer:
cat aws-volumes.json | jq '.Volumes[] | select(.VolumeType == "gp3" and .Size < 64 and .Iops < 1500 and .Throughput > 300 and .CreateTime < "2025-09-31T00:00:002") | .Attachments[].InstanceId'
Redirect that into the file mysolution with the --raw-output argument for jq. And that's it!
cat aws-volumes.json | jq --raw-output '.Volumes[] | select(.VolumeType == "gp3" and .Size < 64 and .Iops < 1500 and .Throughput > 300 and .CreateTime < "2025-09-31T00:00:002") | .Attachments[].InstanceId' > mysolution
A quick and easy one! 🚩