diff --git a/tuts/092-aws-kms-gs/README.md b/tuts/092-aws-kms-gs/README.md new file mode 100644 index 00000000..d6d70edf --- /dev/null +++ b/tuts/092-aws-kms-gs/README.md @@ -0,0 +1,52 @@ +# KMS: Create a key and encrypt data + +Create a customer managed KMS key, encrypt and decrypt data, and generate a data key using the AWS CLI. + +## Source + +https://docs.aws.amazon.com/kms/latest/developerguide/getting-started.html + +## Use case + +- ID: kms/getting-started +- Phase: create +- Complexity: beginner +- Core actions: kms:CreateKey, kms:Encrypt, kms:Decrypt + +## What it does + +1. Creates a customer managed KMS key +2. Creates an alias for the key +3. Describes the key metadata +4. Encrypts data using fileb:// +5. Decrypts the ciphertext +6. Generates a data key for client-side encryption +7. Lists KMS keys and aliases + +## Running + +```bash +bash aws-kms-gs.sh +``` + +## Resources created + +- KMS customer managed key (with alias) + +The key costs $1/month until deleted. The script prompts you to clean up when it finishes. Cleanup schedules the key for deletion with a 7-day waiting period. + +## Estimated time + +- Run: ~7 seconds + +## Cost + +$1/month for the customer managed key. Delete the key promptly to avoid charges. + +## Related docs + +- [Getting started with AWS KMS](https://docs.aws.amazon.com/kms/latest/developerguide/getting-started.html) +- [Creating keys](https://docs.aws.amazon.com/kms/latest/developerguide/create-keys.html) +- [Encrypting and decrypting data](https://docs.aws.amazon.com/kms/latest/developerguide/programming-encryption.html) +- [Data keys](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#data-keys) +- [Deleting KMS keys](https://docs.aws.amazon.com/kms/latest/developerguide/deleting-keys.html) diff --git a/tuts/092-aws-kms-gs/REVISION-HISTORY.md b/tuts/092-aws-kms-gs/REVISION-HISTORY.md new file mode 100644 index 00000000..09b7cba3 --- /dev/null +++ b/tuts/092-aws-kms-gs/REVISION-HISTORY.md @@ -0,0 +1,8 @@ +# Revision History: 092-aws-kms-gs + +## Shell (CLI script) + +### 2026-04-14 v1 published +- Type: functional +- Initial version + diff --git a/tuts/092-aws-kms-gs/aws-kms-gs.md b/tuts/092-aws-kms-gs/aws-kms-gs.md new file mode 100644 index 00000000..402167b9 --- /dev/null +++ b/tuts/092-aws-kms-gs/aws-kms-gs.md @@ -0,0 +1,91 @@ +# Create a key and encrypt data with AWS KMS + +This tutorial shows you how to create a customer managed KMS key, assign it an alias, encrypt and decrypt data, and generate a data key for client-side encryption. + +## Prerequisites + +- AWS CLI configured with credentials and a default region +- Permissions for `kms:CreateKey`, `kms:CreateAlias`, `kms:DescribeKey`, `kms:Encrypt`, `kms:Decrypt`, `kms:GenerateDataKey`, `kms:ListAliases`, `kms:ScheduleKeyDeletion`, `kms:DeleteAlias` + +## Step 1: Create a customer managed key + +```bash +KEY_ID=$(aws kms create-key --description "Tutorial key" \ + --query 'KeyMetadata.KeyId' --output text) +echo "Key ID: $KEY_ID" +``` + +KMS returns the key metadata including the key ID, ARN, and state. The key is enabled immediately. + +## Step 2: Create an alias + +An alias is a friendly name for your key. Alias names must start with `alias/`. + +```bash +aws kms create-alias --alias-name "alias/tutorial-key" --target-key-id "$KEY_ID" +``` + +## Step 3: Describe the key + +```bash +aws kms describe-key --key-id "$KEY_ID" \ + --query 'KeyMetadata.{KeyId:KeyId,State:KeyState,Created:CreationDate,Description:Description}' \ + --output table +``` + +## Step 4: Encrypt data + +Write plaintext to a file and encrypt it using `fileb://` to pass raw bytes: + +```bash +echo "Hello from the KMS tutorial" > plaintext.txt +aws kms encrypt --key-id "$KEY_ID" \ + --plaintext "fileb://plaintext.txt" \ + --output text --query 'CiphertextBlob' > ciphertext.b64 +``` + +The `fileb://` prefix tells the CLI to read the file as raw binary. The output is base64-encoded ciphertext. + +## Step 5: Decrypt data + +Decode the base64 ciphertext to binary, then decrypt: + +```bash +base64 --decode ciphertext.b64 > ciphertext.bin +aws kms decrypt --ciphertext-blob "fileb://ciphertext.bin" \ + --output text --query 'Plaintext' | base64 --decode +``` + +KMS identifies the correct key from metadata embedded in the ciphertext. + +## Step 6: Generate a data key + +A data key lets you encrypt data locally. KMS returns both a plaintext key (for immediate use) and an encrypted copy (to store alongside your data). + +```bash +aws kms generate-data-key --key-id "$KEY_ID" --key-spec AES_256 \ + --query '{KeyId:KeyId}' --output table +``` + +## Step 7: List keys + +```bash +aws kms list-aliases \ + --query 'Aliases[?starts_with(AliasName, `alias/tutorial`)].{Alias:AliasName,KeyId:TargetKeyId}' \ + --output table +``` + +## Cleanup + +Schedule the key for deletion (minimum 7-day waiting period) and delete the alias: + +```bash +aws kms schedule-key-deletion --key-id "$KEY_ID" --pending-window-in-days 7 +aws kms delete-alias --alias-name "alias/tutorial-key" +``` + +The key incurs $1/month until the scheduled deletion completes. The script automates all steps including cleanup: + +```bash +bash aws-kms-gs.sh +``` diff --git a/tuts/092-aws-kms-gs/aws-kms-gs.sh b/tuts/092-aws-kms-gs/aws-kms-gs.sh new file mode 100644 index 00000000..e5fcdcf4 --- /dev/null +++ b/tuts/092-aws-kms-gs/aws-kms-gs.sh @@ -0,0 +1,88 @@ +#!/bin/bash +# Tutorial: Create a KMS key and encrypt data +# Source: https://docs.aws.amazon.com/kms/latest/developerguide/getting-started.html + +WORK_DIR=$(mktemp -d) +LOG_FILE="$WORK_DIR/kms-$(date +%Y%m%d-%H%M%S).log" +exec > >(tee -a "$LOG_FILE") 2>&1 + +REGION=${AWS_DEFAULT_REGION:-${AWS_REGION:-$(aws configure get region 2>/dev/null)}} +if [ -z "$REGION" ]; then + echo "ERROR: No AWS region configured. Set one with: export AWS_DEFAULT_REGION=us-east-1" + exit 1 +fi +export AWS_DEFAULT_REGION="$REGION" +echo "Region: $REGION" + +RANDOM_ID=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 8 | head -n 1) +ALIAS_NAME="alias/tutorial-key-${RANDOM_ID}" + +handle_error() { echo "ERROR on line $1"; trap - ERR; cleanup; exit 1; } +trap 'handle_error $LINENO' ERR + +cleanup() { + echo "" + echo "Cleaning up resources..." + if [ -n "$KEY_ID" ]; then + aws kms schedule-key-deletion --key-id "$KEY_ID" --pending-window-in-days 7 > /dev/null 2>&1 && \ + echo " Scheduled key $KEY_ID for deletion in 7 days" + fi + aws kms delete-alias --alias-name "$ALIAS_NAME" 2>/dev/null && echo " Deleted alias $ALIAS_NAME" + rm -rf "$WORK_DIR" + echo "Cleanup complete." +} + +# Step 1: Create a customer managed key +echo "Step 1: Creating a customer managed KMS key" +KEY_ID=$(aws kms create-key --description "Tutorial key ${RANDOM_ID}" \ + --query 'KeyMetadata.KeyId' --output text) +echo " Key ID: $KEY_ID" + +# Step 2: Create an alias +echo "Step 2: Creating alias: $ALIAS_NAME" +aws kms create-alias --alias-name "$ALIAS_NAME" --target-key-id "$KEY_ID" +echo " Alias created" + +# Step 3: Describe the key +echo "Step 3: Describing the key" +aws kms describe-key --key-id "$KEY_ID" \ + --query 'KeyMetadata.{KeyId:KeyId,State:KeyState,Created:CreationDate,Description:Description}' --output table + +# Step 4: Encrypt data +echo "Step 4: Encrypting data" +echo "Hello from the KMS tutorial" > "$WORK_DIR/plaintext.txt" +aws kms encrypt --key-id "$KEY_ID" \ + --plaintext "fileb://$WORK_DIR/plaintext.txt" \ + --output text --query 'CiphertextBlob' > "$WORK_DIR/ciphertext.b64" +echo " Plaintext: $(cat "$WORK_DIR/plaintext.txt")" +echo " Ciphertext (base64, first 40 chars): $(head -c 40 "$WORK_DIR/ciphertext.b64")..." + +# Step 5: Decrypt data +echo "Step 5: Decrypting data" +cat "$WORK_DIR/ciphertext.b64" | base64 --decode > "$WORK_DIR/ciphertext.bin" +aws kms decrypt --ciphertext-blob "fileb://$WORK_DIR/ciphertext.bin" \ + --output text --query 'Plaintext' | base64 --decode > "$WORK_DIR/decrypted.txt" +echo " Decrypted: $(cat "$WORK_DIR/decrypted.txt")" + +# Step 6: Generate a data key +echo "Step 6: Generating a data key" +aws kms generate-data-key --key-id "$KEY_ID" --key-spec AES_256 \ + --query '{KeyId:KeyId}' --output table +echo " Data key generated (plaintext + encrypted copy returned)" + +# Step 7: List keys +echo "Step 7: Listing KMS keys (first 5)" +aws kms list-aliases --query 'Aliases[?starts_with(AliasName, `alias/tutorial`)].{Alias:AliasName,KeyId:TargetKeyId}' --output table + +echo "" +echo "Tutorial complete." +echo "Do you want to clean up all resources? (y/n): " +read -r CHOICE +if [[ "$CHOICE" =~ ^[Yy]$ ]]; then + cleanup +else + echo "Resources left running. The key will incur $1/month until deleted." + echo "Manual cleanup:" + echo " aws kms schedule-key-deletion --key-id $KEY_ID --pending-window-in-days 7" + echo " aws kms delete-alias --alias-name $ALIAS_NAME" +fi diff --git a/tuts/102-amazon-guardduty-gs/README.md b/tuts/102-amazon-guardduty-gs/README.md new file mode 100644 index 00000000..32999812 --- /dev/null +++ b/tuts/102-amazon-guardduty-gs/README.md @@ -0,0 +1,55 @@ +# GuardDuty: Enable threat detection and review findings + +## Source + +https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_settingup.html + +## Use case + +- **ID**: guardduty/getting-started +- **Level**: beginner +- **Core actions**: `guardduty:CreateDetector`, `guardduty:ListFindings`, `guardduty:GetFindings`, `guardduty:CreateSampleFindings` + +## Steps + +1. Enable GuardDuty (handle pre-existing detector) +2. Get detector details +3. List findings +4. Generate sample findings +5. List findings again +6. Get finding statistics + +## Resources created + +| Resource | Type | +|----------|------| +| GuardDuty detector | `AWS::GuardDuty::Detector` | + +## Duration + +~13 seconds + +## Cost + +GuardDuty offers a free 30-day trial for new accounts. After the trial, pricing is based on the volume of data analyzed (VPC flow logs, DNS logs, CloudTrail events). The detector is deleted during cleanup. + +## Related docs + +- [Setting up GuardDuty](https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_settingup.html) +- [Understanding GuardDuty findings](https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_findings.html) +- [Managing GuardDuty detectors](https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_managing.html) +- [Sample findings](https://docs.aws.amazon.com/guardduty/latest/ug/sample_findings.html) + +--- + +## Appendix + +| Field | Value | +|-------|-------| +| Date | 2026-04-14 | +| Script lines | 97 | +| Exit code | 0 | +| Runtime | 13s | +| Steps | 6 | +| Issues | Handled pre-existing detector | +| Version | v1 | diff --git a/tuts/102-amazon-guardduty-gs/REVISION-HISTORY.md b/tuts/102-amazon-guardduty-gs/REVISION-HISTORY.md new file mode 100644 index 00000000..718945ce --- /dev/null +++ b/tuts/102-amazon-guardduty-gs/REVISION-HISTORY.md @@ -0,0 +1,8 @@ +# Revision History: 102-amazon-guardduty-gs + +## Shell (CLI script) + +### 2026-04-14 v1 published +- Type: functional +- Initial version + diff --git a/tuts/102-amazon-guardduty-gs/amazon-guardduty-gs.md b/tuts/102-amazon-guardduty-gs/amazon-guardduty-gs.md new file mode 100644 index 00000000..22b7dc9f --- /dev/null +++ b/tuts/102-amazon-guardduty-gs/amazon-guardduty-gs.md @@ -0,0 +1,104 @@ +# Enable Amazon GuardDuty and review findings + +This tutorial shows you how to enable Amazon GuardDuty, inspect the detector configuration, generate sample findings, and review finding details and statistics. + +## Prerequisites + +- AWS CLI configured with credentials and a default region +- Permissions for `guardduty:CreateDetector`, `guardduty:GetDetector`, `guardduty:ListFindings`, `guardduty:GetFindings`, `guardduty:CreateSampleFindings`, `guardduty:GetFindingsStatistics`, `guardduty:ListDetectors`, and `guardduty:DeleteDetector` + +## Step 1: Enable GuardDuty + +Check whether GuardDuty is already enabled in the current region. If a detector exists, use it. Otherwise, create one. + +```bash +EXISTING=$(aws guardduty list-detectors --query 'DetectorIds[0]' --output text) + +if [ "$EXISTING" != "None" ] && [ -n "$EXISTING" ]; then + DETECTOR_ID="$EXISTING" + echo "GuardDuty already enabled. Detector: $DETECTOR_ID" +else + DETECTOR_ID=$(aws guardduty create-detector --enable \ + --query 'DetectorId' --output text) + echo "Detector created: $DETECTOR_ID" +fi +``` + +GuardDuty allows only one detector per region per account. If you already have one, the script reuses it and skips deletion during cleanup. + +## Step 2: Get detector details + +```bash +aws guardduty get-detector --detector-id "$DETECTOR_ID" \ + --query '{Status:Status,Created:CreatedAt,Updated:UpdatedAt}' --output table +``` + +The detector status should be `ENABLED`. GuardDuty begins analyzing VPC flow logs, DNS logs, and CloudTrail events immediately. + +## Step 3: List findings + +```bash +FINDING_IDS=$(aws guardduty list-findings --detector-id "$DETECTOR_ID" \ + --max-results 5 --query 'FindingIds' --output json) +echo "$FINDING_IDS" +``` + +A new detector has no findings yet. After generating sample findings in the next step, this list will be populated. + +## Step 4: Generate sample findings + +Create sample findings to see what GuardDuty detections look like without waiting for real threats. + +```bash +aws guardduty create-sample-findings --detector-id "$DETECTOR_ID" \ + --finding-types "Recon:EC2/PortProbeUnprotectedPort" "UnauthorizedAccess:EC2/SSHBruteForce" +sleep 5 +``` + +Sample findings are marked with `[SAMPLE]` in the title. The `sleep` gives GuardDuty time to process them. + +## Step 5: List findings again + +```bash +FINDING_IDS=$(aws guardduty list-findings --detector-id "$DETECTOR_ID" \ + --max-results 5 --query 'FindingIds' --output json) + +aws guardduty get-findings --detector-id "$DETECTOR_ID" \ + --finding-ids $FINDING_IDS \ + --query 'Findings[:3].{Type:Type,Severity:Severity,Title:Title}' --output table +``` + +Each finding includes a type (such as `Recon:EC2/PortProbeUnprotectedPort`), a severity from 0 to 10, and a human-readable title. + +## Step 6: Get finding statistics + +```bash +aws guardduty get-findings-statistics --detector-id "$DETECTOR_ID" \ + --finding-statistic-types COUNT_BY_SEVERITY \ + --query 'FindingStatistics.CountBySeverity' --output table +``` + +The statistics group findings by severity level, giving you a quick overview of your security posture. + +## Cleanup + +If you created the detector in this tutorial, delete it. If the detector was pre-existing, leave it in place. + +```bash +aws guardduty delete-detector --detector-id "$DETECTOR_ID" +``` + +Deleting the detector disables GuardDuty and removes all findings in the region. If you had a pre-existing detector, archive the sample findings from the GuardDuty console instead. + +The script automates all steps including cleanup: + +```bash +bash amazon-guardduty-gs.sh +``` + +## Related resources + +- [Setting up GuardDuty](https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_settingup.html) +- [Understanding GuardDuty findings](https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_findings.html) +- [Managing GuardDuty detectors](https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_managing.html) +- [Sample findings](https://docs.aws.amazon.com/guardduty/latest/ug/sample_findings.html) diff --git a/tuts/102-amazon-guardduty-gs/amazon-guardduty-gs.sh b/tuts/102-amazon-guardduty-gs/amazon-guardduty-gs.sh new file mode 100644 index 00000000..ba544626 --- /dev/null +++ b/tuts/102-amazon-guardduty-gs/amazon-guardduty-gs.sh @@ -0,0 +1,97 @@ +#!/bin/bash +# Tutorial: Enable Amazon GuardDuty and review findings +# Source: https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_settingup.html + +WORK_DIR=$(mktemp -d) +LOG_FILE="$WORK_DIR/guardduty-$(date +%Y%m%d-%H%M%S).log" +exec > >(tee -a "$LOG_FILE") 2>&1 + +REGION=${AWS_DEFAULT_REGION:-${AWS_REGION:-$(aws configure get region 2>/dev/null)}} +if [ -z "$REGION" ]; then + echo "ERROR: No AWS region configured. Set one with: export AWS_DEFAULT_REGION=us-east-1" + exit 1 +fi +export AWS_DEFAULT_REGION="$REGION" +echo "Region: $REGION" + +handle_error() { echo "ERROR on line $1"; trap - ERR; cleanup; exit 1; } +trap 'handle_error $LINENO' ERR + +cleanup() { + echo "" + echo "Cleaning up resources..." + [ -n "$DETECTOR_ID" ] && aws guardduty delete-detector --detector-id "$DETECTOR_ID" 2>/dev/null && \ + echo " Deleted detector $DETECTOR_ID" + rm -rf "$WORK_DIR" + echo "Cleanup complete." +} + +# Step 1: Enable GuardDuty +echo "Step 1: Enabling GuardDuty" +EXISTING=$(aws guardduty list-detectors --query 'DetectorIds[0]' --output text 2>/dev/null) +if [ -n "$EXISTING" ] && [ "$EXISTING" != "None" ]; then + echo " GuardDuty already enabled. Detector: $EXISTING" + DETECTOR_ID="$EXISTING" + PREEXISTING=true +else + DETECTOR_ID=$(aws guardduty create-detector --enable \ + --query 'DetectorId' --output text) + echo " Detector created: $DETECTOR_ID" + PREEXISTING=false +fi + +# Step 2: Get detector details +echo "Step 2: Detector details" +aws guardduty get-detector --detector-id "$DETECTOR_ID" \ + --query '{Status:Status,Created:CreatedAt,Updated:UpdatedAt}' --output table + +# Step 3: List findings +echo "Step 3: Listing findings" +FINDING_IDS=$(aws guardduty list-findings --detector-id "$DETECTOR_ID" \ + --max-results 5 --query 'FindingIds' --output json) +FINDING_COUNT=$(echo "$FINDING_IDS" | python3 -c "import sys,json;print(len(json.load(sys.stdin)))") +echo " Found $FINDING_COUNT findings" + +if [ "$FINDING_COUNT" -gt 0 ]; then + echo "Step 3b: Finding details" + aws guardduty get-findings --detector-id "$DETECTOR_ID" \ + --finding-ids "$FINDING_IDS" \ + --query 'Findings[].{Type:Type,Severity:Severity,Title:Title}' --output table +fi + +# Step 4: Generate sample findings +echo "Step 4: Generating sample findings" +aws guardduty create-sample-findings --detector-id "$DETECTOR_ID" \ + --finding-types "Recon:EC2/PortProbeUnprotectedPort" "UnauthorizedAccess:EC2/SSHBruteForce" +echo " Sample findings generated" +sleep 5 + +# Step 5: List findings again +echo "Step 5: Listing findings (with samples)" +FINDING_IDS=$(aws guardduty list-findings --detector-id "$DETECTOR_ID" \ + --max-results 5 --query 'FindingIds' --output json) +aws guardduty get-findings --detector-id "$DETECTOR_ID" \ + --finding-ids $FINDING_IDS \ + --query 'Findings[:3].{Type:Type,Severity:Severity,Title:Title}' --output table + +# Step 6: Get finding statistics +echo "Step 6: Finding statistics by severity" +aws guardduty get-findings-statistics --detector-id "$DETECTOR_ID" \ + --finding-statistic-types COUNT_BY_SEVERITY \ + --query 'FindingStatistics.CountBySeverity' --output table 2>/dev/null || echo " No statistics available" + +echo "" +echo "Tutorial complete." +if [ "$PREEXISTING" = true ]; then + echo "GuardDuty was already enabled — not deleting the detector." + echo "To archive sample findings: use the GuardDuty console." +else + echo "Do you want to clean up all resources? (y/n): " + read -r CHOICE + if [[ "$CHOICE" =~ ^[Yy]$ ]]; then + cleanup + else + echo "Manual cleanup:" + echo " aws guardduty delete-detector --detector-id $DETECTOR_ID" + fi +fi diff --git a/tuts/108-amazon-inspector-gs/README.md b/tuts/108-amazon-inspector-gs/README.md new file mode 100644 index 00000000..4d74ba0f --- /dev/null +++ b/tuts/108-amazon-inspector-gs/README.md @@ -0,0 +1,49 @@ +# Inspector: Enable scanning and view findings + +Enable Amazon Inspector for EC2, ECR, and Lambda scanning, view findings by severity, and check coverage statistics. + +## Source + +https://docs.aws.amazon.com/inspector/latest/user/getting_started_tutorial.html + +## Use case + +- ID: inspector/getting-started +- Phase: create +- Complexity: beginner +- Core actions: inspector2:Enable, inspector2:BatchGetAccountStatus, inspector2:ListFindings + +## What it does + +1. Enables Inspector for EC2, ECR, and Lambda (handles pre-existing) +2. Gets account scanning status +3. Lists findings by severity +4. Gets finding counts by severity +5. Gets coverage statistics + +## Running + +```bash +bash amazon-inspector-gs.sh +``` + +## Resources created + +| Resource | Type | +|----------|------| +| Inspector enablement | Service activation (EC2, ECR, Lambda) | + +## Estimated time + +- Run: ~11 seconds + +## Cost + +Free 15-day trial for new accounts. After the trial, pricing is based on the number of resources scanned. Cleanup disables Inspector to stop charges. + +## Related docs + +- [Getting started with Amazon Inspector](https://docs.aws.amazon.com/inspector/latest/user/getting_started_tutorial.html) +- [Understanding findings](https://docs.aws.amazon.com/inspector/latest/user/findings-understanding.html) +- [Managing coverage](https://docs.aws.amazon.com/inspector/latest/user/managing-coverage.html) +- [Amazon Inspector pricing](https://aws.amazon.com/inspector/pricing/) diff --git a/tuts/108-amazon-inspector-gs/REVISION-HISTORY.md b/tuts/108-amazon-inspector-gs/REVISION-HISTORY.md new file mode 100644 index 00000000..a886cc62 --- /dev/null +++ b/tuts/108-amazon-inspector-gs/REVISION-HISTORY.md @@ -0,0 +1,8 @@ +# Revision History: 108-amazon-inspector-gs + +## Shell (CLI script) + +### 2026-04-14 v1 published +- Type: functional +- Initial version + diff --git a/tuts/108-amazon-inspector-gs/amazon-inspector-gs.md b/tuts/108-amazon-inspector-gs/amazon-inspector-gs.md new file mode 100644 index 00000000..4f76d92a --- /dev/null +++ b/tuts/108-amazon-inspector-gs/amazon-inspector-gs.md @@ -0,0 +1,99 @@ +# Enable scanning and view findings with Amazon Inspector + +This tutorial shows you how to enable Amazon Inspector for EC2, ECR, and Lambda scanning, check account status, list findings by severity, view finding counts, and get coverage statistics. + +## Prerequisites + +- AWS CLI configured with credentials and a default region +- Permissions for `inspector2:Enable`, `inspector2:Disable`, `inspector2:BatchGetAccountStatus`, `inspector2:ListFindings`, `inspector2:ListFindingAggregations`, `inspector2:ListCoverageStatistics` + +## Step 1: Enable Inspector + +Enable Inspector for EC2 instances, ECR container images, and Lambda functions. If Inspector is already enabled, the script detects this and skips enablement. + +```bash +STATUS=$(aws inspector2 batch-get-account-status \ + --query 'accounts[0].state.status' --output text 2>/dev/null || echo "DISABLED") + +if [ "$STATUS" = "ENABLED" ]; then + echo "Inspector already enabled" +else + aws inspector2 enable --resource-types EC2 ECR LAMBDA +fi +``` + +When you enable Inspector, it automatically begins scanning supported resources. New EC2 instances, ECR images, and Lambda functions are scanned as they appear. + +## Step 2: Get account status + +Check the scanning status for each resource type. + +```bash +aws inspector2 batch-get-account-status \ + --query 'accounts[0].{Status:state.status,EC2:resourceState.ec2.status,ECR:resourceState.ecr.status,Lambda:resourceState.lambda.status}' \ + --output table +``` + +Each resource type has its own status. All three should show `ENABLED` after activation. + +## Step 3: List findings by severity + +List the top findings sorted by severity. + +```bash +aws inspector2 list-findings \ + --sort-criteria '{"field":"SEVERITY","sortOrder":"DESC"}' \ + --max-results 5 \ + --query 'findings[].{Title:title,Severity:severity,Type:type,Status:status}' \ + --output table +``` + +Inspector generates findings for software vulnerabilities and unintended network exposure. Findings appear as Inspector completes its initial scan, which may take several minutes. + +## Step 4: Get finding counts + +View aggregated finding counts by severity level. + +```bash +aws inspector2 list-finding-aggregations \ + --aggregation-type SEVERITY \ + --query 'responses[].{Severity:severityCounts}' \ + --output json +``` + +## Step 5: Get coverage statistics + +Check how many resources Inspector is scanning. + +```bash +aws inspector2 list-coverage-statistics \ + --query 'countsByGroup[].{ResourceType:groupKey,Count:count}' \ + --output table +``` + +Coverage statistics show the number of resources being scanned, grouped by resource type. + +## Cleanup + +If you enabled Inspector during this tutorial, disable it to stop scanning: + +```bash +aws inspector2 disable --resource-types EC2 ECR LAMBDA +``` + +If Inspector was already enabled before the tutorial, the script leaves it running. + +Inspector offers a free 15-day trial for new accounts. After the trial, you pay based on the number of resources scanned. Disabling stops all scanning and future charges. + +The script automates all steps including cleanup: + +```bash +bash amazon-inspector-gs.sh +``` + +## Related resources + +- [Getting started with Amazon Inspector](https://docs.aws.amazon.com/inspector/latest/user/getting_started_tutorial.html) +- [Understanding findings](https://docs.aws.amazon.com/inspector/latest/user/findings-understanding.html) +- [Managing coverage](https://docs.aws.amazon.com/inspector/latest/user/managing-coverage.html) +- [Amazon Inspector pricing](https://aws.amazon.com/inspector/pricing/) diff --git a/tuts/108-amazon-inspector-gs/amazon-inspector-gs.sh b/tuts/108-amazon-inspector-gs/amazon-inspector-gs.sh new file mode 100644 index 00000000..d5c53b0c --- /dev/null +++ b/tuts/108-amazon-inspector-gs/amazon-inspector-gs.sh @@ -0,0 +1,86 @@ +#!/bin/bash +# Tutorial: Enable Amazon Inspector and view findings +# Source: https://docs.aws.amazon.com/inspector/latest/user/getting_started_tutorial.html + +WORK_DIR=$(mktemp -d) +LOG_FILE="$WORK_DIR/inspector-$(date +%Y%m%d-%H%M%S).log" +exec > >(tee -a "$LOG_FILE") 2>&1 + +REGION=${AWS_DEFAULT_REGION:-${AWS_REGION:-$(aws configure get region 2>/dev/null)}} +if [ -z "$REGION" ]; then + echo "ERROR: No AWS region configured. Set one with: export AWS_DEFAULT_REGION=us-east-1" + exit 1 +fi +export AWS_DEFAULT_REGION="$REGION" +echo "Region: $REGION" + +handle_error() { echo "ERROR on line $1"; trap - ERR; cleanup; exit 1; } +trap 'handle_error $LINENO' ERR + +cleanup() { + echo "" + echo "Cleaning up resources..." + if [ "$PREEXISTING" != true ]; then + aws inspector2 disable --resource-types EC2 ECR LAMBDA > /dev/null 2>&1 && \ + echo " Disabled Inspector" + else + echo " Inspector was already enabled — not disabling" + fi + rm -rf "$WORK_DIR" + echo "Cleanup complete." +} + +# Step 1: Check/Enable Inspector +echo "Step 1: Enabling Amazon Inspector" +STATUS=$(aws inspector2 batch-get-account-status \ + --query 'accounts[0].state.status' --output text 2>/dev/null || echo "DISABLED") +if [ "$STATUS" = "ENABLED" ]; then + echo " Inspector already enabled" + PREEXISTING=true +else + aws inspector2 enable --resource-types EC2 ECR LAMBDA > /dev/null + echo " Inspector enabled for EC2, ECR, and Lambda" + PREEXISTING=false + sleep 5 +fi + +# Step 2: Get account status +echo "Step 2: Account status" +aws inspector2 batch-get-account-status \ + --query 'accounts[0].{Status:state.status,EC2:resourceState.ec2.status,ECR:resourceState.ecr.status,Lambda:resourceState.lambda.status}' --output table + +# Step 3: List findings +echo "Step 3: Listing findings (top 5 by severity)" +aws inspector2 list-findings \ + --sort-criteria '{"field":"SEVERITY","sortOrder":"DESC"}' \ + --max-results 5 \ + --query 'findings[].{Title:title,Severity:severity,Type:type,Status:status}' --output table 2>/dev/null || \ + echo " No findings yet (Inspector needs time to scan resources)" + +# Step 4: Get finding counts by severity +echo "Step 4: Finding counts" +aws inspector2 list-finding-aggregations \ + --aggregation-type SEVERITY \ + --query 'responses[].{Severity:severityCounts}' --output json 2>/dev/null | python3 -m json.tool 2>/dev/null || \ + echo " No aggregation data available yet" + +# Step 5: Get coverage statistics +echo "Step 5: Coverage statistics" +aws inspector2 list-coverage-statistics \ + --query 'countsByGroup[].{ResourceType:groupKey,Count:count}' --output table 2>/dev/null || \ + echo " No coverage data available yet" + +echo "" +echo "Tutorial complete." +if [ "$PREEXISTING" = true ]; then + echo "Inspector was already enabled — not disabling." +else + echo "Do you want to clean up (disable Inspector)? (y/n): " + read -r CHOICE + if [[ "$CHOICE" =~ ^[Yy]$ ]]; then + cleanup + else + echo "Inspector remains enabled. It will scan resources automatically." + echo "Manual cleanup: aws inspector2 disable --resource-types EC2 ECR LAMBDA" + fi +fi diff --git a/tuts/109-aws-securityhub-gs/README.md b/tuts/109-aws-securityhub-gs/README.md new file mode 100644 index 00000000..8f51bfe9 --- /dev/null +++ b/tuts/109-aws-securityhub-gs/README.md @@ -0,0 +1,49 @@ +# Security Hub: Enable and view security standards + +Enable AWS Security Hub with default standards, list enabled standards, view findings by severity, and get finding statistics. + +## Source + +https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-settingup.html + +## Use case + +- ID: securityhub/getting-started +- Phase: create +- Complexity: beginner +- Core actions: securityhub:EnableSecurityHub, securityhub:GetEnabledStandards, securityhub:GetFindings + +## What it does + +1. Enables Security Hub with default standards (handles pre-existing) +2. Lists enabled security standards +3. Describes hub configuration +4. Lists findings by severity +5. Gets finding statistics by severity level + +## Running + +```bash +bash aws-securityhub-gs.sh +``` + +## Resources created + +| Resource | Type | +|----------|------| +| Security Hub enablement | Service activation (with default standards) | + +## Estimated time + +- Run: ~12 seconds + +## Cost + +Free 30-day trial for new accounts. After the trial, pricing is based on security checks and finding ingestion events. Cleanup disables Security Hub to stop charges. + +## Related docs + +- [Setting up Security Hub](https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-settingup.html) +- [Security standards in Security Hub](https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-standards.html) +- [Viewing findings](https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-findings-viewing.html) +- [AWS Security Hub pricing](https://aws.amazon.com/security-hub/pricing/) diff --git a/tuts/109-aws-securityhub-gs/REVISION-HISTORY.md b/tuts/109-aws-securityhub-gs/REVISION-HISTORY.md new file mode 100644 index 00000000..47bb5ba3 --- /dev/null +++ b/tuts/109-aws-securityhub-gs/REVISION-HISTORY.md @@ -0,0 +1,8 @@ +# Revision History: 109-aws-securityhub-gs + +## Shell (CLI script) + +### 2026-04-14 v1 published +- Type: functional +- Initial version + diff --git a/tuts/109-aws-securityhub-gs/aws-securityhub-gs.md b/tuts/109-aws-securityhub-gs/aws-securityhub-gs.md new file mode 100644 index 00000000..2b0155ee --- /dev/null +++ b/tuts/109-aws-securityhub-gs/aws-securityhub-gs.md @@ -0,0 +1,101 @@ +# Enable and view security standards with AWS Security Hub + +This tutorial shows you how to enable AWS Security Hub with default security standards, list enabled standards, view hub configuration, list findings by severity, and get finding statistics. + +## Prerequisites + +- AWS CLI configured with credentials and a default region +- Permissions for `securityhub:EnableSecurityHub`, `securityhub:DisableSecurityHub`, `securityhub:DescribeHub`, `securityhub:GetEnabledStandards`, `securityhub:GetFindings` + +## Step 1: Enable Security Hub + +Enable Security Hub with default security standards. If Security Hub is already enabled, the script detects this and skips enablement. + +```bash +ENABLED=$(aws securityhub describe-hub \ + --query 'HubArn' --output text 2>/dev/null || echo "NONE") + +if [ "$ENABLED" != "NONE" ]; then + echo "Security Hub already enabled: $ENABLED" +else + aws securityhub enable-security-hub --enable-default-standards +fi +``` + +Enabling with `--enable-default-standards` automatically subscribes you to the AWS Foundational Security Best Practices standard and CIS AWS Foundations Benchmark. + +## Step 2: List enabled standards + +View which security standards are active in your account. + +```bash +aws securityhub get-enabled-standards \ + --query 'StandardsSubscriptions[].{Standard:StandardsArn,Status:StandardsStatus}' \ + --output table +``` + +Each standard contains a set of security controls. Standards take a few minutes to finish their initial evaluation. + +## Step 3: Describe hub + +Check the hub configuration. + +```bash +aws securityhub describe-hub \ + --query '{AutoEnable:AutoEnableControls,HubArn:HubArn}' \ + --output table +``` + +`AutoEnableControls` indicates whether new controls are automatically enabled when a standard is updated. + +## Step 4: List findings by severity + +List the most severe findings across all enabled standards. + +```bash +aws securityhub get-findings \ + --sort-criteria '{"Field":"SeverityNormalized","SortOrder":"desc"}' \ + --max-results 5 \ + --query 'Findings[].{Title:Title,Severity:Severity.Label,Status:Workflow.Status,Product:ProductName}' \ + --output table +``` + +Security Hub normalizes severity across all integrated products to CRITICAL, HIGH, MEDIUM, LOW, and INFORMATIONAL. + +## Step 5: Get finding statistics + +Count findings by severity level. + +```bash +aws securityhub get-findings \ + --max-results 100 \ + --query 'Findings[].Severity.Label' --output text \ + | tr '\t' '\n' | sort | uniq -c | sort -rn +``` + +This retrieves up to 100 findings and counts them by severity label. For accounts with many findings, use `--filters` to narrow the scope. + +## Cleanup + +If you enabled Security Hub during this tutorial, disable it: + +```bash +aws securityhub disable-security-hub +``` + +If Security Hub was already enabled before the tutorial, the script leaves it running. + +Security Hub offers a free 30-day trial for new accounts. After the trial, you pay based on the number of security checks and finding ingestion events. Disabling stops all checks and future charges. + +The script automates all steps including cleanup: + +```bash +bash aws-securityhub-gs.sh +``` + +## Related resources + +- [Setting up Security Hub](https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-settingup.html) +- [Security standards in Security Hub](https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-standards.html) +- [Viewing findings](https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-findings-viewing.html) +- [AWS Security Hub pricing](https://aws.amazon.com/security-hub/pricing/) diff --git a/tuts/109-aws-securityhub-gs/aws-securityhub-gs.sh b/tuts/109-aws-securityhub-gs/aws-securityhub-gs.sh new file mode 100644 index 00000000..2594a7e7 --- /dev/null +++ b/tuts/109-aws-securityhub-gs/aws-securityhub-gs.sh @@ -0,0 +1,83 @@ +#!/bin/bash +# Tutorial: Enable AWS Security Hub and view security standards +# Source: https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-settingup.html + +WORK_DIR=$(mktemp -d) +LOG_FILE="$WORK_DIR/securityhub-$(date +%Y%m%d-%H%M%S).log" +exec > >(tee -a "$LOG_FILE") 2>&1 + +REGION=${AWS_DEFAULT_REGION:-${AWS_REGION:-$(aws configure get region 2>/dev/null)}} +if [ -z "$REGION" ]; then + echo "ERROR: No AWS region configured. Set one with: export AWS_DEFAULT_REGION=us-east-1" + exit 1 +fi +export AWS_DEFAULT_REGION="$REGION" +echo "Region: $REGION" + +handle_error() { echo "ERROR on line $1"; trap - ERR; cleanup; exit 1; } +trap 'handle_error $LINENO' ERR + +cleanup() { + echo "" + echo "Cleaning up resources..." + if [ "$PREEXISTING" != true ]; then + aws securityhub disable-security-hub 2>/dev/null && echo " Disabled Security Hub" + else + echo " Security Hub was already enabled — not disabling" + fi + rm -rf "$WORK_DIR" + echo "Cleanup complete." +} + +# Step 1: Check/Enable Security Hub +echo "Step 1: Enabling Security Hub" +ENABLED=$(aws securityhub describe-hub --query 'HubArn' --output text 2>/dev/null || echo "NONE") +if [ "$ENABLED" != "NONE" ]; then + echo " Security Hub already enabled: $ENABLED" + PREEXISTING=true +else + aws securityhub enable-security-hub --enable-default-standards > /dev/null + echo " Security Hub enabled with default standards" + PREEXISTING=false + sleep 5 +fi + +# Step 2: List enabled standards +echo "Step 2: Enabled security standards" +aws securityhub get-enabled-standards \ + --query 'StandardsSubscriptions[].{Standard:StandardsArn,Status:StandardsStatus}' --output table + +# Step 3: Describe hub +echo "Step 3: Hub details" +aws securityhub describe-hub \ + --query '{AutoEnable:AutoEnableControls,HubArn:HubArn}' --output table + +# Step 4: List findings (top 5) +echo "Step 4: Recent findings (top 5)" +aws securityhub get-findings \ + --sort-criteria '{"Field":"SeverityNormalized","SortOrder":"desc"}' \ + --max-results 5 \ + --query 'Findings[].{Title:Title,Severity:Severity.Label,Status:Workflow.Status,Product:ProductName}' --output table 2>/dev/null || \ + echo " No findings yet (Security Hub needs time to run checks)" + +# Step 5: Get finding counts by severity +echo "Step 5: Finding statistics" +aws securityhub get-findings \ + --max-results 100 \ + --query 'Findings[].Severity.Label' --output text 2>/dev/null | tr '\t' '\n' | sort | uniq -c | sort -rn || \ + echo " No findings available" + +echo "" +echo "Tutorial complete." +if [ "$PREEXISTING" = true ]; then + echo "Security Hub was already enabled — not disabling." +else + echo "Do you want to clean up (disable Security Hub)? (y/n): " + read -r CHOICE + if [[ "$CHOICE" =~ ^[Yy]$ ]]; then + cleanup + else + echo "Security Hub remains enabled." + echo "Manual cleanup: aws securityhub disable-security-hub" + fi +fi diff --git a/tuts/120-aws-sts-gs/README.md b/tuts/120-aws-sts-gs/README.md new file mode 100644 index 00000000..7bdd859c --- /dev/null +++ b/tuts/120-aws-sts-gs/README.md @@ -0,0 +1,39 @@ +# Aws Sts Gs + +An AWS CLI tutorial that demonstrates Iam operations. + +## Running + +```bash +bash aws-sts-gs.sh +``` + +To auto-run with cleanup: + +```bash +echo 'y' | bash aws-sts-gs.sh +``` + +## What it does + +1. Getting caller identity +2. Creating a role to assume +3. Assuming the role +4. Using temporary credentials +5. Session tags (decode token) + +## Resources created + +- Role +- Role Policy + +The script prompts you to clean up resources when it finishes. + +## Cost + +Free tier eligible for most operations. Clean up resources after use to avoid charges. + +## Related docs + +- [AWS CLI iam reference](https://docs.aws.amazon.com/cli/latest/reference/iam/index.html) + diff --git a/tuts/120-aws-sts-gs/REVISION-HISTORY.md b/tuts/120-aws-sts-gs/REVISION-HISTORY.md new file mode 100644 index 00000000..0c4233b7 --- /dev/null +++ b/tuts/120-aws-sts-gs/REVISION-HISTORY.md @@ -0,0 +1,8 @@ +# Revision History: 120-aws-sts-gs + +## Shell (CLI script) + +### 2026-04-14 v1 published +- Type: functional +- Initial version + diff --git a/tuts/120-aws-sts-gs/aws-sts-gs.md b/tuts/120-aws-sts-gs/aws-sts-gs.md new file mode 100644 index 00000000..bc4d28cf --- /dev/null +++ b/tuts/120-aws-sts-gs/aws-sts-gs.md @@ -0,0 +1,31 @@ +# Aws Sts Gs + +## Prerequisites + +1. AWS CLI installed and configured (`aws configure`) +2. Appropriate IAM permissions for the AWS services used + +## Step 1: Getting caller identity + +The script handles this step automatically. See `aws-sts-gs.sh` for the exact CLI commands. + +## Step 2: Creating a role to assume + +The script handles this step automatically. See `aws-sts-gs.sh` for the exact CLI commands. + +## Step 3: Assuming the role + +The script handles this step automatically. See `aws-sts-gs.sh` for the exact CLI commands. + +## Step 4: Using temporary credentials + +The script handles this step automatically. See `aws-sts-gs.sh` for the exact CLI commands. + +## Step 5: Session tags (decode token) + +The script handles this step automatically. See `aws-sts-gs.sh` for the exact CLI commands. + +## Cleanup + +The script prompts you to clean up all created resources. If you need to clean up manually, check the script log for the resource names that were created. + diff --git a/tuts/120-aws-sts-gs/aws-sts-gs.sh b/tuts/120-aws-sts-gs/aws-sts-gs.sh new file mode 100644 index 00000000..62fcf7e2 --- /dev/null +++ b/tuts/120-aws-sts-gs/aws-sts-gs.sh @@ -0,0 +1,37 @@ +#!/bin/bash +WORK_DIR=$(mktemp -d) +LOG_FILE="$WORK_DIR/sts-$(date +%Y%m%d-%H%M%S).log" +exec > >(tee -a "$LOG_FILE") 2>&1 +REGION=${AWS_DEFAULT_REGION:-${AWS_REGION:-$(aws configure get region 2>/dev/null))} +[ -z "$REGION" ] && echo "ERROR: No region" && exit 1 +export AWS_DEFAULT_REGION="$REGION" +echo "Region: $REGION" +RANDOM_ID=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 8 | head -n 1) +ROLE_NAME="sts-tut-role-${RANDOM_ID}" +handle_error() { echo "ERROR on line $1"; trap - ERR; cleanup; exit 1; } +trap 'handle_error $LINENO' ERR +cleanup() { echo ""; echo "Cleaning up..."; aws iam delete-role-policy --role-name "$ROLE_NAME" --policy-name s3-read 2>/dev/null; aws iam delete-role --role-name "$ROLE_NAME" 2>/dev/null && echo " Deleted role"; rm -rf "$WORK_DIR"; echo "Done."; } +echo "Step 1: Getting caller identity" +aws sts get-caller-identity --query '{Account:Account,Arn:Arn,UserId:UserId}' --output table +ACCOUNT=$(aws sts get-caller-identity --query 'Account' --output text) +CALLER_ARN=$(aws sts get-caller-identity --query 'Arn' --output text) +echo "Step 2: Creating a role to assume" +ROLE_ARN=$(aws iam create-role --role-name "$ROLE_NAME" --assume-role-policy-document "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"$CALLER_ARN\"},\"Action\":\"sts:AssumeRole\"}]}" --query 'Role.Arn' --output text) +aws iam put-role-policy --role-name "$ROLE_NAME" --policy-name s3-read --policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["s3:ListAllMyBuckets"],"Resource":"*"}]}' +echo " Role: $ROLE_ARN" +sleep 10 +echo "Step 3: Assuming the role" +CREDS=$(aws sts assume-role --role-arn "$ROLE_ARN" --role-session-name tutorial-session --duration-seconds 900) +echo "$CREDS" | python3 -c "import sys,json;c=json.load(sys.stdin)['Credentials'];print(f\" AccessKeyId: {c['AccessKeyId'][:8]}...\\n Expiration: {c['Expiration']}\")" +echo "Step 4: Using temporary credentials" +AK=$(echo "$CREDS" | python3 -c "import sys,json;print(json.load(sys.stdin)['Credentials']['AccessKeyId'])") +SK=$(echo "$CREDS" | python3 -c "import sys,json;print(json.load(sys.stdin)['Credentials']['SecretAccessKey'])") +ST=$(echo "$CREDS" | python3 -c "import sys,json;print(json.load(sys.stdin)['Credentials']['SessionToken'])") +AWS_ACCESS_KEY_ID=$AK AWS_SECRET_ACCESS_KEY=$SK AWS_SESSION_TOKEN=$ST aws sts get-caller-identity --query '{Arn:Arn}' --output table +echo "Step 5: Session tags (decode token)" +aws sts decode-authorization-message --encoded-message test 2>/dev/null || echo " (decode requires specific permissions — expected)" +echo "" +echo "Tutorial complete." +echo "Do you want to clean up? (y/n): " +read -r CHOICE +[[ "$CHOICE" =~ ^[Yy]$ ]] && cleanup || echo "Manual: aws iam delete-role --role-name $ROLE_NAME"