1+ """
2+ AWS Account Data Management: Get Account Data with Caching
3+
4+ This Lambda function retrieves comprehensive account information including metadata,
5+ tags, organizational structure, and team assignments. Uses DynamoDB caching to
6+ improve performance and reduce API calls to AWS Organizations.
7+
8+ Account Data Includes:
9+ - Basic account information (ID, name, email, join date)
10+ - Organizational unit placement and hierarchy
11+ - Tag-based metadata (team, environment, client, project)
12+ - Contact information and team email assignments
13+ - Ticketing system integration details (Jira/ServiceNow)
14+ - Account age and classification (new vs established)
15+
16+ Caching Strategy:
17+ - Check DynamoDB cache first for existing account data
18+ - Fetch fresh data from AWS Organizations if cache miss
19+ - Store fresh data in cache for future requests
20+ - Cache improves performance and reduces Organizations API throttling
21+
22+ Target Resources: AWS Organizations accounts and DynamoDB cache
23+ Purpose: Centralized account metadata retrieval with performance optimization
24+ """
25+
126import os
227import datetime as dt
328import json
429import boto3
530from botocore .config import Config
631from dateutil import parser
732
8- # Get environment variables
33+ # SOAR Configuration
934PRODUCT_NAME = os .environ ['PRODUCT_NAME' ]
35+
36+ # Team Contact Configuration
1037ACCOUNT_TEAM_EMAIL_TAG = os .environ ['ACCOUNT_TEAM_EMAIL_TAG' ] # soar:team:email
1138ACCOUNT_TEAM_EMAIL_TAG_APP = os .environ ['ACCOUNT_TEAM_EMAIL_TAG_APP' ] # soar:team:email:app
1239DEFAULT_TEAM_EMAIL = os .environ ['DEFAULT_TEAM_EMAIL' ]
40+
41+ # Account Classification Tags
1342ENVIRONMENT_TAG = os .environ ['ENVIRONMENT_TAG' ] # soar:environment
1443CLIENT_TAG = os .environ ['CLIENT_TAG' ] # soar:client
1544PROJECT_TAG = os .environ ['PROJECT_TAG' ] # soar:project
1645TEAM_TAG = os .environ ['TEAM_TAG' ] # soar:team
1746
18- TICKETING_SYSTEM = os .environ ['TICKETING_SYSTEM' ] #
47+ # Ticketing System Integration
48+ TICKETING_SYSTEM = os .environ ['TICKETING_SYSTEM' ] # JIRA or ServiceNow
1949
50+ # Jira Integration Configuration
2051JIRA_PROJECT_KEY_TAG = os .environ ['JIRA_PROJECT_KEY_TAG' ] # soar:jira:project-key
2152JIRA_PROJECT_KEY_TAG_APP = os .environ ['JIRA_PROJECT_KEY_TAG_APP' ] # soar:jira:project-key:app
22- JIRA_DEFAULT_PROJECT_KEY = os .environ ['JIRA_DEFAULT_PROJECT_KEY' ] # XXX
53+ JIRA_DEFAULT_PROJECT_KEY = os .environ ['JIRA_DEFAULT_PROJECT_KEY' ] # Default project key
2354
55+ # ServiceNow Integration Configuration
2456SERVICE_NOW_PROJECT_QUEUE_TAG = os .environ ['SERVICE_NOW_PROJECT_QUEUE_TAG' ] # soar:service-now:project-queue
2557SERVICE_NOW_PROJECT_QUEUE_TAG_APP = os .environ ['SERVICE_NOW_PROJECT_QUEUE_TAG_APP' ] # soar:service-now:project-queue:app
26- SERVICE_NOW_DEFAULT_PROJECT_QUEUE = os .environ ['SERVICE_NOW_DEFAULT_PROJECT_QUEUE' ] # XXX
58+ SERVICE_NOW_DEFAULT_PROJECT_QUEUE = os .environ ['SERVICE_NOW_DEFAULT_PROJECT_QUEUE' ] # Default queue
2759
60+ # Cache Configuration
2861CACHED_ACCOUNT_DATA_TABLE_NAME = os .environ ['CACHED_ACCOUNT_DATA_TABLE_NAME' ]
29-
3062MIN_AGE_HOURS = int (os .environ ['MIN_AGE_HOURS' ])
3163
32-
33- # Configure Boto3
64+ # Configure Boto3 with minimal retries - let Step Functions handle retry logic
3465config = Config (
3566 retries = {
3667 'total_max_attempts' : 1 # Let Step Functions handle the retries
3768 }
3869)
3970
40- # Create Boto3 clients
71+ # AWS Service Clients
4172client = boto3 .client ('organizations' , config = config )
4273dynamodb = boto3 .client ('dynamodb' )
4374
44- # Lambda handler function
75+
4576def lambda_handler (account_id , _context ):
46- # Check if account data is cached
77+ """
78+ Main Lambda handler for retrieving account data with caching.
79+
80+ Args:
81+ account_id: AWS account ID to retrieve data for
82+ _context: Lambda context (unused)
83+
84+ Returns:
85+ dict: Comprehensive account data including metadata, contacts, and classification
86+
87+ Process:
88+ 1. Check DynamoDB cache for existing account data
89+ 2. If cache hit, return cached data immediately
90+ 3. If cache miss, fetch fresh data from AWS Organizations
91+ 4. Store fresh data in cache and return to caller
92+ """
93+ # STEP 1: Check cache first for performance optimization
4794 cached_account_data = get_cached_account_data (account_id )
4895 if cached_account_data :
4996 print (f"Account { account_id } : Using cache" )
5097 return cached_account_data
5198
52- # Fetch fresh account data
99+ # STEP 2: Cache miss - fetch fresh data and update cache
53100 account_data = get_fresh_account_data (account_id )
54101 put_cached_account_data (account_id , account_data )
55102 return account_data
56103
57- # Get cached account data from DynamoDB
104+
58105def get_cached_account_data (account_id ):
106+ """
107+ Retrieve account data from DynamoDB cache.
108+
109+ Args:
110+ account_id: AWS account ID to look up
111+
112+ Returns:
113+ dict: Cached account data if found and valid, False otherwise
114+
115+ Error Handling:
116+ Returns False for any cache misses, corruption, or JSON parsing errors.
117+ This ensures graceful fallback to fresh data fetching.
118+ """
59119 response = dynamodb .get_item (
60120 TableName = CACHED_ACCOUNT_DATA_TABLE_NAME ,
61121 Key = {
@@ -76,8 +136,18 @@ def get_cached_account_data(account_id):
76136
77137 return data
78138
79- # Put account data into DynamoDB cache
80139def put_cached_account_data (account_id , account_data ):
140+ """
141+ Store account data in DynamoDB cache for future requests.
142+
143+ Args:
144+ account_id: AWS account ID as cache key
145+ account_data: Complete account data dictionary to cache
146+
147+ Cache Format:
148+ Stores JSON-serialized account data with account ID as primary key.
149+ This enables fast lookup and reduces Organizations API calls.
150+ """
81151 response = dynamodb .put_item (
82152 TableName = CACHED_ACCOUNT_DATA_TABLE_NAME ,
83153 Item = {
@@ -87,8 +157,29 @@ def put_cached_account_data(account_id, account_data):
87157 )
88158 print (response )
89159
90- # Fetch fresh account data
160+
91161def get_fresh_account_data (account_id ):
162+ """
163+ Fetch comprehensive account data from AWS Organizations and compile metadata.
164+
165+ Args:
166+ account_id: AWS account ID to retrieve information for
167+
168+ Returns:
169+ dict: Complete account data including:
170+ - Basic account info (ID, name, email, join date)
171+ - Organizational structure (OU placement)
172+ - Tag-based metadata (team, environment, client, project)
173+ - Contact information (team emails)
174+ - Ticketing integration (Jira/ServiceNow project mappings)
175+ - Account classification (new vs established)
176+ - Tallies for reporting and aggregation
177+
178+ Data Sources:
179+ - AWS Organizations: Account details, tags, OU structure
180+ - Environment variables: Default values and tag mappings
181+ - Calculated fields: Account age, team assignments, project mappings
182+ """
92183 print (f"Account { account_id } : Fetching fresh data" )
93184
94185 # Get account details
0 commit comments