audit-labs/audit-tools

A collection of scripts, queries, and other goodies you can use in an audit.

clone: git clone https://gitbay.org/audit-labs/audit-tools.git

73917d9d1b203416050e4237ea6bfe007dc442f7

unsigned

author: Christian Cleberg <hello@cleberg.net> · 2025-12-11T18:15:37Z

add aws script
 applications/aws/README.md            |  94 +++++++++++++++++++++++++
 applications/aws/get_account_users.sh | 125 ++++++++++++++++++++++++++++++++++
 2 files changed, 219 insertions(+)

diff --git a/applications/aws/README.md b/applications/aws/README.md
new file mode 100644
index 0000000..b42171b
--- /dev/null
+++ b/applications/aws/README.md
@@ -0,0 +1,94 @@
+# `get_account_users.sh`
+
+*Note*: This example uses an account titled `cmc`, which has access provisioned to it through IAM.
+
+``` bash
+./get_account_users.sh
+```
+
+``` text
+Fetching IAM Identity Center and Account details...
+Successfully found Account 'cmc' with ID: 214941490075
+---
+Step 2: Finding all permission sets provisioned to 'cmc'...
+Found provisioned permission sets. Now checking assignments for each...
+---
+  -> Fetching policies for Permission Set: arn:aws:sso:::permissionSet/ssoins-68041bff81588aa3/ps-6ea9be6a2332b891
+  -> Found Assignment: testgroup1 (GROUP) -> AdministratorAccess
+  -> Found Assignment: iamtestuser1 (USER) -> AdministratorAccess
+  -> Found Assignment: testgroup2 (GROUP) -> AdministratorAccess
+  -> Fetching policies for Permission Set: arn:aws:sso:::permissionSet/ssoins-68041bff81588aa3/ps-590510f2a285016d
+  -> Found Assignment: iamtestuser1 (USER) -> Billing
+---
+Success! Report saved to 'report_cmc.json'
+The file contains all user/group assignments and their policies for account 'cmc'.
+```
+
+``` bash
+cat report_cmc.json
+```
+
+```json
+[
+  {
+    "principal": {
+      "type": "GROUP",
+      "name": "testgroup1"
+    },
+    "permission_set": {
+      "name": "AdministratorAccess",
+      "policies": {
+        "managed_policies": [
+          "arn:aws:iam::aws:policy/AdministratorAccess"
+        ],
+        "inline_policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"Statement2\",\"Effect\":\"Deny\",\"Action\":[\"a4b:*\"],\"Resource\":[\"*\"]}]}"
+      }
+    }
+  },
+  {
+    "principal": {
+      "type": "USER",
+      "name": "iamtestuser1"
+    },
+    "permission_set": {
+      "name": "AdministratorAccess",
+      "policies": {
+        "managed_policies": [
+          "arn:aws:iam::aws:policy/AdministratorAccess"
+        ],
+        "inline_policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"Statement2\",\"Effect\":\"Deny\",\"Action\":[\"a4b:*\"],\"Resource\":[\"*\"]}]}"
+      }
+    }
+  },
+  {
+    "principal": {
+      "type": "GROUP",
+      "name": "testgroup2"
+    },
+    "permission_set": {
+      "name": "AdministratorAccess",
+      "policies": {
+        "managed_policies": [
+          "arn:aws:iam::aws:policy/AdministratorAccess"
+        ],
+        "inline_policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"Statement2\",\"Effect\":\"Deny\",\"Action\":[\"a4b:*\"],\"Resource\":[\"*\"]}]}"
+      }
+    }
+  },
+  {
+    "principal": {
+      "type": "USER",
+      "name": "iamtestuser1"
+    },
+    "permission_set": {
+      "name": "Billing",
+      "policies": {
+        "managed_policies": [
+          "arn:aws:iam::aws:policy/job-function/Billing"
+        ],
+        "inline_policy": ""
+      }
+    }
+  }
+]
+```
diff --git a/applications/aws/get_account_users.sh b/applications/aws/get_account_users.sh
new file mode 100644
index 0000000..4dfe40a
--- /dev/null
+++ b/applications/aws/get_account_users.sh
@@ -0,0 +1,125 @@
+#!/bin/bash
+
+# This script analyzes all IAM Identity Center assignments for a specific
+# AWS account and outputs the details to a single JSON file.
+# Corrected Logic: First finds provisioned permission sets, then gets assignments for each.
+
+# --- Configuration ---
+ACCOUNT_NAME=""
+
+# --- Prerequisite check ---
+if ! command -v aws &> /dev/null || ! command -v jq &> /dev/null; then
+    echo "Error: Both AWS CLI and jq are required. Please install them and ensure they are in your PATH."
+    exit 1
+fi
+
+# --- Step 1: Get Instance details and find the target Account ID ---
+echo "Fetching IAM Identity Center and Account details..."
+
+INSTANCE_ARN=$(aws sso-admin list-instances --query "Instances[0].InstanceArn" --output text)
+IDENTITY_STORE_ID=$(aws sso-admin list-instances --query "Instances[0].IdentityStoreId" --output text)
+
+if [ -z "$INSTANCE_ARN" ] || [ -z "$IDENTITY_STORE_ID" ]; then
+    echo "Error: Could not find IAM Identity Center instance ARN or Identity Store ID."
+    exit 1
+fi
+
+ACCOUNT_ID=$(aws organizations list-accounts --query "Accounts[?Name=='$ACCOUNT_NAME' && Status=='ACTIVE'].Id" --output text)
+
+if [ -z "$ACCOUNT_ID" ]; then
+    echo "Error: Could not find an active AWS account with the name '$ACCOUNT_NAME'."
+    exit 1
+fi
+
+echo "Successfully found Account '$ACCOUNT_NAME' with ID: $ACCOUNT_ID"
+echo "---"
+
+# --- Step 2: Get all Permission Sets provisioned to the account ---
+echo "Step 2: Finding all permission sets provisioned to '$ACCOUNT_NAME'..."
+PROVISIONED_SETS_ARN=$(aws sso-admin list-permission-sets-provisioned-to-account \
+    --instance-arn "$INSTANCE_ARN" \
+    --account-id "$ACCOUNT_ID" \
+    --query "PermissionSets[]" --output text)
+
+if [ -z "$PROVISIONED_SETS_ARN" ]; then
+    echo "No permission sets are provisioned for account '$ACCOUNT_NAME'."
+    exit 0
+fi
+
+echo "Found provisioned permission sets. Now checking assignments for each..."
+echo "---"
+
+# --- Caches to store fetched data ---
+declare -A PERMISSION_SET_CACHE
+declare -A PRINCIPAL_NAME_CACHE
+FINAL_JSON_ARRAY="[]" # Initialize an empty JSON array
+
+# --- Step 3: Loop through each provisioned permission set and get its assignments ---
+for PS_ARN in $PROVISIONED_SETS_ARN; do
+    
+    # Get assignments for this specific permission set in this account
+    ACCOUNT_ASSIGNMENTS=$(aws sso-admin list-account-assignments \
+        --instance-arn "$INSTANCE_ARN" \
+        --account-id "$ACCOUNT_ID" \
+        --permission-set-arn "$PS_ARN" \
+        --query "AccountAssignments[]" --output json)
+
+    if [ "$(echo "$ACCOUNT_ASSIGNMENTS" | jq 'length')" -eq 0 ]; then
+        echo "  -> Permission Set ARN $PS_ARN is provisioned but has no active assignments."
+        continue
+    fi
+
+    # Since there are assignments, let's get the permission set's details (policies, name)
+    # Using a cache to avoid redundant calls if a PS is somehow listed twice
+    if [ -z "${PERMISSION_SET_CACHE[$PS_ARN]}" ]; then
+        echo "  -> Fetching policies for Permission Set: $PS_ARN"
+        PS_NAME=$(aws sso-admin describe-permission-set --instance-arn "$INSTANCE_ARN" --permission-set-arn "$PS_ARN" --query "PermissionSet.Name" --output text)
+        MANAGED_POLICIES=$(aws sso-admin list-managed-policies-in-permission-set --instance-arn "$INSTANCE_ARN" --permission-set-arn "$PS_ARN" --query "AttachedManagedPolicies[].Arn" --output json)
+        INLINE_POLICY=$(aws sso-admin get-inline-policy-for-permission-set --instance-arn "$INSTANCE_ARN" --permission-set-arn "$PS_ARN" --query "InlinePolicy" --output json)
+        
+        PERMISSION_SET_CACHE[$PS_ARN]=$(jq -n \
+            --arg name "$PS_NAME" \
+            --argjson managed "$MANAGED_POLICIES" \
+            --argjson inline "$INLINE_POLICY" \
+            '{name: $name, policies: {managed_policies: $managed, inline_policy: $inline}}')
+    fi
+    CACHED_PS_DETAILS=${PERMISSION_SET_CACHE[$PS_ARN]}
+
+    # Now process each assignment found for this permission set
+    for row in $(echo "${ACCOUNT_ASSIGNMENTS}" | jq -r '.[] | @base64'); do
+        _jq() { echo ${row} | base64 --decode | jq -r ${1}; }
+        PRINCIPAL_TYPE=$(_jq '.PrincipalType')
+        PRINCIPAL_ID=$(_jq '.PrincipalId')
+
+        # Get Principal (User/Group) Name, using a cache
+        if [ -z "${PRINCIPAL_NAME_CACHE[$PRINCIPAL_ID]}" ]; then
+            PRINCIPAL_NAME=""
+            if [ "$PRINCIPAL_TYPE" == "USER" ]; then
+                PRINCIPAL_NAME=$(aws identitystore describe-user --identity-store-id "$IDENTITY_STORE_ID" --user-id "$PRINCIPAL_ID" --query "UserName" --output text 2>/dev/null)
+            elif [ "$PRINCIPAL_TYPE" == "GROUP" ]; then
+                PRINCIPAL_NAME=$(aws identitystore describe-group --identity-store-id "$IDENTITY_STORE_ID" --group-id "$PRINCIPAL_ID" --query "DisplayName" --output text 2>/dev/null)
+            fi
+            PRINCIPAL_NAME_CACHE[$PRINCIPAL_ID]=${PRINCIPAL_NAME:-"ID: $PRINCIPAL_ID"}
+        fi
+        CACHED_PRINCIPAL_NAME=${PRINCIPAL_NAME_CACHE[$PRINCIPAL_ID]}
+        
+        echo "  -> Found Assignment: ${CACHED_PRINCIPAL_NAME} ($PRINCIPAL_TYPE) -> $(echo "$CACHED_PS_DETAILS" | jq -r .name)"
+
+        # Build the final JSON object for this assignment
+        ASSIGNMENT_OUTPUT=$(jq -n \
+            --arg principal_type "$PRINCIPAL_TYPE" \
+            --arg principal_name "$CACHED_PRINCIPAL_NAME" \
+            --argjson ps_details "$CACHED_PS_DETAILS" \
+            '{principal: {type: $principal_type, name: $principal_name}, permission_set: $ps_details}')
+
+        FINAL_JSON_ARRAY=$(echo "$FINAL_JSON_ARRAY" | jq --argjson new_entry "$ASSIGNMENT_OUTPUT" '. += [$new_entry]')
+    done
+done
+
+# --- Step 4: Save the final report ---
+OUTPUT_FILENAME="report_${ACCOUNT_NAME}.json"
+echo "$FINAL_JSON_ARRAY" | jq '.' > "$OUTPUT_FILENAME"
+
+echo "---"
+echo "Success! Report saved to '$OUTPUT_FILENAME'"
+echo "The file contains all user/group assignments and their policies for account '$ACCOUNT_NAME'."