Commit 10729070f7
Unsigned
Layout: unified · split
applications/aws/README.md +37
| @@ -204,4 +204,41 @@ Rule#,Policy‑Item,Expected,Actual,Result | |||
| 204 | 8,Maximum password age (days),90,90,PASS | 204 | 8,Maximum password age (days),90,90,PASS |
| 205 | 9,Prevent password reuse (last N),4,4,PASS | 205 | 9,Prevent password reuse (last N),4,4,PASS |
| 206 | 10,Hard expiry (no grace period),false,false,PASS | 206 | 10,Hard expiry (no grace period),false,false,PASS |
| 207 | ``` | ||
| 208 | |||
| 209 | # `aws_s3_buckets.sh` | ||
| 210 | |||
| 211 | This script requires one non-interactive step. Simply run the script: | ||
| 212 | |||
| 213 | ``` bash | ||
| 214 | chmod +x aws_s3_buckets.sh | ||
| 215 | ./aws_s3_buckets.sh | ||
| 216 | ``` | ||
| 217 | |||
| 218 | The shell will show you each bucket discovered during the scanning process, as well as the final result. This final result is a combination of the bucket's Public Access Block (PAB), Policy Status (IsPublic), and ACLs (AllUsers Group). | ||
| 219 | |||
| 220 | ``` text | ||
| 221 | Starting FULL S3 Public Access Audit for the CURRENT account... | ||
| 222 | --- | ||
| 223 | 1. Retrieving all bucket names... | ||
| 224 | Processing bucket: 13bf5920-a09f-47bc-a75a-394a09f18d6a | ||
| 225 | Region determined: eu-west-1 | ||
| 226 | Final Status: FALSE | ||
| 227 | Processing bucket: c67fa6bd-2fd5-4bc5-825d-587fb535bf2e | ||
| 228 | Region determined: eu-west-1 | ||
| 229 | Final Status: FALSE | ||
| 230 | --- | ||
| 231 | ✅ Audit Complete. | ||
| 232 | Final report saved to **s3_full_public_access_audit.csv** | ||
| 233 | BucketName,Region,PAB_FullyRestricted,Policy_IsPublic,ACL_AllUsersRead,ACL_AllUsersWrite,OverallPublicStatus | ||
| 234 | 13bf5920-a09f-47bc-a75a-394a09f18d6a,eu-west-1,FALSE-VULNERABLE,No Policy,FALSE,FALSE,"FALSE" | ||
| 235 | c67fa6bd-2fd5-4bc5-825d-587fb535bf2e,eu-west-1,TRUE,No Policy,FALSE,FALSE,"FALSE" | ||
| 236 | ``` | ||
| 237 | |||
| 238 | It will also save the results shown above to the `s3_full_public_access_audit.csv` file: | ||
| 239 | |||
| 240 | ``` csv | ||
| 241 | BucketName,Region,PAB_FullyRestricted,Policy_IsPublic,ACL_AllUsersRead,ACL_AllUsersWrite,OverallPublicStatus | ||
| 242 | 13bf5920-a09f-47bc-a75a-394a09f18d6a,eu-west-1,FALSE-VULNERABLE,No Policy,FALSE,FALSE,"FALSE" | ||
| 243 | c67fa6bd-2fd5-4bc5-825d-587fb535bf2e,eu-west-1,TRUE,No Policy,FALSE,FALSE,"FALSE" | ||
| 207 | ```\ No newline at end of file | 244 | ```\ No newline at end of file |
applications/aws/aws_s3_buckets.sh added +131
| @@ -0,0 +1,131 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | |||
| 3 | # --- Configuration --- | ||
| 4 | # File to store the final report | ||
| 5 | REPORT_FILE="s3_full_public_access_audit.csv" | ||
| 6 | # The region to use for the initial global list-buckets call (e.g., 'us-east-1') | ||
| 7 | MASTER_REGION="us-east-1" | ||
| 8 | |||
| 9 | # AWS Regions to check for bucket location. Add more regions if your organization uses them. | ||
| 10 | AWS_REGIONS="us-east-1 us-west-2 eu-central-1 ap-southeast-2" | ||
| 11 | |||
| 12 | # --- Initialization --- | ||
| 13 | echo "BucketName,Region,PAB_FullyRestricted,Policy_IsPublic,ACL_AllUsersRead,ACL_AllUsersWrite,OverallPublicStatus" > "$REPORT_FILE" | ||
| 14 | echo "Starting FULL S3 Public Access Audit for the CURRENT account..." | ||
| 15 | echo "---" | ||
| 16 | |||
| 17 | # 1. Retrieve all bucket names | ||
| 18 | echo "1. Retrieving all bucket names..." | ||
| 19 | BUCKET_LIST=$(aws s3api list-buckets --region "$MASTER_REGION" --query 'Buckets[].Name' --output text) | ||
| 20 | |||
| 21 | if [ -z "$BUCKET_LIST" ]; then | ||
| 22 | echo "✅ No S3 buckets found in this account." | ||
| 23 | exit 0 | ||
| 24 | fi | ||
| 25 | |||
| 26 | # 2. & 3. Iterate through each bucket to find location and run checks | ||
| 27 | for BUCKET_NAME in $BUCKET_LIST; do | ||
| 28 | |||
| 29 | echo "Processing bucket: $BUCKET_NAME" | ||
| 30 | BUCKET_REGION="" | ||
| 31 | |||
| 32 | # 2. Find the bucket region | ||
| 33 | for REGION in $AWS_REGIONS; do | ||
| 34 | BUCKET_LOCATION_RESPONSE=$(aws s3api get-bucket-location --bucket "$BUCKET_NAME" --region "$REGION" 2>/dev/null) | ||
| 35 | if [ $? -eq 0 ]; then | ||
| 36 | LOCATION_CONSTRAINT=$(echo "$BUCKET_LOCATION_RESPONSE" | jq -r '.LocationConstraint') | ||
| 37 | BUCKET_REGION=${LOCATION_CONSTRAINT:-"us-east-1"} | ||
| 38 | break | ||
| 39 | fi | ||
| 40 | done | ||
| 41 | |||
| 42 | if [ -z "$BUCKET_REGION" ]; then | ||
| 43 | echo " ⚠️ WARNING: Could not determine region for $BUCKET_NAME. Skipping all checks." | ||
| 44 | echo "$BUCKET_NAME,UNKNOWN,N/A,N/A,N/A,N/A,UNKNOWN" >> "$REPORT_FILE" | ||
| 45 | continue | ||
| 46 | fi | ||
| 47 | |||
| 48 | echo " Region determined: $BUCKET_REGION" | ||
| 49 | |||
| 50 | # --- Variables for the three checks --- | ||
| 51 | PAB_FULLY_RESTRICTED="UNKNOWN" | ||
| 52 | POLICY_IS_PUBLIC="UNKNOWN" | ||
| 53 | ACL_ALL_USERS_READ="FALSE" | ||
| 54 | ACL_ALL_USERS_WRITE="FALSE" | ||
| 55 | OVERALL_PUBLIC_STATUS="FALSE" # Assume safe until proven otherwise | ||
| 56 | |||
| 57 | # --- CHECK A: Public Access Block (PAB) --- | ||
| 58 | PAB_STATUS=$(aws s3api get-public-access-block --bucket "$BUCKET_NAME" --region "$BUCKET_REGION" 2>/dev/null) | ||
| 59 | |||
| 60 | if [ $? -ne 0 ]; then | ||
| 61 | # PAB Missing is the highest risk state. | ||
| 62 | PAB_FULLY_RESTRICTED="CRITICAL-MISSING" | ||
| 63 | OVERALL_PUBLIC_STATUS="TRUE - PAB Missing" | ||
| 64 | else | ||
| 65 | # Check if ALL four PAB flags are true | ||
| 66 | PAB_CONFIG=$(echo "$PAB_STATUS" | jq -r '.PublicAccessBlockConfiguration') | ||
| 67 | if [ "$(echo "$PAB_CONFIG" | jq -r '.BlockPublicAcls and .IgnorePublicAcls and .BlockPublicPolicy and .RestrictPublicBuckets')" = "true" ]; then | ||
| 68 | PAB_FULLY_RESTRICTED="TRUE" | ||
| 69 | else | ||
| 70 | PAB_FULLY_RESTRICTED="FALSE-VULNERABLE" | ||
| 71 | fi | ||
| 72 | fi | ||
| 73 | |||
| 74 | # --- CHECK B: Bucket Policy Status (If S3 service thinks it's public) --- | ||
| 75 | POLICY_STATUS=$(aws s3api get-bucket-policy-status --bucket "$BUCKET_NAME" --region "$BUCKET_REGION" 2>/dev/null) | ||
| 76 | |||
| 77 | if [ $? -eq 0 ]; then | ||
| 78 | POLICY_IS_PUBLIC=$(echo "$POLICY_STATUS" | jq -r '.PolicyStatus.IsPublic') | ||
| 79 | if [ "$POLICY_IS_PUBLIC" = "true" ]; then | ||
| 80 | OVERALL_PUBLIC_STATUS="TRUE - Policy" | ||
| 81 | fi | ||
| 82 | else | ||
| 83 | # Expected error if no bucket policy exists, treat as NOT public via policy. | ||
| 84 | POLICY_IS_PUBLIC="No Policy" | ||
| 85 | fi | ||
| 86 | |||
| 87 | # --- CHECK C: Bucket ACLs (for AllUsers group) --- | ||
| 88 | ACL_RESPONSE=$(aws s3api get-bucket-acl --bucket "$BUCKET_NAME" --region "$BUCKET_REGION" 2>/dev/null) | ||
| 89 | |||
| 90 | if [ $? -eq 0 ]; then | ||
| 91 | # Find if any grant to 'http://acs.amazonaws.com/groups/global/AllUsers' exists | ||
| 92 | |||
| 93 | # Check for READ access | ||
| 94 | if echo "$ACL_RESPONSE" | jq -e '.Grants[] | select(.Grantee.URI=="http://acs.amazonaws.com/groups/global/AllUsers") | select(.Permission | test("READ|FULL_CONTROL"))' >/dev/null; then | ||
| 95 | ACL_ALL_USERS_READ="TRUE" | ||
| 96 | if [ "$OVERALL_PUBLIC_STATUS" = "FALSE" ]; then | ||
| 97 | OVERALL_PUBLIC_STATUS="TRUE - ACL Read" | ||
| 98 | fi | ||
| 99 | fi | ||
| 100 | |||
| 101 | # Check for WRITE access (often less common for public, but still public exposure) | ||
| 102 | if echo "$ACL_RESPONSE" | jq -e '.Grants[] | select(.Grantee.URI=="http://acs.amazonaws.com/groups/global/AllUsers") | select(.Permission | test("WRITE|FULL_CONTROL"))' >/dev/null; then | ||
| 103 | ACL_ALL_USERS_WRITE="TRUE" | ||
| 104 | if [ "$OVERALL_PUBLIC_STATUS" = "FALSE" ]; then | ||
| 105 | OVERALL_PUBLIC_STATUS="TRUE - ACL Write" | ||
| 106 | fi | ||
| 107 | fi | ||
| 108 | else | ||
| 109 | ACL_ALL_USERS_READ="ACL Check Failed" | ||
| 110 | ACL_ALL_USERS_WRITE="ACL Check Failed" | ||
| 111 | fi | ||
| 112 | |||
| 113 | # Final check for PAB failure (PAB is the highest authority) | ||
| 114 | if [ "$PAB_FULLY_RESTRICTED" = "CRITICAL-MISSING" ]; then | ||
| 115 | OVERALL_PUBLIC_STATUS="TRUE - PAB Missing (CRITICAL)" | ||
| 116 | elif [ "$OVERALL_PUBLIC_STATUS" != "FALSE" ] && [ "$PAB_FULLY_RESTRICTED" != "TRUE" ]; then | ||
| 117 | # If the bucket is found public by Policy or ACL AND PAB isn't fully set, confirm it's public | ||
| 118 | : # Status already set by Policy or ACL check above | ||
| 119 | fi | ||
| 120 | |||
| 121 | |||
| 122 | # --- Save the output as CSV --- | ||
| 123 | echo "$BUCKET_NAME,$BUCKET_REGION,$PAB_FULLY_RESTRICTED,$POLICY_IS_PUBLIC,$ACL_ALL_USERS_READ,$ACL_ALL_USERS_WRITE,\"$OVERALL_PUBLIC_STATUS\"" >> "$REPORT_FILE" | ||
| 124 | echo " Final Status: $OVERALL_PUBLIC_STATUS" | ||
| 125 | |||
| 126 | done | ||
| 127 | |||
| 128 | echo "---" | ||
| 129 | echo "✅ Audit Complete." | ||
| 130 | echo "Final report saved to **$REPORT_FILE**" | ||
| 131 | cat "$REPORT_FILE"\ No newline at end of file | ||