Commit 10729070f7
Unsigned
Layout: unified · split
applications/aws/README.md +37
| @@ -204,4 +204,41 @@ Rule#,Policy‑Item,Expected,Actual,Result | ||
| 204 | 204 | 8,Maximum password age (days),90,90,PASS |
| 205 | 205 | 9,Prevent password reuse (last N),4,4,PASS |
| 206 | 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 | 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 | ||