runbooks 0.2.5__py3-none-any.whl → 0.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- conftest.py +26 -0
- jupyter-agent/.env +2 -0
- jupyter-agent/.env.template +2 -0
- jupyter-agent/.gitattributes +35 -0
- jupyter-agent/.gradio/certificate.pem +31 -0
- jupyter-agent/README.md +16 -0
- jupyter-agent/__main__.log +8 -0
- jupyter-agent/app.py +256 -0
- jupyter-agent/cloudops-agent.png +0 -0
- jupyter-agent/ds-system-prompt.txt +154 -0
- jupyter-agent/jupyter-agent.png +0 -0
- jupyter-agent/llama3_template.jinja +123 -0
- jupyter-agent/requirements.txt +9 -0
- jupyter-agent/tmp/4ojbs8a02ir/jupyter-agent.ipynb +68 -0
- jupyter-agent/tmp/cm5iasgpm3p/jupyter-agent.ipynb +91 -0
- jupyter-agent/tmp/crqbsseag5/jupyter-agent.ipynb +91 -0
- jupyter-agent/tmp/hohanq1u097/jupyter-agent.ipynb +57 -0
- jupyter-agent/tmp/jns1sam29wm/jupyter-agent.ipynb +53 -0
- jupyter-agent/tmp/jupyter-agent.ipynb +27 -0
- jupyter-agent/utils.py +409 -0
- runbooks/__init__.py +71 -3
- runbooks/__main__.py +13 -0
- runbooks/aws/ec2_describe_instances.py +1 -1
- runbooks/aws/ec2_run_instances.py +8 -2
- runbooks/aws/ec2_start_stop_instances.py +17 -4
- runbooks/aws/ec2_unused_volumes.py +5 -1
- runbooks/aws/s3_create_bucket.py +4 -2
- runbooks/aws/s3_list_objects.py +6 -1
- runbooks/aws/tagging_lambda_handler.py +13 -2
- runbooks/aws/tags.json +12 -0
- runbooks/base.py +353 -0
- runbooks/cfat/README.md +49 -0
- runbooks/cfat/__init__.py +74 -0
- runbooks/cfat/app.ts +644 -0
- runbooks/cfat/assessment/__init__.py +40 -0
- runbooks/cfat/assessment/asana-import.csv +39 -0
- runbooks/cfat/assessment/cfat-checks.csv +31 -0
- runbooks/cfat/assessment/cfat.txt +520 -0
- runbooks/cfat/assessment/collectors.py +200 -0
- runbooks/cfat/assessment/jira-import.csv +39 -0
- runbooks/cfat/assessment/runner.py +387 -0
- runbooks/cfat/assessment/validators.py +290 -0
- runbooks/cfat/cli.py +103 -0
- runbooks/cfat/docs/asana-import.csv +24 -0
- runbooks/cfat/docs/cfat-checks.csv +31 -0
- runbooks/cfat/docs/cfat.txt +335 -0
- runbooks/cfat/docs/checks-output.png +0 -0
- runbooks/cfat/docs/cloudshell-console-run.png +0 -0
- runbooks/cfat/docs/cloudshell-download.png +0 -0
- runbooks/cfat/docs/cloudshell-output.png +0 -0
- runbooks/cfat/docs/downloadfile.png +0 -0
- runbooks/cfat/docs/jira-import.csv +24 -0
- runbooks/cfat/docs/open-cloudshell.png +0 -0
- runbooks/cfat/docs/report-header.png +0 -0
- runbooks/cfat/models.py +1026 -0
- runbooks/cfat/package-lock.json +5116 -0
- runbooks/cfat/package.json +38 -0
- runbooks/cfat/report.py +496 -0
- runbooks/cfat/reporting/__init__.py +46 -0
- runbooks/cfat/reporting/exporters.py +337 -0
- runbooks/cfat/reporting/formatters.py +496 -0
- runbooks/cfat/reporting/templates.py +135 -0
- runbooks/cfat/run-assessment.sh +23 -0
- runbooks/cfat/runner.py +69 -0
- runbooks/cfat/src/actions/check-cloudtrail-existence.ts +43 -0
- runbooks/cfat/src/actions/check-config-existence.ts +37 -0
- runbooks/cfat/src/actions/check-control-tower.ts +37 -0
- runbooks/cfat/src/actions/check-ec2-existence.ts +46 -0
- runbooks/cfat/src/actions/check-iam-users.ts +50 -0
- runbooks/cfat/src/actions/check-legacy-cur.ts +30 -0
- runbooks/cfat/src/actions/check-org-cloudformation.ts +30 -0
- runbooks/cfat/src/actions/check-vpc-existence.ts +43 -0
- runbooks/cfat/src/actions/create-asanaimport.ts +14 -0
- runbooks/cfat/src/actions/create-backlog.ts +372 -0
- runbooks/cfat/src/actions/create-jiraimport.ts +15 -0
- runbooks/cfat/src/actions/create-report.ts +616 -0
- runbooks/cfat/src/actions/define-account-type.ts +51 -0
- runbooks/cfat/src/actions/get-enabled-org-policy-types.ts +40 -0
- runbooks/cfat/src/actions/get-enabled-org-services.ts +26 -0
- runbooks/cfat/src/actions/get-idc-info.ts +34 -0
- runbooks/cfat/src/actions/get-org-da-accounts.ts +34 -0
- runbooks/cfat/src/actions/get-org-details.ts +35 -0
- runbooks/cfat/src/actions/get-org-member-accounts.ts +44 -0
- runbooks/cfat/src/actions/get-org-ous.ts +35 -0
- runbooks/cfat/src/actions/get-regions.ts +22 -0
- runbooks/cfat/src/actions/zip-assessment.ts +27 -0
- runbooks/cfat/src/types/index.d.ts +147 -0
- runbooks/cfat/tests/__init__.py +141 -0
- runbooks/cfat/tests/test_cli.py +340 -0
- runbooks/cfat/tests/test_integration.py +290 -0
- runbooks/cfat/tests/test_models.py +505 -0
- runbooks/cfat/tests/test_reporting.py +354 -0
- runbooks/cfat/tsconfig.json +16 -0
- runbooks/cfat/webpack.config.cjs +27 -0
- runbooks/config.py +260 -0
- runbooks/finops/README.md +337 -0
- runbooks/finops/__init__.py +86 -0
- runbooks/finops/aws_client.py +245 -0
- runbooks/finops/cli.py +151 -0
- runbooks/finops/cost_processor.py +410 -0
- runbooks/finops/dashboard_runner.py +448 -0
- runbooks/finops/helpers.py +355 -0
- runbooks/finops/main.py +14 -0
- runbooks/finops/profile_processor.py +174 -0
- runbooks/finops/types.py +66 -0
- runbooks/finops/visualisations.py +80 -0
- runbooks/inventory/.gitignore +354 -0
- runbooks/inventory/ArgumentsClass.py +261 -0
- runbooks/inventory/FAILED_SCRIPTS_TROUBLESHOOTING.md +619 -0
- runbooks/inventory/Inventory_Modules.py +6130 -0
- runbooks/inventory/LandingZone/delete_lz.py +1075 -0
- runbooks/inventory/PASSED_SCRIPTS_GUIDE.md +738 -0
- runbooks/inventory/README.md +1320 -0
- runbooks/inventory/__init__.py +62 -0
- runbooks/inventory/account_class.py +532 -0
- runbooks/inventory/all_my_instances_wrapper.py +123 -0
- runbooks/inventory/aws_decorators.py +201 -0
- runbooks/inventory/aws_organization.png +0 -0
- runbooks/inventory/cfn_move_stack_instances.py +1526 -0
- runbooks/inventory/check_cloudtrail_compliance.py +614 -0
- runbooks/inventory/check_controltower_readiness.py +1107 -0
- runbooks/inventory/check_landingzone_readiness.py +711 -0
- runbooks/inventory/cloudtrail.md +727 -0
- runbooks/inventory/collectors/__init__.py +20 -0
- runbooks/inventory/collectors/aws_compute.py +518 -0
- runbooks/inventory/collectors/aws_networking.py +275 -0
- runbooks/inventory/collectors/base.py +222 -0
- runbooks/inventory/core/__init__.py +19 -0
- runbooks/inventory/core/collector.py +303 -0
- runbooks/inventory/core/formatter.py +296 -0
- runbooks/inventory/delete_s3_buckets_objects.py +169 -0
- runbooks/inventory/discovery.md +81 -0
- runbooks/inventory/draw_org_structure.py +748 -0
- runbooks/inventory/ec2_vpc_utils.py +341 -0
- runbooks/inventory/find_cfn_drift_detection.py +272 -0
- runbooks/inventory/find_cfn_orphaned_stacks.py +719 -0
- runbooks/inventory/find_cfn_stackset_drift.py +733 -0
- runbooks/inventory/find_ec2_security_groups.py +669 -0
- runbooks/inventory/find_landingzone_versions.py +201 -0
- runbooks/inventory/find_vpc_flow_logs.py +1221 -0
- runbooks/inventory/inventory.sh +659 -0
- runbooks/inventory/list_cfn_stacks.py +558 -0
- runbooks/inventory/list_cfn_stackset_operation_results.py +252 -0
- runbooks/inventory/list_cfn_stackset_operations.py +734 -0
- runbooks/inventory/list_cfn_stacksets.py +453 -0
- runbooks/inventory/list_config_recorders_delivery_channels.py +681 -0
- runbooks/inventory/list_ds_directories.py +354 -0
- runbooks/inventory/list_ec2_availability_zones.py +286 -0
- runbooks/inventory/list_ec2_ebs_volumes.py +244 -0
- runbooks/inventory/list_ec2_instances.py +425 -0
- runbooks/inventory/list_ecs_clusters_and_tasks.py +562 -0
- runbooks/inventory/list_elbs_load_balancers.py +411 -0
- runbooks/inventory/list_enis_network_interfaces.py +526 -0
- runbooks/inventory/list_guardduty_detectors.py +568 -0
- runbooks/inventory/list_iam_policies.py +404 -0
- runbooks/inventory/list_iam_roles.py +518 -0
- runbooks/inventory/list_iam_saml_providers.py +359 -0
- runbooks/inventory/list_lambda_functions.py +882 -0
- runbooks/inventory/list_org_accounts.py +446 -0
- runbooks/inventory/list_org_accounts_users.py +354 -0
- runbooks/inventory/list_rds_db_instances.py +406 -0
- runbooks/inventory/list_route53_hosted_zones.py +318 -0
- runbooks/inventory/list_servicecatalog_provisioned_products.py +575 -0
- runbooks/inventory/list_sns_topics.py +360 -0
- runbooks/inventory/list_ssm_parameters.py +402 -0
- runbooks/inventory/list_vpc_subnets.py +433 -0
- runbooks/inventory/list_vpcs.py +422 -0
- runbooks/inventory/lockdown_cfn_stackset_role.py +224 -0
- runbooks/inventory/models/__init__.py +24 -0
- runbooks/inventory/models/account.py +192 -0
- runbooks/inventory/models/inventory.py +309 -0
- runbooks/inventory/models/resource.py +247 -0
- runbooks/inventory/recover_cfn_stack_ids.py +205 -0
- runbooks/inventory/requirements.txt +12 -0
- runbooks/inventory/run_on_multi_accounts.py +211 -0
- runbooks/inventory/tests/common_test_data.py +3661 -0
- runbooks/inventory/tests/common_test_functions.py +204 -0
- runbooks/inventory/tests/setup.py +24 -0
- runbooks/inventory/tests/src.py +18 -0
- runbooks/inventory/tests/test_cfn_describe_stacks.py +208 -0
- runbooks/inventory/tests/test_ec2_describe_instances.py +162 -0
- runbooks/inventory/tests/test_inventory_modules.py +55 -0
- runbooks/inventory/tests/test_lambda_list_functions.py +86 -0
- runbooks/inventory/tests/test_moto_integration_example.py +273 -0
- runbooks/inventory/tests/test_org_list_accounts.py +49 -0
- runbooks/inventory/update_aws_actions.py +173 -0
- runbooks/inventory/update_cfn_stacksets.py +1215 -0
- runbooks/inventory/update_cloudwatch_logs_retention_policy.py +294 -0
- runbooks/inventory/update_iam_roles_cross_accounts.py +478 -0
- runbooks/inventory/update_s3_public_access_block.py +539 -0
- runbooks/inventory/utils/__init__.py +23 -0
- runbooks/inventory/utils/aws_helpers.py +510 -0
- runbooks/inventory/utils/threading_utils.py +493 -0
- runbooks/inventory/utils/validation.py +682 -0
- runbooks/inventory/verify_ec2_security_groups.py +1430 -0
- runbooks/main.py +1004 -0
- runbooks/organizations/__init__.py +12 -0
- runbooks/organizations/manager.py +374 -0
- runbooks/security/README.md +447 -0
- runbooks/security/__init__.py +71 -0
- runbooks/{security_baseline → security}/checklist/alternate_contacts.py +8 -1
- runbooks/{security_baseline → security}/checklist/bucket_public_access.py +4 -1
- runbooks/{security_baseline → security}/checklist/cloudwatch_alarm_configuration.py +9 -2
- runbooks/{security_baseline → security}/checklist/guardduty_enabled.py +9 -2
- runbooks/{security_baseline → security}/checklist/multi_region_instance_usage.py +5 -1
- runbooks/{security_baseline → security}/checklist/root_access_key.py +6 -1
- runbooks/{security_baseline → security}/config-origin.json +1 -1
- runbooks/{security_baseline → security}/config.json +1 -1
- runbooks/{security_baseline → security}/permission.json +1 -1
- runbooks/{security_baseline → security}/report_generator.py +10 -2
- runbooks/{security_baseline → security}/report_template_en.html +7 -7
- runbooks/{security_baseline → security}/report_template_jp.html +7 -7
- runbooks/{security_baseline → security}/report_template_kr.html +12 -12
- runbooks/{security_baseline → security}/report_template_vn.html +7 -7
- runbooks/{security_baseline → security}/run_script.py +8 -2
- runbooks/{security_baseline → security}/security_baseline_tester.py +12 -4
- runbooks/{security_baseline → security}/utils/common.py +5 -1
- runbooks/utils/__init__.py +204 -0
- runbooks-0.7.0.dist-info/METADATA +375 -0
- runbooks-0.7.0.dist-info/RECORD +249 -0
- {runbooks-0.2.5.dist-info → runbooks-0.7.0.dist-info}/WHEEL +1 -1
- runbooks-0.7.0.dist-info/entry_points.txt +7 -0
- runbooks-0.7.0.dist-info/licenses/LICENSE +201 -0
- runbooks-0.7.0.dist-info/top_level.txt +3 -0
- runbooks/python101/calculator.py +0 -34
- runbooks/python101/config.py +0 -1
- runbooks/python101/exceptions.py +0 -16
- runbooks/python101/file_manager.py +0 -218
- runbooks/python101/toolkit.py +0 -153
- runbooks-0.2.5.dist-info/METADATA +0 -439
- runbooks-0.2.5.dist-info/RECORD +0 -61
- runbooks-0.2.5.dist-info/entry_points.txt +0 -3
- runbooks-0.2.5.dist-info/top_level.txt +0 -1
- /runbooks/{security_baseline/__init__.py → inventory/tests/script_test_data.py} +0 -0
- /runbooks/{security_baseline → security}/checklist/__init__.py +0 -0
- /runbooks/{security_baseline → security}/checklist/account_level_bucket_public_access.py +0 -0
- /runbooks/{security_baseline → security}/checklist/direct_attached_policy.py +0 -0
- /runbooks/{security_baseline → security}/checklist/iam_password_policy.py +0 -0
- /runbooks/{security_baseline → security}/checklist/iam_user_mfa.py +0 -0
- /runbooks/{security_baseline → security}/checklist/multi_region_trail.py +0 -0
- /runbooks/{security_baseline → security}/checklist/root_mfa.py +0 -0
- /runbooks/{security_baseline → security}/checklist/root_usage.py +0 -0
- /runbooks/{security_baseline → security}/checklist/trail_enabled.py +0 -0
- /runbooks/{security_baseline → security}/checklist/trusted_advisor.py +0 -0
- /runbooks/{security_baseline → security}/utils/__init__.py +0 -0
- /runbooks/{security_baseline → security}/utils/enums.py +0 -0
- /runbooks/{security_baseline → security}/utils/language.py +0 -0
- /runbooks/{security_baseline → security}/utils/level_const.py +0 -0
- /runbooks/{security_baseline → security}/utils/permission_list.py +0 -0
@@ -0,0 +1,733 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
AWS CloudFormation StackSet Drift Detection Management and Analysis Script
|
4
|
+
|
5
|
+
Comprehensive enterprise-grade tool for discovering, monitoring, and enabling drift detection
|
6
|
+
across CloudFormation StackSets in AWS Organizations environments. Designed for infrastructure
|
7
|
+
governance, compliance monitoring, and automated drift detection management with multi-threading
|
8
|
+
support for efficient large-scale StackSet operations.
|
9
|
+
|
10
|
+
Key Features:
|
11
|
+
- Multi-account CloudFormation StackSet drift detection discovery and status monitoring
|
12
|
+
- Automated drift detection enablement based on configurable time thresholds
|
13
|
+
- Fragment-based StackSet filtering for targeted drift detection management
|
14
|
+
- Multi-threaded drift detection operations for improved performance at scale
|
15
|
+
- Comprehensive status reporting with tabular output and optional file export
|
16
|
+
- Enterprise authentication with cross-account role assumption support
|
17
|
+
- Configurable time-based drift detection refresh policies
|
18
|
+
|
19
|
+
Enterprise Capabilities:
|
20
|
+
- CloudFormation StackSet lifecycle management and drift monitoring
|
21
|
+
- Organizational compliance tracking through systematic drift detection
|
22
|
+
- Automated infrastructure governance with policy-driven drift detection updates
|
23
|
+
- Multi-region StackSet drift status visibility and management
|
24
|
+
- Performance-optimized concurrent drift detection operations
|
25
|
+
- Comprehensive error handling for large-scale organizational environments
|
26
|
+
|
27
|
+
Operational Use Cases:
|
28
|
+
- Infrastructure compliance auditing across organizational StackSet deployments
|
29
|
+
- Automated drift detection enablement for StackSets exceeding age thresholds
|
30
|
+
- StackSet governance through systematic drift monitoring and reporting
|
31
|
+
- Enterprise infrastructure change tracking and compliance validation
|
32
|
+
- Organizational CloudFormation resource drift analysis and remediation planning
|
33
|
+
|
34
|
+
Output Format:
|
35
|
+
- Tabular display of StackSet drift detection status with account, region, and timing information
|
36
|
+
- Optional CSV/JSON export for integration with enterprise reporting systems
|
37
|
+
- Comprehensive operational metrics including drift detection age and status
|
38
|
+
- Color-coded terminal output for enhanced operational visibility
|
39
|
+
|
40
|
+
Authentication & Security:
|
41
|
+
- AWS Organizations cross-account access with IAM role assumption
|
42
|
+
- Multi-profile authentication support for organizational account management
|
43
|
+
- Regional validation and access control for secure StackSet operations
|
44
|
+
- Comprehensive error handling for authorization and access management
|
45
|
+
|
46
|
+
Performance & Scale:
|
47
|
+
- Multi-threaded drift detection operations for efficient large-scale processing
|
48
|
+
- Memory-efficient processing for extensive StackSet inventories
|
49
|
+
- Configurable concurrency limits for optimal AWS API usage and performance
|
50
|
+
- Progress tracking and operational timing for performance monitoring
|
51
|
+
|
52
|
+
Dependencies:
|
53
|
+
- boto3: AWS SDK for CloudFormation StackSet API operations
|
54
|
+
- Custom modules: Inventory_Modules, ArgumentsClass, account_class
|
55
|
+
- colorama: Enhanced terminal output and color formatting
|
56
|
+
- dateutil: Advanced date/time parsing and timezone handling
|
57
|
+
|
58
|
+
Authors: AWS CloudOps Team
|
59
|
+
Version: 2024.03.06
|
60
|
+
License: MIT
|
61
|
+
"""
|
62
|
+
|
63
|
+
import logging
|
64
|
+
import sys
|
65
|
+
from datetime import datetime
|
66
|
+
from os.path import split
|
67
|
+
from time import time
|
68
|
+
|
69
|
+
import Inventory_Modules
|
70
|
+
from account_class import aws_acct_access
|
71
|
+
from ArgumentsClass import CommonArguments
|
72
|
+
from botocore.exceptions import ClientError
|
73
|
+
from colorama import Fore, init
|
74
|
+
from Inventory_Modules import display_results
|
75
|
+
|
76
|
+
# Initialize colorama for cross-platform colored terminal output
|
77
|
+
init()
|
78
|
+
__version__ = "2024.03.06"
|
79
|
+
begin_time = time() # Script execution timing for performance monitoring
|
80
|
+
sleep_interval = 5 # Default wait interval for drift detection operations
|
81
|
+
|
82
|
+
|
83
|
+
def parse_args(args):
|
84
|
+
"""
|
85
|
+
Parse and validate command line arguments for CloudFormation StackSet drift detection operations.
|
86
|
+
|
87
|
+
Configures comprehensive CLI argument parsing with enterprise-grade options for StackSet
|
88
|
+
drift detection management, including profile authentication, regional targeting, fragment
|
89
|
+
filtering, drift detection enablement, and time-based refresh policies for organizational
|
90
|
+
infrastructure governance and compliance monitoring.
|
91
|
+
|
92
|
+
Args:
|
93
|
+
args (list): Command line arguments from sys.argv[1:] for argument parsing
|
94
|
+
|
95
|
+
Returns:
|
96
|
+
argparse.Namespace: Parsed arguments object containing:
|
97
|
+
- Profile: AWS profile name for authentication and cross-account access
|
98
|
+
- Region: Target AWS region for StackSet drift detection operations
|
99
|
+
- Fragments: StackSet name fragments for targeted filtering and discovery
|
100
|
+
- Exact: Boolean flag for exact fragment matching vs substring matching
|
101
|
+
- pstatus: StackSet status filter for 'active' vs all status types
|
102
|
+
- pEnable: Boolean flag to enable automated drift detection on eligible StackSets
|
103
|
+
- pDaysSince: Time threshold in days for drift detection refresh policy
|
104
|
+
- Filename: Optional output file path for results export and persistence
|
105
|
+
- Time: Boolean flag for execution timing and performance monitoring
|
106
|
+
- loglevel: Logging verbosity level for operational visibility
|
107
|
+
|
108
|
+
CLI Arguments:
|
109
|
+
Authentication & Targeting:
|
110
|
+
--profile (-p): AWS profile for authentication and account access
|
111
|
+
--region (-r): Target AWS region for StackSet operations
|
112
|
+
|
113
|
+
StackSet Filtering & Discovery:
|
114
|
+
--fragment (-f): StackSet name fragments for targeted search and filtering
|
115
|
+
--exact (-e): Enable exact fragment matching instead of substring search
|
116
|
+
|
117
|
+
Drift Detection Management:
|
118
|
+
--status (-s): StackSet status filter ('active' for operational StackSets only)
|
119
|
+
+enable: Automated drift detection enablement for eligible StackSets
|
120
|
+
--days_since (--ds): Age threshold in days for drift detection refresh
|
121
|
+
|
122
|
+
Output & Reporting:
|
123
|
+
--filename: Output file path for results export (CSV/JSON format)
|
124
|
+
--timing (-t): Enable execution timing and performance metrics
|
125
|
+
--loglevel (-v): Logging verbosity (DEBUG, INFO, WARNING, ERROR)
|
126
|
+
|
127
|
+
Enterprise Features:
|
128
|
+
- Multi-profile authentication for organizational account management
|
129
|
+
- Regional targeting with validation for StackSet drift detection operations
|
130
|
+
- Fragment-based filtering for targeted StackSet discovery and management
|
131
|
+
- Time-based drift detection refresh policies for compliance automation
|
132
|
+
- Flexible output options for integration with enterprise reporting systems
|
133
|
+
|
134
|
+
Validation & Error Handling:
|
135
|
+
- AWS profile validation with comprehensive error messaging
|
136
|
+
- Regional access validation preventing unauthorized operations
|
137
|
+
- Argument validation with detailed help text and usage examples
|
138
|
+
- Type checking and range validation for numeric parameters
|
139
|
+
"""
|
140
|
+
# Extract script name for argument group organization and help display
|
141
|
+
script_path, script_name = split(sys.argv[0])
|
142
|
+
|
143
|
+
# Initialize common argument parser with enterprise authentication and targeting
|
144
|
+
parser = CommonArguments()
|
145
|
+
parser.singleprofile() # AWS profile for authentication and account access
|
146
|
+
parser.singleregion() # Target AWS region for StackSet operations
|
147
|
+
parser.extendedargs() # Extended arguments for account filtering and targeting
|
148
|
+
parser.fragment() # StackSet name fragment filtering for targeted discovery
|
149
|
+
parser.save_to_file() # Output file options for results export and persistence
|
150
|
+
parser.timing() # Execution timing for performance monitoring
|
151
|
+
parser.verbosity() # Logging verbosity for operational visibility
|
152
|
+
parser.version(__version__) # Script version for compatibility tracking
|
153
|
+
|
154
|
+
# Configure script-specific arguments for StackSet drift detection management
|
155
|
+
local = parser.my_parser.add_argument_group(script_name, "Parameters specific to this script")
|
156
|
+
|
157
|
+
# StackSet status filtering for operational vs all StackSet types
|
158
|
+
local.add_argument(
|
159
|
+
"-s",
|
160
|
+
"--status",
|
161
|
+
dest="pstatus",
|
162
|
+
metavar="CloudFormation status",
|
163
|
+
default="active",
|
164
|
+
help="StackSet status filter: 'active' for operational StackSets, 'all' for comprehensive discovery including deleted StackSets",
|
165
|
+
)
|
166
|
+
|
167
|
+
# Automated drift detection enablement for eligible StackSets
|
168
|
+
local.add_argument(
|
169
|
+
"+enable",
|
170
|
+
dest="pEnable",
|
171
|
+
action="store_true",
|
172
|
+
help="Enable automated drift detection on StackSets that haven't been checked within the specified time threshold",
|
173
|
+
)
|
174
|
+
|
175
|
+
# Time threshold for drift detection refresh policy and compliance automation
|
176
|
+
local.add_argument(
|
177
|
+
"--days_since",
|
178
|
+
"--ds",
|
179
|
+
dest="pDaysSince",
|
180
|
+
metavar="Number of days old",
|
181
|
+
type=int,
|
182
|
+
default=15,
|
183
|
+
help="Maximum age in days since last drift detection check before StackSet requires drift detection refresh (default: 15 days)",
|
184
|
+
)
|
185
|
+
|
186
|
+
return parser.my_parser.parse_args(args)
|
187
|
+
|
188
|
+
|
189
|
+
def setup_auth(fProfile: str) -> aws_acct_access:
|
190
|
+
"""
|
191
|
+
Configure AWS authentication and validate account access for StackSet drift detection operations.
|
192
|
+
|
193
|
+
Establishes secure AWS authentication using the specified profile with comprehensive error
|
194
|
+
handling and validation. Provides operational context display including account information,
|
195
|
+
region targeting, fragment filtering, and drift detection enablement status for enterprise
|
196
|
+
StackSet management and infrastructure governance operations.
|
197
|
+
|
198
|
+
Args:
|
199
|
+
fProfile (str): AWS profile name for authentication and cross-account access
|
200
|
+
None or empty string defaults to default profile or environment credentials
|
201
|
+
|
202
|
+
Returns:
|
203
|
+
aws_acct_access: Authenticated AWS account access object containing:
|
204
|
+
- acct_number: AWS account number for operational context
|
205
|
+
- AccountType: Account type (root, member, etc.) for organizational visibility
|
206
|
+
- Region: Target AWS region for StackSet drift detection operations
|
207
|
+
- session: Authenticated boto3 session for CloudFormation API calls
|
208
|
+
- Success: Boolean indicating successful authentication and account access
|
209
|
+
|
210
|
+
Authentication Process:
|
211
|
+
1. Initialize AWS account access object with specified profile
|
212
|
+
2. Validate credential authenticity and account permissions
|
213
|
+
3. Verify CloudFormation StackSet API access in target region
|
214
|
+
4. Display comprehensive operational context for user confirmation
|
215
|
+
5. Return authenticated account object for downstream operations
|
216
|
+
|
217
|
+
Operational Context Display:
|
218
|
+
- Account information including account number and organizational type
|
219
|
+
- Target region for StackSet drift detection operations
|
220
|
+
- Fragment filtering criteria for StackSet discovery and targeting
|
221
|
+
- Drift detection enablement status and operational mode
|
222
|
+
- User confirmation of operational parameters and scope
|
223
|
+
|
224
|
+
Error Handling:
|
225
|
+
- Connection errors with comprehensive error messaging and exit codes
|
226
|
+
- Authentication failures with detailed troubleshooting guidance
|
227
|
+
- Profile validation with specific error messaging for credential issues
|
228
|
+
- Regional access validation preventing unauthorized operations
|
229
|
+
|
230
|
+
Enterprise Security:
|
231
|
+
- Multi-profile authentication for organizational account management
|
232
|
+
- Cross-account role assumption validation for secure operations
|
233
|
+
- Regional access control ensuring authorized StackSet operations
|
234
|
+
- Comprehensive audit logging for security and compliance tracking
|
235
|
+
|
236
|
+
Raises:
|
237
|
+
SystemExit: On authentication failures or connection errors with specific exit codes:
|
238
|
+
- Exit code 8: Connection errors preventing AWS API access
|
239
|
+
- Exit code 99: Authentication failures or invalid credentials
|
240
|
+
"""
|
241
|
+
try:
|
242
|
+
# Initialize AWS account access with profile-based authentication
|
243
|
+
aws_acct = aws_acct_access(fProfile)
|
244
|
+
except ConnectionError as my_Error:
|
245
|
+
# Handle connection errors with detailed logging and graceful exit
|
246
|
+
logging.error(f"Exiting due to error: {my_Error}")
|
247
|
+
sys.exit(8)
|
248
|
+
|
249
|
+
# Validate successful authentication and account access
|
250
|
+
if not aws_acct.Success:
|
251
|
+
print(f"{Fore.RED}Profile {pProfile} failed to access an account. Check credentials and try again{Fore.RESET}")
|
252
|
+
sys.exit(99)
|
253
|
+
|
254
|
+
# Display comprehensive operational context for user confirmation and audit logging
|
255
|
+
print()
|
256
|
+
print(f"You asked me to display drift detection status on stacksets that match the following:")
|
257
|
+
print(f"\t\tIn the {aws_acct.AccountType} account {aws_acct.acct_number}")
|
258
|
+
print(f"\t\tIn this Region: {pRegion}")
|
259
|
+
|
260
|
+
# Display fragment filtering criteria with exact vs substring matching context
|
261
|
+
if pExact:
|
262
|
+
print(f"\t\tFor stacksets that {Fore.RED}exactly match{Fore.RESET}: {pFragments}")
|
263
|
+
else:
|
264
|
+
print(
|
265
|
+
f"\t\tFor stacksets that contain th{'is fragment' if len(pFragments) == 1 else 'ese fragments'}: {pFragments}"
|
266
|
+
)
|
267
|
+
|
268
|
+
# Display drift detection enablement status for operational clarity
|
269
|
+
print(f"\t\tand enable drift detection on those stacksets, if they're not current") if pEnableDriftDetection else ""
|
270
|
+
|
271
|
+
print()
|
272
|
+
return aws_acct
|
273
|
+
|
274
|
+
|
275
|
+
def find_stack_sets(faws_acct: aws_acct_access, fStackSetFragmentlist: list = None, fExact: bool = False) -> dict:
|
276
|
+
"""
|
277
|
+
Discover and enumerate CloudFormation StackSets with comprehensive drift detection metadata.
|
278
|
+
|
279
|
+
Performs targeted CloudFormation StackSet discovery using fragment-based filtering with
|
280
|
+
comprehensive error handling and drift detection metadata extraction. Designed for enterprise
|
281
|
+
StackSet lifecycle management, compliance monitoring, and automated drift detection operations
|
282
|
+
across organizational AWS environments.
|
283
|
+
|
284
|
+
Args:
|
285
|
+
faws_acct (aws_acct_access): Authenticated AWS account access object containing:
|
286
|
+
- session: boto3 session for CloudFormation API operations
|
287
|
+
- Region: Target AWS region for StackSet discovery operations
|
288
|
+
- acct_number: Account number for error logging and operational context
|
289
|
+
fStackSetFragmentlist (list): StackSet name fragments for targeted filtering
|
290
|
+
None defaults to ["all"] for comprehensive StackSet discovery
|
291
|
+
fExact (bool): Fragment matching mode for precision targeting
|
292
|
+
True: Exact fragment matching for specific StackSet identification
|
293
|
+
False: Substring matching for broader StackSet discovery
|
294
|
+
|
295
|
+
Returns:
|
296
|
+
dict: Comprehensive StackSet discovery results containing:
|
297
|
+
- Success: Boolean indicating successful StackSet discovery operation
|
298
|
+
- ErrorMessage: Detailed error information for troubleshooting and logging
|
299
|
+
- StackSets: Dictionary of discovered StackSets with drift detection metadata:
|
300
|
+
- StackSetName: CloudFormation StackSet identifier
|
301
|
+
- Status: Current StackSet operational status
|
302
|
+
- DriftStatus: Current drift detection status (DRIFTED, IN_SYNC, etc.)
|
303
|
+
- LastDriftCheckTimestamp: Most recent drift detection timestamp
|
304
|
+
- Stack_Instances_number: Count of StackSet instances across accounts/regions
|
305
|
+
- Additional operational metadata for governance and compliance
|
306
|
+
|
307
|
+
StackSet Discovery Features:
|
308
|
+
- Fragment-based filtering for targeted StackSet identification and management
|
309
|
+
- Comprehensive drift detection metadata extraction for compliance monitoring
|
310
|
+
- StackSet instance enumeration for organizational visibility and governance
|
311
|
+
- Status-based filtering for operational StackSet lifecycle management
|
312
|
+
- Regional StackSet discovery with cross-account instance visibility
|
313
|
+
|
314
|
+
Drift Detection Metadata:
|
315
|
+
- Current drift detection status for infrastructure change tracking
|
316
|
+
- Last drift check timestamps for compliance and policy enforcement
|
317
|
+
- Drift detection enablement status for automated governance workflows
|
318
|
+
- Instance-level drift aggregation for comprehensive compliance reporting
|
319
|
+
|
320
|
+
Error Handling & Resilience:
|
321
|
+
- AWS API authorization failure detection with detailed error logging
|
322
|
+
- CloudFormation service error handling with comprehensive error context
|
323
|
+
- Network connectivity error management with graceful degradation
|
324
|
+
- Regional access validation preventing unauthorized StackSet operations
|
325
|
+
|
326
|
+
Enterprise Integration:
|
327
|
+
- Structured result format for integration with enterprise reporting systems
|
328
|
+
- Comprehensive error messaging for operational troubleshooting and audit
|
329
|
+
- Performance-optimized discovery for large-scale StackSet inventories
|
330
|
+
- Organizational compliance tracking through systematic metadata extraction
|
331
|
+
|
332
|
+
Performance Considerations:
|
333
|
+
- Memory-efficient processing for extensive StackSet inventories
|
334
|
+
- Regional API optimization for improved discovery performance
|
335
|
+
- Concurrent-safe operations for integration with multi-threaded workflows
|
336
|
+
- Structured result caching for repeated discovery operations
|
337
|
+
"""
|
338
|
+
# Configure default fragment filtering for comprehensive StackSet discovery
|
339
|
+
if fStackSetFragmentlist is None:
|
340
|
+
fStackSetFragmentlist = ["all"] # Default to all StackSets for comprehensive analysis
|
341
|
+
|
342
|
+
# Initialize StackSet discovery result structure with error tracking
|
343
|
+
StackSets = {"Success": False, "ErrorMessage": "", "StackSets": {}}
|
344
|
+
|
345
|
+
try:
|
346
|
+
# Execute comprehensive StackSet discovery with drift detection metadata extraction
|
347
|
+
StackSets = Inventory_Modules.find_stacksets3(faws_acct, faws_acct.Region, fStackSetFragmentlist, fExact, True)
|
348
|
+
except ClientError as my_Error:
|
349
|
+
# Handle AWS API client errors with specific authorization failure detection
|
350
|
+
if "AuthFailure" in str(my_Error):
|
351
|
+
error_message = f"{aws_acct.acct_number}: Authorization Failure"
|
352
|
+
logging.error(error_message)
|
353
|
+
else:
|
354
|
+
error_message = f"Error: {my_Error}"
|
355
|
+
logging.error(error_message)
|
356
|
+
StackSets["ErrorMessage"] = error_message
|
357
|
+
except Exception as my_Error:
|
358
|
+
# Handle comprehensive exceptions with detailed error logging
|
359
|
+
error_message = f"Error: {my_Error}"
|
360
|
+
logging.error(error_message)
|
361
|
+
StackSets["ErrorMessage"] = error_message
|
362
|
+
|
363
|
+
return StackSets
|
364
|
+
|
365
|
+
|
366
|
+
def enable_stack_set_drift_detection(faws_acct: aws_acct_access, fStackSets: dict = None):
|
367
|
+
"""
|
368
|
+
Enable automated drift detection across multiple CloudFormation StackSets using multi-threading.
|
369
|
+
|
370
|
+
Executes comprehensive drift detection enablement operations across organizational StackSets
|
371
|
+
using multi-threaded processing for efficient large-scale operations. Monitors drift detection
|
372
|
+
operation progress with real-time status tracking and comprehensive error handling for enterprise
|
373
|
+
infrastructure governance and compliance automation.
|
374
|
+
|
375
|
+
Args:
|
376
|
+
faws_acct (aws_acct_access): Authenticated AWS account access object containing:
|
377
|
+
- session: boto3 session for CloudFormation StackSet API operations
|
378
|
+
- acct_number: Account number for operational logging and error context
|
379
|
+
- Region: Target AWS region for drift detection operations
|
380
|
+
fStackSets (dict): List of StackSets requiring drift detection enablement containing:
|
381
|
+
- StackSetName: CloudFormation StackSet identifier for drift detection
|
382
|
+
- NeedsDriftDetectionUpdate: Boolean indicating drift detection requirement
|
383
|
+
- Additional StackSet metadata for operational context and tracking
|
384
|
+
|
385
|
+
Returns:
|
386
|
+
dict: Updated StackSets dictionary with drift detection operation results containing:
|
387
|
+
- Success: Boolean indicating overall drift detection enablement success
|
388
|
+
- ErrorMessage: Detailed error information for failed operations
|
389
|
+
- Individual StackSet status updates with drift detection results
|
390
|
+
|
391
|
+
Multi-threaded Architecture:
|
392
|
+
- Queue-based worker pattern for concurrent drift detection operations
|
393
|
+
- Configurable worker thread pool with automatic scaling based on StackSet count
|
394
|
+
- Thread-safe operation monitoring with real-time progress tracking
|
395
|
+
- Graceful error handling for authorization and operational failures
|
396
|
+
|
397
|
+
Drift Detection Operation Management:
|
398
|
+
- Automated drift detection enablement on eligible StackSets
|
399
|
+
- Real-time operation status monitoring with progress indicators
|
400
|
+
- Operation completion tracking with timeout management
|
401
|
+
- Comprehensive error detection and recovery for failed operations
|
402
|
+
|
403
|
+
Progress Monitoring & Feedback:
|
404
|
+
- Real-time terminal progress display with operation status updates
|
405
|
+
- Configurable sleep intervals for optimal API usage and performance
|
406
|
+
- Operation timing tracking for performance monitoring and optimization
|
407
|
+
- Visual progress indicators for enhanced user experience
|
408
|
+
|
409
|
+
Error Handling & Resilience:
|
410
|
+
- AWS API authorization failure detection with graceful degradation
|
411
|
+
- CloudFormation service error management with detailed error logging
|
412
|
+
- Network connectivity error handling with operation retry capabilities
|
413
|
+
- Thread-safe error aggregation for comprehensive operation reporting
|
414
|
+
|
415
|
+
Enterprise Operational Features:
|
416
|
+
- Concurrent drift detection operations for improved performance at scale
|
417
|
+
- Comprehensive operational logging for audit and troubleshooting
|
418
|
+
- Resource-efficient processing for large-scale StackSet inventories
|
419
|
+
- Integration-ready result format for enterprise reporting and automation
|
420
|
+
|
421
|
+
Performance Optimization:
|
422
|
+
- Worker thread scaling based on StackSet count for optimal performance
|
423
|
+
- Memory-efficient processing with queue-based work distribution
|
424
|
+
- API rate limiting awareness with configurable sleep intervals
|
425
|
+
- Operational timing metrics for performance analysis and optimization
|
426
|
+
"""
|
427
|
+
from queue import Queue
|
428
|
+
from threading import Thread
|
429
|
+
from time import sleep
|
430
|
+
|
431
|
+
class UpdateDriftDetection(Thread):
|
432
|
+
"""
|
433
|
+
Multi-threaded worker class for concurrent drift detection enablement operations.
|
434
|
+
|
435
|
+
Implements thread-safe drift detection operations using queue-based work distribution
|
436
|
+
for efficient processing of CloudFormation StackSet drift detection across multiple
|
437
|
+
StackSets with comprehensive error handling and progress monitoring.
|
438
|
+
"""
|
439
|
+
|
440
|
+
def __init__(self, queue):
|
441
|
+
Thread.__init__(self)
|
442
|
+
self.queue = queue
|
443
|
+
|
444
|
+
def run(self):
|
445
|
+
while True:
|
446
|
+
# Extract StackSet work item from queue for drift detection processing
|
447
|
+
c_aws_acct, c_stackset_name = self.queue.get()
|
448
|
+
logging.info(f"De-queued info for account {c_aws_acct.acct_number}")
|
449
|
+
|
450
|
+
try:
|
451
|
+
# Execute drift detection enablement with comprehensive status monitoring
|
452
|
+
logging.info(f"Attempting to run drift_detection on {c_stackset_name['StackSetName']}")
|
453
|
+
client = c_aws_acct.session.client("cloudformation")
|
454
|
+
logging.info(f"Enabling Drift Detection for {c_stackset_name['StackSetName']}")
|
455
|
+
|
456
|
+
# Initiate drift detection operation using custom inventory module
|
457
|
+
DD_Operation = Inventory_Modules.enable_drift_on_stackset3(
|
458
|
+
c_aws_acct, c_stackset_name["StackSetName"]
|
459
|
+
)
|
460
|
+
|
461
|
+
# Monitor drift detection operation progress with real-time status tracking
|
462
|
+
intervals_waited = 1
|
463
|
+
sleep(sleep_interval) # Initial wait for operation to start
|
464
|
+
|
465
|
+
# Poll drift detection operation status until completion
|
466
|
+
Status = client.describe_stack_set_operation(
|
467
|
+
StackSetName=c_stackset_name["StackSetName"], OperationId=DD_Operation["OperationId"]
|
468
|
+
)
|
469
|
+
|
470
|
+
# Continue monitoring while drift detection operation is running
|
471
|
+
while Status["StackSetOperation"]["Status"] in ["RUNNING"]:
|
472
|
+
Status = client.describe_stack_set_operation(
|
473
|
+
StackSetName=c_stackset_name["StackSetName"], OperationId=DD_Operation["OperationId"]
|
474
|
+
)
|
475
|
+
sleep(sleep_interval) # Wait between status checks to avoid API throttling
|
476
|
+
|
477
|
+
# Display real-time progress with timing information
|
478
|
+
print(
|
479
|
+
f"{ERASE_LINE}Waiting for {c_stackset_name['StackSetName']} to finish drift detection",
|
480
|
+
f"{sleep_interval * intervals_waited} seconds waited so far",
|
481
|
+
end="\r",
|
482
|
+
)
|
483
|
+
intervals_waited += 1
|
484
|
+
logging.info(f"Sleeping to allow {c_stackset_name['StackSetName']} to continue drift detection")
|
485
|
+
|
486
|
+
# Process drift detection operation completion status
|
487
|
+
if Status["Status"] in ["FAILED"]:
|
488
|
+
fStackSets["Success"] = False
|
489
|
+
fStackSets["ErrorMessage"] = Status["StackSetOperation"]["StackSetDriftDetectionDetails"]
|
490
|
+
else:
|
491
|
+
fStackSets["Success"] = True
|
492
|
+
|
493
|
+
except TypeError as my_Error:
|
494
|
+
# Handle type errors in drift detection processing with logging
|
495
|
+
logging.info(f"Error: {my_Error}")
|
496
|
+
continue
|
497
|
+
except ClientError as my_Error:
|
498
|
+
# Handle AWS API client errors with specific authorization failure detection
|
499
|
+
if "AuthFailure" in str(my_Error):
|
500
|
+
logging.error(f"Account {c_aws_acct.acct_number}: Authorization Failure")
|
501
|
+
continue
|
502
|
+
except KeyError as my_Error:
|
503
|
+
# Handle missing key errors in account access with detailed logging
|
504
|
+
logging.error(f"Account Access failed - trying to access {c_aws_acct.acct_number}")
|
505
|
+
logging.info(f"Actual Error: {my_Error}")
|
506
|
+
continue
|
507
|
+
finally:
|
508
|
+
# Mark queue item as completed for work distribution tracking
|
509
|
+
# Note: Commented metadata updates for potential future enhancement
|
510
|
+
# fStackSets[c_stackset_name]['AccountId'] = c_aws_acct.acct_number
|
511
|
+
# fStackSets[c_stackset_name]['Region'] = c_aws_acct.Region
|
512
|
+
self.queue.task_done()
|
513
|
+
|
514
|
+
# Configure optimal worker thread count based on StackSet count and system limits
|
515
|
+
WorkerThreads = min(len(fStackSets), 25)
|
516
|
+
|
517
|
+
# Initialize multi-threaded processing infrastructure for drift detection operations
|
518
|
+
checkqueue = Queue()
|
519
|
+
|
520
|
+
# Create and start worker thread pool for concurrent drift detection operations
|
521
|
+
for x in range(WorkerThreads):
|
522
|
+
worker = UpdateDriftDetection(checkqueue)
|
523
|
+
# Daemon threads allow main thread exit even if workers are still processing
|
524
|
+
worker.daemon = True
|
525
|
+
worker.start()
|
526
|
+
|
527
|
+
# Queue drift detection work items for worker thread processing
|
528
|
+
for stackset in fStackSets:
|
529
|
+
logging.info(f"Connecting to account {faws_acct.acct_number}")
|
530
|
+
try:
|
531
|
+
# Queue StackSet for drift detection processing with progress display
|
532
|
+
print(
|
533
|
+
f"{ERASE_LINE}Queuing stackset {stackset['StackSetName']} in account {faws_acct.acct_number} in region {faws_acct.Region}",
|
534
|
+
end="\r",
|
535
|
+
)
|
536
|
+
checkqueue.put((faws_acct, stackset))
|
537
|
+
except ClientError as my_Error:
|
538
|
+
# Handle authorization failures with informative error messaging
|
539
|
+
if "AuthFailure" in str(my_Error):
|
540
|
+
logging.error(
|
541
|
+
f"Authorization Failure accessing account {faws_acct.acct_number} in {faws_acct.Region} region"
|
542
|
+
)
|
543
|
+
logging.error(f"It's possible that the region {faws_acct.Region} hasn't been opted-into")
|
544
|
+
pass
|
545
|
+
|
546
|
+
# Wait for all worker threads to complete drift detection operations
|
547
|
+
checkqueue.join()
|
548
|
+
return fStackSets
|
549
|
+
|
550
|
+
|
551
|
+
def days_between_dates(fdate1: datetime, fdays_since: int):
|
552
|
+
"""
|
553
|
+
Calculate time difference between drift detection timestamp and current time for compliance evaluation.
|
554
|
+
|
555
|
+
Performs comprehensive date arithmetic to determine whether CloudFormation StackSet drift detection
|
556
|
+
timestamps meet organizational compliance policies and time-based refresh requirements. Designed
|
557
|
+
for enterprise governance automation with timezone-aware date calculations and structured result
|
558
|
+
formatting for integration with automated compliance workflows.
|
559
|
+
|
560
|
+
Args:
|
561
|
+
fdate1 (datetime): Drift detection timestamp from CloudFormation StackSet metadata
|
562
|
+
None indicates drift detection has never been executed
|
563
|
+
Must be timezone-aware datetime object for accurate calculations
|
564
|
+
fdays_since (int): Maximum acceptable age in days for drift detection compliance
|
565
|
+
Organizational policy threshold for drift detection refresh requirements
|
566
|
+
|
567
|
+
Returns:
|
568
|
+
dict: Comprehensive drift detection age evaluation containing:
|
569
|
+
- Current: Boolean indicating compliance with organizational time policies
|
570
|
+
- NumberOfDays: Integer days since last drift detection for operational metrics
|
571
|
+
- ErrorMessage: Detailed error information for null or invalid timestamps
|
572
|
+
|
573
|
+
Compliance Policy Evaluation:
|
574
|
+
- Current=True: Drift detection age within acceptable organizational thresholds
|
575
|
+
- Current=False: Drift detection exceeds policy limits and requires refresh
|
576
|
+
- ErrorMessage: Indicates drift detection has never been executed (requires enablement)
|
577
|
+
|
578
|
+
Enterprise Features:
|
579
|
+
- Timezone-aware date calculations for accurate multi-region compliance evaluation
|
580
|
+
- Structured result format for integration with enterprise governance systems
|
581
|
+
- Comprehensive error handling for missing or invalid drift detection metadata
|
582
|
+
- Policy-driven compliance evaluation with configurable time thresholds
|
583
|
+
|
584
|
+
Date Calculation Logic:
|
585
|
+
1. Validate drift detection timestamp existence and format
|
586
|
+
2. Calculate absolute time difference between current time and drift detection timestamp
|
587
|
+
3. Extract days component from timedelta for policy evaluation
|
588
|
+
4. Compare against organizational policy threshold for compliance determination
|
589
|
+
5. Return structured compliance result with operational metrics
|
590
|
+
|
591
|
+
Error Handling:
|
592
|
+
- Null timestamp handling for StackSets without drift detection history
|
593
|
+
- Type validation ensuring datetime objects for accurate calculations
|
594
|
+
- Timezone handling for consistent multi-region drift detection evaluation
|
595
|
+
- Comprehensive error messaging for troubleshooting and operational visibility
|
596
|
+
|
597
|
+
Integration Considerations:
|
598
|
+
- Structured result format for automated compliance reporting systems
|
599
|
+
- Policy threshold configurability for organizational governance flexibility
|
600
|
+
- Operational metrics inclusion for drift detection age tracking and analysis
|
601
|
+
- Error state handling for StackSets requiring initial drift detection enablement
|
602
|
+
"""
|
603
|
+
from dateutil.tz import tzutc
|
604
|
+
|
605
|
+
# Validate drift detection timestamp existence for compliance evaluation
|
606
|
+
if fdate1 is None:
|
607
|
+
# Return structured error result for StackSets without drift detection history
|
608
|
+
response = {"Current": False, "ErrorMessage": "Drift Status never checked"}
|
609
|
+
return response
|
610
|
+
elif not isinstance(fdate1, datetime):
|
611
|
+
# Enforce datetime object requirement for accurate date arithmetic
|
612
|
+
raise ValueError("Date passed in should be datetime object")
|
613
|
+
|
614
|
+
# Calculate timezone-aware time difference for accurate compliance evaluation
|
615
|
+
date_difference = abs(datetime.now(tzutc()) - fdate1)
|
616
|
+
|
617
|
+
# Extract days component from timedelta for policy threshold comparison
|
618
|
+
number_of_days = date_difference.days
|
619
|
+
|
620
|
+
# Evaluate drift detection age against organizational compliance policy
|
621
|
+
if number_of_days <= fdays_since:
|
622
|
+
# Drift detection meets organizational compliance requirements
|
623
|
+
response = {"Current": True, "NumberOfDays": number_of_days}
|
624
|
+
else:
|
625
|
+
# Drift detection exceeds policy threshold and requires refresh
|
626
|
+
response = {"Current": False, "NumberOfDays": number_of_days}
|
627
|
+
|
628
|
+
return response
|
629
|
+
|
630
|
+
|
631
|
+
##################
|
632
|
+
# Main
|
633
|
+
##################
|
634
|
+
if __name__ == "__main__":
|
635
|
+
args = parse_args(sys.argv[1:])
|
636
|
+
pProfile = args.Profile
|
637
|
+
pRegion = args.Region
|
638
|
+
pFragments = args.Fragments
|
639
|
+
pExact = args.Exact
|
640
|
+
pDaysSince = args.pDaysSince
|
641
|
+
pstatus = args.pstatus
|
642
|
+
pFilename = args.Filename
|
643
|
+
pEnableDriftDetection = args.pEnable
|
644
|
+
pTiming = args.Time
|
645
|
+
AccountsToSkip = args.SkipAccounts
|
646
|
+
ProfilesToSkip = args.SkipProfiles
|
647
|
+
pAccounts = args.Accounts
|
648
|
+
pSaveFilename = args.Filename
|
649
|
+
verbose = args.loglevel
|
650
|
+
|
651
|
+
# Set Log Level
|
652
|
+
logging.basicConfig(level=verbose, format="[%(filename)s:%(lineno)s - %(funcName)20s() ] %(message)s")
|
653
|
+
logging.getLogger("boto3").setLevel(logging.CRITICAL)
|
654
|
+
logging.getLogger("botocore").setLevel(logging.CRITICAL)
|
655
|
+
logging.getLogger("s3transfer").setLevel(logging.CRITICAL)
|
656
|
+
logging.getLogger("urllib3").setLevel(logging.CRITICAL)
|
657
|
+
"""
|
658
|
+
We should eventually create an argument here that would check on the status of the drift-detection using
|
659
|
+
"describe_stack_drift_detection_status", but we haven't created that function yet...
|
660
|
+
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/cloudformation.html#CloudFormation.Client.describe_stack_drift_detection_status
|
661
|
+
"""
|
662
|
+
|
663
|
+
##########################
|
664
|
+
ERASE_LINE = "\x1b[2K"
|
665
|
+
|
666
|
+
# Setup the aws_acct object, and the list of Regions
|
667
|
+
aws_acct = setup_auth(pProfile)
|
668
|
+
|
669
|
+
display_dict_stacksets = {
|
670
|
+
"AccountNumber": {"DisplayOrder": 1, "Heading": "Acct Number"},
|
671
|
+
"Region": {"DisplayOrder": 2, "Heading": "Region"},
|
672
|
+
"StackSetName": {"DisplayOrder": 3, "Heading": "Stack Set Name"},
|
673
|
+
"Status": {"DisplayOrder": 4, "Heading": "Stack Status"},
|
674
|
+
"Stack_Instances_number": {"DisplayOrder": 5, "Heading": "# of Instances"},
|
675
|
+
"DriftStatus": {"DisplayOrder": 6, "Heading": "Drift Status"},
|
676
|
+
"LastDriftCheckTimestamp": {"DisplayOrder": 7, "Heading": "Date Drift Checked"},
|
677
|
+
"NeedsDriftDetectionUpdate": {"DisplayOrder": 8, "Heading": "Needs update", "Condition": [True]},
|
678
|
+
}
|
679
|
+
|
680
|
+
# RegionList = Inventory_Modules.get_service_regions('cloudformation', pRegionList)
|
681
|
+
|
682
|
+
# Find StackSets to operate on and get the last detection status
|
683
|
+
StackSets = find_stack_sets(aws_acct, pFragments, pExact)
|
684
|
+
StackSetsList = [item for key, item in StackSets["StackSets"].items()]
|
685
|
+
for item in StackSetsList:
|
686
|
+
item["AccountNumber"] = aws_acct.acct_number
|
687
|
+
item["Region"] = aws_acct.Region
|
688
|
+
sorted_all_stacksets = sorted(StackSetsList, key=lambda x: (x["StackSetName"]))
|
689
|
+
for item in sorted_all_stacksets:
|
690
|
+
if (
|
691
|
+
"LastDriftCheckTimestamp" not in item.keys()
|
692
|
+
or not days_between_dates(item["LastDriftCheckTimestamp"], pDaysSince)["Current"]
|
693
|
+
) and item.get("Stack_Instances_number", 0) > 0:
|
694
|
+
item["NeedsDriftDetectionUpdate"] = True
|
695
|
+
else:
|
696
|
+
item["NeedsDriftDetectionUpdate"] = False
|
697
|
+
display_results(sorted_all_stacksets, display_dict_stacksets, None, pSaveFilename)
|
698
|
+
# Enable drift_detection on those stacksets
|
699
|
+
DriftDetectionNeededStacksets = [item for item in StackSetsList if item["NeedsDriftDetectionUpdate"]]
|
700
|
+
if len(DriftDetectionNeededStacksets) == 0:
|
701
|
+
print()
|
702
|
+
print(f"The stacksets found all fall within current guidelines. No additional drift detection is necessary.")
|
703
|
+
print()
|
704
|
+
ReallyDetectDrift = False
|
705
|
+
else:
|
706
|
+
StackSetNamesThatNeededDriftDetection = [item["StackSetName"] for item in DriftDetectionNeededStacksets]
|
707
|
+
if verbose == logging.INFO:
|
708
|
+
print(
|
709
|
+
f"The following stacksets haven't been updated in at least {pDaysSince} days, and therefore need to be updated:"
|
710
|
+
)
|
711
|
+
for stackname in StackSetNamesThatNeededDriftDetection:
|
712
|
+
print(f"\t{stackname}")
|
713
|
+
ReallyDetectDrift = input(
|
714
|
+
f"Do you want to enable drift detection on th{'is' if len(DriftDetectionNeededStacksets) == 1 else 'ese'} {len(DriftDetectionNeededStacksets)} stackset{' that is not' if len(DriftDetectionNeededStacksets) == 1 else 's that are not'} current? (y/n)"
|
715
|
+
) in ["Y", "y"]
|
716
|
+
if ReallyDetectDrift:
|
717
|
+
Drift_Status = enable_stack_set_drift_detection(aws_acct, DriftDetectionNeededStacksets)
|
718
|
+
StackSets = find_stack_sets(aws_acct, StackSetNamesThatNeededDriftDetection, True)
|
719
|
+
# Determine whether we want to update this status or not -
|
720
|
+
StackSetsList = [item for key, item in StackSets["StackSets"].items()]
|
721
|
+
sorted_all_stacksets = sorted(StackSetsList, key=lambda x: (x["StackSetName"]))
|
722
|
+
# Display results
|
723
|
+
display_results(sorted_all_stacksets, display_dict_stacksets, None, pSaveFilename)
|
724
|
+
|
725
|
+
print(ERASE_LINE)
|
726
|
+
print(f"{Fore.RED}Looked through {len(sorted_all_stacksets)} StackSets across the {pRegion} region{Fore.RESET}")
|
727
|
+
print()
|
728
|
+
|
729
|
+
if pTiming:
|
730
|
+
print(ERASE_LINE)
|
731
|
+
print(f"{Fore.GREEN}This script took {time() - begin_time:.3f} seconds{Fore.RESET}")
|
732
|
+
print("Thanks for using this script...")
|
733
|
+
print()
|