Query bulk user roles #1070
-
Hello community. I'm developing a health-check script that would get all user's granted role and check how many users are falcon admin and how many are RTR admin. I use the user_management.get_user_grants to query the user granted roles. [https://falconpy.io/Service-Collections/User-Management.html#combineduserrolesv1] The problem here I'm facing is that this method could only retrieve roles for 1 user at a time. Each API call would run for around 5 seconds which means it would become very long if I was to query 50+ users. Is there a way I can bulk query all users using 1 API call instead of N-user times? |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 5 replies
-
Hi @dkang-firmus - I've confirmed this API operation only accepts one UUID per request. Adding support for multiple IDs is an excellent idea submission. In the interim, I've put together a sample for you that leverages A few notes:
Let us know if there are any questions! 😄 r"""Threaded user grant lookup example.
______ __ _______ __ __ __
| |.----.-----.--.--.--.--| | __| |_.----.|__| |--.-----.
| ---|| _| _ | | | | _ |__ | _| _|| | <| -__|
|______||__| |_____|________|_____|_______|____|__| |__|__|__|_____|
___ ___ ___ ___ __
| Y .-----.-----.----.| Y .---.-.-----.---.-.-----.-----.--------.-----.-----| |_
|. | |__ --| -__| _||. | _ | | _ | _ | -__| | -__| | _|
|. | |_____|_____|__| |. \_/ |___._|__|__|___._|___ |_____|__|__|__|_____|__|__|____|
|: 1 | |: | | |_____|
|::.. . | |::.|:. | FalconPy v1.3.3
`-------' `--- ---'
Asynchronously retrieve all user grants for every user defined within the tenant and output
the results to a comma-delimited text file. When not specified, this file is named user_grants.csv.
Creation date: 11.13.2023 - jshcodes@CrowdStrike
"""
import os
import csv
import logging
from argparse import ArgumentParser, RawTextHelpFormatter
from concurrent.futures import ThreadPoolExecutor
from datetime import datetime
try:
from falconpy import UserManagement
except ImportError as no_falconpy:
raise ImportError("The CrowdStrike FalconPy library must be installed.") from no_falconpy
def consume_arguments():
"""Retrieve any provided command line arguments."""
parser = ArgumentParser(description=__doc__, formatter_class=RawTextHelpFormatter)
parser.add_argument("-d", "--debug", help="Enable debug.", default=False, action="store_true")
parser.add_argument("-o", "--output", help="CSV output filename.", default="user_grants.csv")
auth = parser.add_argument_group("Authentication arguments "
"(not required if using environment authentication)")
auth.add_argument("-k", "--client_id",
help="Falcon API client ID",
default=os.getenv("FALCON_CLIENT_ID")
)
auth.add_argument("-s", "--client_secret",
help="Falcon API client secret",
default=os.getenv("FALCON_CLIENT_SECRET")
)
return parser.parse_args(), parser
def get_grants(interface: UserManagement, uuid: str):
"""Retrieve all grants for the user UUID in question."""
print(f" Retrieving grant detail for {uuid}", end="\r")
return interface.get_user_grants(uuid).data
def get_grant_data(sdk: UserManagement):
"""Retrieve all user UUIDs within the tenant and then retrieve the grants for each."""
running = True
user_ids = []
user_grants = []
offset = None
while running:
user_lookup = sdk.query_users(limit=500, offset=offset)
user_ids.extend(user_lookup.data)
total = user_lookup.total
offset = len(user_ids)
with ThreadPoolExecutor() as executor:
futures = {
executor.submit(get_grants, sdk, user_id) for user_id in user_lookup.data
}
for fut in futures:
user_grants.extend(fut.result())
if len(user_ids) >= total:
running = False
return user_ids, user_grants
def write_grant_results(user_grants: list, output_file: str):
"""Write grant details to the specified CSV file."""
with open(output_file, "w", newline="", encoding="utf-8") as csv_file:
writer = csv.writer(csv_file)
writer.writerow(user_grants[0].keys()) # Header row
for grants in user_grants:
# Data rows
writer.writerow(grants.values())
if __name__ == "__main__":
begin = datetime.now().timestamp()
parsed, handler = consume_arguments()
if not parsed.client_id or not parsed.client_secret:
handler.print_help()
raise SystemExit(
"\nYou must provide API credentials via the environment variables\n"
"FALCON_CLIENT_ID and FALCON_CLIENT_SECRET or you must provide\n"
"them using the '-k' and '-s' command line arguments."
)
if parsed.debug:
logging.basicConfig(level=logging.DEBUG)
users = UserManagement(client_id=parsed.client_id,
client_secret=parsed.client_secret,
debug=parsed.debug,
pythonic=True
)
id_list, grant_list = get_grant_data(users)
write_grant_results(grant_list, parsed.output)
print(" " * 80) # Clear the last status update line
print(f"{len(id_list):,} total users identified.")
print(f"{len(grant_list):,} total grants retrieved.")
print(f"Results saved to {parsed.output}.")
print(f"Total processing time: {datetime.now().timestamp() - begin:.2f} seconds.") |
Beta Was this translation helpful? Give feedback.
Hi @dkang-firmus -
This solution was expanded to speak to MSSP scenarios and is now available as a sample! 🎉