runbooks 0.2.3__py3-none-any.whl → 0.6.1__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.template +2 -0
- jupyter-agent/.gitattributes +35 -0
- jupyter-agent/README.md +16 -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/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/__init__.py +88 -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/Inventory_Modules.py +6130 -0
- runbooks/inventory/LandingZone/delete_lz.py +1075 -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/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/script_test_data.py +0 -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 +785 -0
- runbooks/organizations/__init__.py +12 -0
- runbooks/organizations/manager.py +374 -0
- runbooks/security_baseline/README.md +324 -0
- runbooks/security_baseline/checklist/alternate_contacts.py +8 -1
- runbooks/security_baseline/checklist/bucket_public_access.py +4 -1
- runbooks/security_baseline/checklist/cloudwatch_alarm_configuration.py +9 -2
- runbooks/security_baseline/checklist/guardduty_enabled.py +9 -2
- runbooks/security_baseline/checklist/multi_region_instance_usage.py +5 -1
- runbooks/security_baseline/checklist/root_access_key.py +6 -1
- runbooks/security_baseline/config-origin.json +1 -1
- runbooks/security_baseline/config.json +1 -1
- runbooks/security_baseline/permission.json +1 -1
- runbooks/security_baseline/report_generator.py +10 -2
- runbooks/security_baseline/report_template_en.html +8 -8
- runbooks/security_baseline/report_template_jp.html +8 -8
- runbooks/security_baseline/report_template_kr.html +13 -13
- runbooks/security_baseline/report_template_vn.html +8 -8
- runbooks/security_baseline/requirements.txt +7 -0
- runbooks/security_baseline/run_script.py +8 -2
- runbooks/security_baseline/security_baseline_tester.py +10 -2
- runbooks/security_baseline/utils/common.py +5 -1
- runbooks/utils/__init__.py +204 -0
- runbooks-0.6.1.dist-info/METADATA +373 -0
- runbooks-0.6.1.dist-info/RECORD +237 -0
- {runbooks-0.2.3.dist-info → runbooks-0.6.1.dist-info}/WHEEL +1 -1
- runbooks-0.6.1.dist-info/entry_points.txt +7 -0
- runbooks-0.6.1.dist-info/licenses/LICENSE +201 -0
- runbooks-0.6.1.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.3.dist-info/METADATA +0 -435
- runbooks-0.2.3.dist-info/RECORD +0 -61
- runbooks-0.2.3.dist-info/entry_points.txt +0 -3
- runbooks-0.2.3.dist-info/top_level.txt +0 -1
@@ -0,0 +1,616 @@
|
|
1
|
+
import { DetachClassicLinkVpcCommand } from '@aws-sdk/client-ec2';
|
2
|
+
import { CloudFoundationAssessment, Task } from '../types';
|
3
|
+
import { Console } from 'node:console'
|
4
|
+
import { Transform } from 'node:stream'
|
5
|
+
import * as fs from 'fs';
|
6
|
+
|
7
|
+
const ts = new Transform({ transform(chunk, enc, cb) { cb(null, chunk) } })
|
8
|
+
const logger = new Console({ stdout: ts })
|
9
|
+
|
10
|
+
function getTable (data:any) {
|
11
|
+
logger.table(data)
|
12
|
+
return (ts.read() || '').toString()
|
13
|
+
}
|
14
|
+
|
15
|
+
async function createReport(assessment:CloudFoundationAssessment): Promise<Task[]> {
|
16
|
+
let tasks:Task[] = [];
|
17
|
+
let dateTime = new Date()
|
18
|
+
const reportFile = "./cfat.txt"
|
19
|
+
let report:string = "Cloud Foundation Assessment Tool"
|
20
|
+
report+=`\nGenerated on: ${dateTime.toUTCString()} \n\n`;
|
21
|
+
let score:number = 0;
|
22
|
+
let totalRequiredLoe:number = 0;
|
23
|
+
let totalScore:number= 0;
|
24
|
+
let cfatStatus:string = "COMPLETE";
|
25
|
+
if(assessment.cfatChecks && assessment.cfatChecks.length > 0){
|
26
|
+
report+= `\nIncomplete Requirements:`;
|
27
|
+
for (const check of assessment.cfatChecks) {
|
28
|
+
totalScore += check.weight;
|
29
|
+
if (check.required === true && check.status === 'incomplete') {
|
30
|
+
report+=`\n INCOMPLETE: ${check.check}`;
|
31
|
+
totalRequiredLoe += check.loe
|
32
|
+
cfatStatus = "INCOMPLETE";
|
33
|
+
}
|
34
|
+
if(check.status === 'complete'){
|
35
|
+
score += check.weight;
|
36
|
+
}
|
37
|
+
}
|
38
|
+
report+= `\n\n====================================\n`;
|
39
|
+
report+= `\nFoundation Status: ${cfatStatus}`;
|
40
|
+
if(cfatStatus === "INCOMPLETE"){
|
41
|
+
report+= `\nEstimate of Required Level of Effort (LOE): ${totalRequiredLoe} hours`;
|
42
|
+
}
|
43
|
+
report+= `\nCFAT Score: ${score} out of ${totalScore}`;
|
44
|
+
report+= `\n\n====================================\n`;
|
45
|
+
report+= `\nFoundation Checks:\n`;
|
46
|
+
if(assessment.cfatChecks && assessment.cfatChecks.length > 0){
|
47
|
+
const strTable = getTable(assessment.cfatChecks)
|
48
|
+
report+= `${strTable}`
|
49
|
+
}
|
50
|
+
}
|
51
|
+
report+= `\n\nStart Detailed Report:\n\n`;
|
52
|
+
report+=`\n*********************************************************`;
|
53
|
+
report+=`\n MANAGEMENT ACCOUNT`;
|
54
|
+
report+=`\n*********************************************************`;
|
55
|
+
report+=`\n\nAWS ACCOUNT TYPE\n`;
|
56
|
+
report+=`\n Is in AWS Organization: ${assessment.organizationDeploy}`;
|
57
|
+
report+=`\n Assessing AWS Management Account: ${assessment.managementAccount}`;
|
58
|
+
|
59
|
+
report+=`\n\nIAM USERS CHECK\n`;
|
60
|
+
if (assessment.iamUserChecks && assessment.iamUserChecks.length > 0) {
|
61
|
+
for(const iamUser of assessment.iamUserChecks){
|
62
|
+
report+=`\n IAM User: ${iamUser.userName}`;
|
63
|
+
if(iamUser.accessKeyId){
|
64
|
+
report+=`\n User API Key ID: ${iamUser.accessKeyId}`;
|
65
|
+
}
|
66
|
+
report+=`\n`;
|
67
|
+
}
|
68
|
+
} else {
|
69
|
+
report+=`\n No IAM Users found.`;
|
70
|
+
}
|
71
|
+
report+=`\n\nEC2 INSTANCE CHECK\n`;
|
72
|
+
if(assessment.ec2Checks && assessment.ec2Checks.find(param => param.ec2Found === true)){
|
73
|
+
for (const ec2 of assessment.ec2Checks ){
|
74
|
+
if(ec2.ec2Found){
|
75
|
+
report+=`\n ${ec2.region} - found EC2 Instance(s).`;
|
76
|
+
}
|
77
|
+
}
|
78
|
+
}else {
|
79
|
+
report+=`\n No EC2 instances found.`;
|
80
|
+
}
|
81
|
+
report+=`\n\nVPC CHECK\n`;
|
82
|
+
if(assessment.vpcChecks && assessment.vpcChecks.length >0){
|
83
|
+
for(const vpcFind of assessment.vpcChecks){
|
84
|
+
if(vpcFind.vpcFound){
|
85
|
+
report+=`\n ${vpcFind.region} - found VPC(s).`;
|
86
|
+
}
|
87
|
+
}
|
88
|
+
} else {
|
89
|
+
report+=`\n No VPCs found.`;
|
90
|
+
}
|
91
|
+
report+=`\n\nAWS CONFIG CHECK\n`;
|
92
|
+
if(assessment.configDetails && assessment.configDetails.find(param => param.configRecorderFound === true)){
|
93
|
+
for (const configFind of assessment.configDetails){
|
94
|
+
if(configFind.configRecorderFound){
|
95
|
+
report+=`\n ${configFind.region} - Config Recorder found`;
|
96
|
+
}
|
97
|
+
if(configFind.configDeliveryChannelFound){
|
98
|
+
report+=`\n ${configFind.region} - Config Delivery Channel found`;
|
99
|
+
}
|
100
|
+
}
|
101
|
+
} else{
|
102
|
+
report+=`\n No AWS Config resource discovered`;
|
103
|
+
}
|
104
|
+
report+=`\n\nMANAGEMENT ACCOUNT TASKS:`;
|
105
|
+
const maCategory:string = "Management Account"
|
106
|
+
if (assessment.iamUserChecks && assessment.iamUserChecks.length > 0) {
|
107
|
+
for(const iamUser of assessment.iamUserChecks){
|
108
|
+
let iamTask:Task={title:`Remove IAM user ${iamUser.userName}`, category: maCategory, detail: `Review and determine if IAM user ${iamUser.userName} can be deleted.`}
|
109
|
+
const message:string = `${iamTask.title} - ${iamTask.category} - ${iamTask.detail}`
|
110
|
+
tasks.push(iamTask);
|
111
|
+
report+=`\n ${ message }`;
|
112
|
+
if(iamUser.accessKeyId){
|
113
|
+
let iamApiTask:Task={title:`Remove IAM user ${iamUser.userName} API key ${iamUser.accessKeyId} `, category: maCategory, detail: `Review and determine if IAM user API key ${iamUser.accessKeyId} for ${iamUser.userName} can be removed.`}
|
114
|
+
const message:string = `${iamApiTask.title} - ${iamApiTask.category} - ${iamApiTask.detail}`
|
115
|
+
report+=`\n ${ message }`;
|
116
|
+
tasks.push(iamApiTask);
|
117
|
+
}
|
118
|
+
}
|
119
|
+
}
|
120
|
+
if(assessment.ec2Checks && assessment.ec2Checks.find(param => param.ec2Found === true)){
|
121
|
+
for (const ec2 of assessment.ec2Checks){
|
122
|
+
if(ec2.ec2Found && ec2.region){
|
123
|
+
let ec2Task:Task={title:`Delete EC2 instance in ${ec2.region}`, category: maCategory, detail: `Delete any unnecessary EC2 instance in ${ec2.region}`}
|
124
|
+
const message:string = `${ec2Task.title} - ${ec2Task.category} - ${ec2Task.detail}`
|
125
|
+
report+=`\n ${ message }`;
|
126
|
+
tasks.push(ec2Task);
|
127
|
+
}
|
128
|
+
}
|
129
|
+
}
|
130
|
+
if(assessment.vpcChecks && assessment.vpcChecks.length >0){
|
131
|
+
for(const vpcFind of assessment.vpcChecks){
|
132
|
+
if(vpcFind.vpcFound && vpcFind.region){
|
133
|
+
let vpcTask:Task={title:`Delete VPC in ${vpcFind.region}`, category: maCategory, detail: `Delete any unnecessary VPC in ${vpcFind.region} to include the default VPC.`}
|
134
|
+
const message:string = `${vpcTask.title} - ${vpcTask.category} - ${vpcTask.detail}`
|
135
|
+
report+=`\n ${ message }`;
|
136
|
+
tasks.push(vpcTask);
|
137
|
+
}
|
138
|
+
}
|
139
|
+
}
|
140
|
+
report+=`\n\n*********************************************************`;
|
141
|
+
report+=`\n GOVERNANCE`;
|
142
|
+
report+=`\n*********************************************************`;
|
143
|
+
report+=`\n\nAWS ORGANIZATION POLICY TYPES\n`;
|
144
|
+
report+=`\n Service Control Policies (SCP) enabled: ${assessment.scpEnabled}`;
|
145
|
+
report+=`\n Tag Policies enabled: ${assessment.tagPolicyEnabled}`;
|
146
|
+
report+=`\n Backup Policies enabled: ${assessment.backupPolicyEnabled}`;
|
147
|
+
report+=`\n\nAWS ORGANIZATION CLOUDFORMATION\n`;
|
148
|
+
report+=`\n AWS CloudFormation Organization stack sets status : ${assessment.orgCloudFormationStatus}`;
|
149
|
+
report+=`\n\nCLOUDTRAIL CHECK\n`;
|
150
|
+
if(assessment.cloudTrailDetails && assessment.cloudTrailDetails.length > 0) {
|
151
|
+
for(const ctFind of assessment.cloudTrailDetails){
|
152
|
+
if(ctFind.trailFound){
|
153
|
+
report+=`\n CloudTrail found in ${ctFind.region}`;
|
154
|
+
report+=`\n Is Organization Trail: ${ctFind.isOrgTrail}`;
|
155
|
+
report+=`\n Is MultiRegion: ${ctFind.isMultiRegion}`;
|
156
|
+
report+=`\n`;
|
157
|
+
}
|
158
|
+
}
|
159
|
+
}else {
|
160
|
+
report+=`\n No AWS CloudTrail resource discovered`;
|
161
|
+
}
|
162
|
+
report+=`\n\nGOVERNANCE SERVICES ENABLED IN AWS ORGANIZATION:\n`;
|
163
|
+
if(assessment.orgServices){
|
164
|
+
if(assessment.orgServices.find(param=> param.service === 'cloudtrail.amazonaws.com')){
|
165
|
+
report+=`\n AWS CloudTrail`;
|
166
|
+
}
|
167
|
+
if(assessment.orgServices.find(param=> param.service === 'config.amazonaws.com')){
|
168
|
+
report+=`\n AWS Config`;
|
169
|
+
}
|
170
|
+
}else{
|
171
|
+
report+=`\n No governance service enabled`;
|
172
|
+
}
|
173
|
+
|
174
|
+
///// SET THE BACKLOG TASK FOR GOVERNANCE /////
|
175
|
+
report+=`\n\nGOVERNANCE TASKS:`;
|
176
|
+
const govCategory:string = "Governance"
|
177
|
+
if(!assessment.orgServices || !assessment.orgServices.find(param=> param.service === 'cloudtrail.amazonaws.com')){
|
178
|
+
const ctOrgServiceTask:Task = {title:'Enable AWS CloudTrail', category: govCategory, detail: `Enable AWS CloudTrail in AWS Organization`}
|
179
|
+
tasks.push(ctOrgServiceTask);
|
180
|
+
const message:string = `${ctOrgServiceTask.title} - ${ctOrgServiceTask.category} - ${ctOrgServiceTask.detail}`
|
181
|
+
report+=`\n ${message}`;
|
182
|
+
}
|
183
|
+
if(!assessment.orgServices || !assessment.orgServices.find(param=> param.service === 'config.amazonaws.com')){
|
184
|
+
const configOrgServiceTask:Task = {title: 'Enable AWS Config', category: govCategory, detail: `Enable AWS Config in AWS Organization`}
|
185
|
+
tasks.push(configOrgServiceTask);
|
186
|
+
const message:string = `${configOrgServiceTask.title} - ${configOrgServiceTask.category} - ${configOrgServiceTask.detail}`
|
187
|
+
report+=`\n ${message}`;
|
188
|
+
}
|
189
|
+
if(!assessment.scpEnabled) {
|
190
|
+
const scpEnabledTask:Task = {title: 'Enable SCP', category: govCategory, detail: `Enable SCP in AWS Organization`}
|
191
|
+
tasks.push(scpEnabledTask);
|
192
|
+
const message:string = `${scpEnabledTask.title} - ${scpEnabledTask.category} - ${scpEnabledTask.detail}`
|
193
|
+
report+=`\n ${message}`;
|
194
|
+
|
195
|
+
}
|
196
|
+
if(!assessment.tagPolicyEnabled) {
|
197
|
+
let tagPolicyEnabledTask:Task = {title: 'Enable Tag Policy', category: govCategory, detail: `Enable Tag Policy in AWS Organization`}
|
198
|
+
tasks.push(tagPolicyEnabledTask);
|
199
|
+
const message:string = `${tagPolicyEnabledTask.title} - ${tagPolicyEnabledTask.category} - ${tagPolicyEnabledTask.detail}`
|
200
|
+
report+=`\n ${message}`;
|
201
|
+
}
|
202
|
+
if(!assessment.backupPolicyEnabled) {
|
203
|
+
let backupPolicyEnabledTask:Task = {title: 'Enable Backup Policy', category: govCategory, detail: `Enable Backup Policy in AWS Organization`}
|
204
|
+
tasks.push(backupPolicyEnabledTask);
|
205
|
+
const message:string = `${backupPolicyEnabledTask.title} - ${backupPolicyEnabledTask.category} - ${backupPolicyEnabledTask.detail}`
|
206
|
+
report+=`\n ${message}`;
|
207
|
+
}
|
208
|
+
report+=`\n\n*********************************************************`;
|
209
|
+
report+=`\n FINANCIAL MANAGEMENT`;
|
210
|
+
report+=`\n*********************************************************`;
|
211
|
+
report+=`\n\nLegacy CUR`;
|
212
|
+
report+=`\n Is legacy CUR setup: ${assessment.isLegacyCurSetup}`;
|
213
|
+
report+=`\n\nCLOUD FINANCIAL MANAGEMENT TASKS:`;
|
214
|
+
const finCategory:string = "Cloud Financial Management"
|
215
|
+
if(!assessment.isLegacyCurSetup){
|
216
|
+
const legacyCurSetupTask:Task={title:'Setup legacy CUR', category: finCategory, detail: `Setup legacy CUR in AWS Organization`}
|
217
|
+
tasks.push(legacyCurSetupTask);
|
218
|
+
const message:string = `${legacyCurSetupTask.title} - ${legacyCurSetupTask.category} - ${legacyCurSetupTask.detail}`
|
219
|
+
report+=`\n ${message}`;
|
220
|
+
}
|
221
|
+
report+=`\n\n*********************************************************`;
|
222
|
+
report+=`\n MULTI-ACCOUNT STRATEGY`;
|
223
|
+
report+=`\n*********************************************************`;
|
224
|
+
report+=`\n\nAWS ORGANIZATION DETAILS\n`;
|
225
|
+
report+=`\n AWS Organization Id: ${assessment.orgId}`;
|
226
|
+
report+=`\n AWS Organization ARN: ${assessment.orgArn}`;
|
227
|
+
report+=`\n AWS Organization Root OU Id: ${assessment.orgRootOuId}`;
|
228
|
+
report+=`\n\nAWS ORGANIZATION CLOUDFORMATION\n`;
|
229
|
+
report+=`\n AWS CloudFormation Organization stack sets status : ${assessment.orgCloudFormationStatus}`;
|
230
|
+
let transitionalFound,suspendedFound,infrastructureFound:boolean = false;
|
231
|
+
let workloadsFound:boolean = false;
|
232
|
+
let securityFound:boolean = false;
|
233
|
+
if(assessment.orgRootOuId){
|
234
|
+
report+=`\n\nAWS ORGANIZATION TOP-LEVEL ORGANIZATION UNITS\n`;
|
235
|
+
report+=`\n List of Organization's top-level OUs and AWS accounts:`;
|
236
|
+
if(assessment.orgOuInfo && assessment.orgOuInfo.length > 0){
|
237
|
+
for (const ou of assessment.orgOuInfo){
|
238
|
+
if(ou.name?.toLowerCase() === 'suspended'){suspendedFound = true}
|
239
|
+
if(ou.name?.toLowerCase() === 'transitional'){transitionalFound = true}
|
240
|
+
if(ou.name?.toLowerCase() === 'workloads'){workloadsFound=true}
|
241
|
+
if(ou.name?.toLowerCase() === 'security'){securityFound=true}
|
242
|
+
if(ou.name?.toLowerCase() === 'infrastructure'){infrastructureFound=true}
|
243
|
+
report+=`\n Organizational Unit: ${ou.name}`;
|
244
|
+
report+=`\n Organizational Unit Id: ${ou.id}`;
|
245
|
+
if(ou.accounts && ou.accounts.length > 0){
|
246
|
+
report+=`\n AWS Accounts:`;
|
247
|
+
for (const account of ou.accounts){
|
248
|
+
report+=`\n ${account.Name}`;
|
249
|
+
}
|
250
|
+
report+=`\n`;
|
251
|
+
}
|
252
|
+
else{
|
253
|
+
report+=`\n AWS Accounts: None`;
|
254
|
+
report+=`\n`;
|
255
|
+
}
|
256
|
+
}
|
257
|
+
|
258
|
+
} else {
|
259
|
+
report+=`\n No top level OUs found.`;
|
260
|
+
}
|
261
|
+
}
|
262
|
+
report+=`\n\nAWS ORGANIZATION MEMBER ACCOUNTS\n`;
|
263
|
+
if(assessment.orgMemberAccounts && assessment.orgMemberAccounts.length > 0){
|
264
|
+
for (const memberAccount of assessment.orgMemberAccounts){
|
265
|
+
report+=`\n Account: ${memberAccount.accountName}`;
|
266
|
+
report+=`\n Account Email: ${memberAccount.accountEmail}\n`;
|
267
|
+
}
|
268
|
+
} else {
|
269
|
+
report+=`No member accounts found which is amazing as this is running from one.`;
|
270
|
+
}
|
271
|
+
report+=`\n\nAWS ORGANIZATION ENABLED SERVICES\n`;
|
272
|
+
report+=`\n The following AWS Services are enabled within your AWS Organization:`;
|
273
|
+
if(assessment.orgServices && assessment.orgServices.length > 0){
|
274
|
+
for (const orgService of assessment.orgServices){
|
275
|
+
report+=`\n ${orgService.service}`;
|
276
|
+
}
|
277
|
+
} else{
|
278
|
+
report+=`\n No trusted access enabled in the AWS Organization`;
|
279
|
+
}
|
280
|
+
let identityDelegated:boolean = false
|
281
|
+
let securityHubDelegated:boolean = false
|
282
|
+
let guardDutyDelegated:boolean = false
|
283
|
+
let configDelegated:boolean = false
|
284
|
+
let iamAccessAnalyzerDelegated:boolean = false
|
285
|
+
let s3StorageLensDelegated:boolean = false
|
286
|
+
let ipamDelegated:boolean = false
|
287
|
+
let accountDelegated:boolean = false
|
288
|
+
let backupDelegated:boolean = false
|
289
|
+
report+=`\n\nAWS ORGANIZATION INTEGRATED SERVICE REGISTERED DELEGATED ADMINS\n`;
|
290
|
+
if(assessment.orgDelegatedAdminAccounts && assessment.orgDelegatedAdminAccounts.length > 0){
|
291
|
+
for (const account of assessment.orgDelegatedAdminAccounts){
|
292
|
+
report+=`\n Account: ${account.accountName}`;
|
293
|
+
if(account.services && account.services.length > 0 ){
|
294
|
+
report+=`\n Delegated Services:`;
|
295
|
+
for (const srv of account.services){
|
296
|
+
report+=`\n ${srv.ServicePrincipal}`;
|
297
|
+
if(srv.ServicePrincipal === 'securityhub.amazonaws.com'){securityHubDelegated=true}
|
298
|
+
if(srv.ServicePrincipal === 'guardduty.amazonaws.com'){guardDutyDelegated=true}
|
299
|
+
if(srv.ServicePrincipal === 'sso.amazonaws.com'){identityDelegated=true}
|
300
|
+
if(srv.ServicePrincipal === 'config.amazonaws.com'){configDelegated=true}
|
301
|
+
if(srv.ServicePrincipal === 'access-analyzer.amazonaws.com'){iamAccessAnalyzerDelegated=true}
|
302
|
+
if(srv.ServicePrincipal === 'storage-lens.s3.amazonaws.com'){s3StorageLensDelegated=true}
|
303
|
+
if(srv.ServicePrincipal === 'ipam.amazonaws.com'){ipamDelegated=true}
|
304
|
+
if(srv.ServicePrincipal === 'account.amazonaws.com'){accountDelegated=true}
|
305
|
+
if(srv.ServicePrincipal === 'backup.amazonaws.com'){backupDelegated=true}
|
306
|
+
}
|
307
|
+
}
|
308
|
+
report+=`\n `;
|
309
|
+
}
|
310
|
+
} else {
|
311
|
+
report+=`\n No delegated admin accounts in AWS Organization`;
|
312
|
+
}
|
313
|
+
report+=`\n\nMULTI-ACCOUNT STRATEGY TASKS:`;
|
314
|
+
let masCategory:string = 'Multi-Account Strategy';
|
315
|
+
const accountEmailReviewTask:Task = {title: 'Review Account Email Addresses', category: masCategory, detail: `Review Account Email Addresses in AWS Organization`}
|
316
|
+
const message:string = `${accountEmailReviewTask.title} - ${accountEmailReviewTask.category} - ${accountEmailReviewTask.detail}`
|
317
|
+
report+=`\n ${message}`;
|
318
|
+
if(!assessment.scpEnabled) {
|
319
|
+
const scpEnabledTask:Task = {title: 'Enable Service Control Policy', category: masCategory, detail: `Enable Service Control Policy in AWS Organization`}
|
320
|
+
tasks.push(scpEnabledTask);
|
321
|
+
const message:string = `${scpEnabledTask.title} - ${scpEnabledTask.category} - ${scpEnabledTask.detail}`
|
322
|
+
report+=`\n ${message}`;
|
323
|
+
}
|
324
|
+
if(!transitionalFound){
|
325
|
+
const transitionalTask:Task = {title: 'Deploy Transitional OU', category: masCategory, detail: `Deploy Transitional OU in AWS Organization`}
|
326
|
+
tasks.push(transitionalTask);
|
327
|
+
const message:string = `${transitionalTask.title} - ${transitionalTask.category} - ${transitionalTask.detail}`
|
328
|
+
report+=`\n ${message}`;
|
329
|
+
}
|
330
|
+
if(!suspendedFound){
|
331
|
+
const suspendedTask:Task = {title: 'Deploy Suspended OU', category: masCategory, detail: `Deploy Suspended OU in AWS Organization`}
|
332
|
+
tasks.push(suspendedTask);
|
333
|
+
const message:string = `${suspendedTask.title} - ${suspendedTask.category} - ${suspendedTask.detail}`
|
334
|
+
report+=`\n ${message}`;
|
335
|
+
}
|
336
|
+
if(!workloadsFound){
|
337
|
+
const workloadsTask:Task = {title: 'Deploy Workloads OU', category: masCategory, detail: `Deploy Workloads OU in AWS Organization`}
|
338
|
+
tasks.push(workloadsTask);
|
339
|
+
const message:string = `${workloadsTask.title} - ${workloadsTask.category} - ${workloadsTask.detail}`
|
340
|
+
report+=`\n ${message}`;
|
341
|
+
}
|
342
|
+
if(!securityFound){
|
343
|
+
const securityTask:Task = {title: 'Deploy Security OU', category: masCategory, detail: `Deploy Security OU in AWS Organization`}
|
344
|
+
tasks.push(securityTask);
|
345
|
+
const message:string = `${securityTask.title} - ${securityTask.category} - ${securityTask.detail}`
|
346
|
+
report+=`\n ${message}`;
|
347
|
+
}
|
348
|
+
if(!infrastructureFound){
|
349
|
+
const infrastructureTask:Task = {title: 'Deploy Infrastructure OU', category: masCategory, detail: `Deploy Infrastructure OU in AWS Organization`}
|
350
|
+
tasks.push(infrastructureTask);
|
351
|
+
const message:string = `${infrastructureTask.title} - ${infrastructureTask.category} - ${infrastructureTask.detail}`
|
352
|
+
report+=`\n ${message}`;
|
353
|
+
}
|
354
|
+
|
355
|
+
report+=`\n\n*********************************************************`;
|
356
|
+
report+=`\n LANDING ZONE`;
|
357
|
+
report+=`\n*********************************************************`;
|
358
|
+
report+=`\n\nAWS CONTROL TOWER\n`;
|
359
|
+
if(assessment.controlTowerRegion){
|
360
|
+
report+=`\n Control Tower home region: ${assessment.controlTowerRegion}`;
|
361
|
+
report+=`\n Control Tower status: ${assessment.controlTowerStatus}`;
|
362
|
+
report+=`\n Control Tower Landing Zone version: ${assessment.controlTowerDeployedVersion}`;
|
363
|
+
report+=`\n Latest available version: ${assessment.controlTowerLatestAvailableVersion}`;
|
364
|
+
report+=`\n Drift Status: ${assessment.controlTowerDriftStatus}`;
|
365
|
+
}else {
|
366
|
+
report+=`\n AWS Control Tower is not deployed in the AWS Organization`;
|
367
|
+
}
|
368
|
+
report+=`\n\nLANDING ZONE TASKS:`;
|
369
|
+
let lzTaskNumber: number = 1
|
370
|
+
const lzWaypoint:string = "Landing Zone"
|
371
|
+
if(assessment.controlTowerRegion === undefined){
|
372
|
+
const deployControlTowerTask:Task = {title: 'Deploy AWS Control Tower', category: lzWaypoint, detail: `Deploy AWS Control Tower in AWS Organization`}
|
373
|
+
tasks.push(deployControlTowerTask);
|
374
|
+
const message:string = `${deployControlTowerTask.title} - ${deployControlTowerTask.category} - ${deployControlTowerTask.detail}`
|
375
|
+
report+=`\n ${message}`;
|
376
|
+
}
|
377
|
+
if(assessment.controlTowerDriftStatus === 'DRIFTED'){
|
378
|
+
const fixLzDriftTask:Task = {title: 'Fix drift in deployed landing zone', category: lzWaypoint, detail: `Fix drift in deployed landing zone`}
|
379
|
+
tasks.push(fixLzDriftTask);
|
380
|
+
const message:string = `${fixLzDriftTask.title} - ${fixLzDriftTask.category} - ${fixLzDriftTask.detail}`
|
381
|
+
report+=`\n ${message}`;
|
382
|
+
}
|
383
|
+
if(assessment.controlTowerDeployedVersion !== assessment.controlTowerLatestAvailableVersion){
|
384
|
+
const updateControlTowerTask:Task = {title: `Update AWS Control Tower to latest version`, category: lzWaypoint, detail: `Update AWS Control Tower to version ${assessment.controlTowerLatestAvailableVersion}`}
|
385
|
+
tasks.push(updateControlTowerTask);
|
386
|
+
const message:string = `${updateControlTowerTask.title} - ${updateControlTowerTask.category} - ${updateControlTowerTask.detail}`
|
387
|
+
report+=`\n ${message}`;
|
388
|
+
}
|
389
|
+
if(!assessment.orgServices || !assessment.orgServices.find(param=> param.service === 'member.org.stacksets.cloudformation.amazonaws.com')){
|
390
|
+
const orgServiceCfnEnableTask:Task = {title: 'Enable AWS CloudFormation', category: lzWaypoint, detail: `Enable AWS CloudFormation in AWS Organization`}
|
391
|
+
tasks.push(orgServiceCfnEnableTask);
|
392
|
+
const message:string = `${orgServiceCfnEnableTask.title} - ${orgServiceCfnEnableTask.category} - ${orgServiceCfnEnableTask.detail}`
|
393
|
+
report+=`\n ${message}`;
|
394
|
+
}
|
395
|
+
report+=`\n\n*********************************************************`;
|
396
|
+
report+=`\n IDENTITY`;
|
397
|
+
report+=`\n*********************************************************`;
|
398
|
+
if(assessment.idcInfo){
|
399
|
+
report+=`\n\nAWS IAM IDENTITY CENTER\n`;
|
400
|
+
report+=`\n IdC Region: ${assessment.idcInfo.region}`;
|
401
|
+
report+=`\n IdC ARN: ${assessment.idcInfo.arn}`;
|
402
|
+
report+=`\n IdC Instance Id: ${assessment.idcInfo.id}`;
|
403
|
+
}else{
|
404
|
+
report+=`\n\nAWS IAM IDENTITY CENTER NOT FOUND\n`;
|
405
|
+
}
|
406
|
+
report+=`\n\nIDENTITY TASKS:`;
|
407
|
+
const ssoCategory:string = 'Identity'
|
408
|
+
|
409
|
+
if(!assessment.orgServices || !assessment.orgServices.find(param=> param.service === 'sso.amazonaws.com')){
|
410
|
+
const ssoTask:Task = {title: 'Enable AWS Single Sign-On', category: ssoCategory, detail: `Enable AWS Single Sign-On in AWS Organization`}
|
411
|
+
tasks.push(ssoTask);
|
412
|
+
const message:string = `${ssoTask.title} - ${ssoTask.category} - ${ssoTask.detail}`
|
413
|
+
report+=`\n ${message}`;
|
414
|
+
}
|
415
|
+
if(!identityDelegated){
|
416
|
+
const identityDelegatedTask:Task = {title: 'Delegate administration to AWS IAM Identity Center', category: ssoCategory, detail: `Delegate administration to AWS IAM Identity Center`}
|
417
|
+
tasks.push(identityDelegatedTask);
|
418
|
+
const message:string = `${identityDelegatedTask.title} - ${identityDelegatedTask.category} - ${identityDelegatedTask.detail}`
|
419
|
+
report+=`\n ${message}`;
|
420
|
+
}
|
421
|
+
if(!assessment.scpEnabled) {
|
422
|
+
const ssoTask:Task = {title: 'Enable AWS Single Sign-On', category: ssoCategory, detail: `Enable AWS Single Sign-On in AWS Organization`}
|
423
|
+
tasks.push(ssoTask);
|
424
|
+
const message:string = `${ssoTask.title} - ${ssoTask.category} - ${ssoTask.detail}`
|
425
|
+
report+=`\n ${message}`;
|
426
|
+
}
|
427
|
+
report+=`\n\n*********************************************************`;
|
428
|
+
report+=`\n SECURITY`;
|
429
|
+
report+=`\n*********************************************************`;
|
430
|
+
report+=`\n\nAWS SECURITY SERVICES ENABLED IN AWS ORGANIZATION:\n`;
|
431
|
+
if(assessment.orgServices && assessment.orgServices.find(param=> param.service === 'guardduty.amazonaws.com')){
|
432
|
+
report+=`\n AWS GuardDuty`;
|
433
|
+
}
|
434
|
+
if(assessment.orgServices && assessment.orgServices.find(param=> param.service === 'securityhub.amazonaws.com')){
|
435
|
+
report+=`\n AWS Security Hub`;
|
436
|
+
}
|
437
|
+
if(assessment.orgServices && assessment.orgServices.find(param=> param.service === 'access-analyzer.amazonaws.com')){
|
438
|
+
report+=`\n IAM Access Analyzer`;
|
439
|
+
}
|
440
|
+
if(assessment.orgServices && assessment.orgServices.find(param=> param.service === 'macie.amazonaws.com')){
|
441
|
+
report+=`\n Macie`;
|
442
|
+
}
|
443
|
+
if(assessment.orgServices && assessment.orgServices.find(param=> param.service === 'storage-lens.s3.amazonaws.com')){
|
444
|
+
report+=`\n Amazon S3 Storage Lens`;
|
445
|
+
}
|
446
|
+
if(assessment.orgServices && assessment.orgServices.find(param=> param.service === 'inspector2.amazonaws.com')){
|
447
|
+
report+=`\n Amazon Inspector`;
|
448
|
+
}
|
449
|
+
if(assessment.orgServices && assessment.orgServices.find(param=> param.service === 'cloudtrail.amazonaws.com')){
|
450
|
+
report+=`\n AWS CloudTrail`;
|
451
|
+
}
|
452
|
+
if(assessment.orgServices && assessment.orgServices.find(param=> param.service === 'config.amazonaws.com')){
|
453
|
+
report+=`\n AWS Config`;
|
454
|
+
}
|
455
|
+
report+=`\n\nSECURITY TASKS:`;
|
456
|
+
const secCategory:string = "Security"
|
457
|
+
if(!assessment.scpEnabled) {
|
458
|
+
const ssoTask:Task = {title: 'Enable AWS Single Sign-On', category: secCategory, detail: `Enable AWS Single Sign-On in AWS Organization`}
|
459
|
+
tasks.push(ssoTask);
|
460
|
+
const message:string = `${ssoTask.title} - ${ssoTask.category} - ${ssoTask.detail}`
|
461
|
+
report+=`\n ${message}`;
|
462
|
+
}
|
463
|
+
if(!assessment.orgServices || !assessment.orgServices.find(param=> param.service === 'guardduty.amazonaws.com')){
|
464
|
+
const taskGuardDutyDelegated:Task = {title: 'Delegate administration to AWS GuardDuty', category: secCategory, detail: `Delegate administration to AWS GuardDuty`}
|
465
|
+
tasks.push(taskGuardDutyDelegated);
|
466
|
+
const message:string = `${taskGuardDutyDelegated.title} - ${taskGuardDutyDelegated.category} - ${taskGuardDutyDelegated.detail}`
|
467
|
+
report+=`\n ${message}`;
|
468
|
+
}
|
469
|
+
if(!assessment.orgServices || !assessment.orgServices.find(param=> param.service === 'securityhub.amazonaws.com')){
|
470
|
+
const taskSecurityHubDelegated:Task = {title: 'Delegate administration to AWS Security Hub', category: secCategory, detail: `Delegate administration to AWS Security Hub`}
|
471
|
+
tasks.push(taskSecurityHubDelegated);
|
472
|
+
const message:string = `${taskSecurityHubDelegated.title} - ${taskSecurityHubDelegated.category} - ${taskSecurityHubDelegated.detail}`
|
473
|
+
report+=`\n ${message}`;
|
474
|
+
}
|
475
|
+
|
476
|
+
if(!assessment.orgServices || !assessment.orgServices.find(param=> param.service === 'access-analyzer.amazonaws.com')){
|
477
|
+
const taskIamAccessAnalyzerDelegated:Task = {title: 'Delegate administration to AWS IAM Access Analyzer', category: secCategory, detail: `Delegate administration to AWS IAM Access Analyzer`}
|
478
|
+
tasks.push(taskIamAccessAnalyzerDelegated);
|
479
|
+
const message:string = `${taskIamAccessAnalyzerDelegated.title} - ${taskIamAccessAnalyzerDelegated.category} - ${taskIamAccessAnalyzerDelegated.detail}`
|
480
|
+
report+=`\n ${message}`;
|
481
|
+
}
|
482
|
+
if(!assessment.orgServices || !assessment.orgServices.find(param=> param.service === 'cloudtrail.amazonaws.com')){
|
483
|
+
const taskCloudTrailDelegated:Task = {title: 'Delegate administration to AWS CloudTrail', category: secCategory, detail: `Delegate administration to AWS CloudTrail`}
|
484
|
+
tasks.push(taskCloudTrailDelegated);
|
485
|
+
const message:string = `${taskCloudTrailDelegated.title} - ${taskCloudTrailDelegated.category} - ${taskCloudTrailDelegated.detail}`
|
486
|
+
report+=`\n ${message}`;
|
487
|
+
}
|
488
|
+
if(!assessment.orgServices || !assessment.orgServices.find(param=> param.service === 'config.amazonaws.com')){
|
489
|
+
const taskConfigDelegated:Task = {title: 'Delegate administration to AWS Config', category: secCategory, detail: `Delegate administration to AWS Config`}
|
490
|
+
tasks.push(taskConfigDelegated);
|
491
|
+
const message:string = `${taskConfigDelegated.title} - ${taskConfigDelegated.category} - ${taskConfigDelegated.detail}`
|
492
|
+
report+=`\n ${message}`;
|
493
|
+
}
|
494
|
+
if(!securityHubDelegated){
|
495
|
+
const taskSecurityHubDelegated:Task = {title: 'Delegate administration of AWS Security Hub', category: secCategory, detail: `Delegate administration to AWS Security Hub`}
|
496
|
+
tasks.push(taskSecurityHubDelegated);
|
497
|
+
const message:string = `${taskSecurityHubDelegated.title} - ${taskSecurityHubDelegated.category} - ${taskSecurityHubDelegated.detail}`
|
498
|
+
report+=`\n ${message}`;
|
499
|
+
}
|
500
|
+
if(!guardDutyDelegated){
|
501
|
+
const taskGuardDutyDelegated:Task = {title: 'Delegate administration of AWS GuardDuty', category: secCategory, detail: `Delegate administration to AWS GuardDuty`}
|
502
|
+
tasks.push(taskGuardDutyDelegated);
|
503
|
+
const message:string = `${taskGuardDutyDelegated.title} - ${taskGuardDutyDelegated.category} - ${taskGuardDutyDelegated.detail}`
|
504
|
+
report+=`\n ${message}`;
|
505
|
+
}
|
506
|
+
if(!configDelegated){
|
507
|
+
const taskConfigDelegated:Task = {title: 'Delegate administration of AWS Config', category: secCategory, detail: `Delegate administration to AWS Config`}
|
508
|
+
tasks.push(taskConfigDelegated);
|
509
|
+
const message:string = `${taskConfigDelegated.title} - ${taskConfigDelegated.category} - ${taskConfigDelegated.detail}`
|
510
|
+
report+=`\n ${message}`;
|
511
|
+
}
|
512
|
+
if(!iamAccessAnalyzerDelegated){
|
513
|
+
const taskIamAccessAnalyzerDelegated:Task = {title: 'Delegate administration of AWS IAM Access Analyzer', category: secCategory, detail: `Delegate administration to AWS IAM Access Analyzer`}
|
514
|
+
tasks.push(taskIamAccessAnalyzerDelegated);
|
515
|
+
const message:string = `${taskIamAccessAnalyzerDelegated.title} - ${taskIamAccessAnalyzerDelegated.category} - ${taskIamAccessAnalyzerDelegated.detail}`
|
516
|
+
report+=`\n ${message}`;
|
517
|
+
}
|
518
|
+
if(!s3StorageLensDelegated){
|
519
|
+
const taskS3StorageLensDelegated:Task = {title: 'Delegate administration of Amazon S3 Storage Lens', category: secCategory, detail: `Delegate administration to Amazon S3 Storage Lens`}
|
520
|
+
tasks.push(taskS3StorageLensDelegated);
|
521
|
+
const message:string = `${taskS3StorageLensDelegated.title} - ${taskS3StorageLensDelegated.category} - ${taskS3StorageLensDelegated.detail}`
|
522
|
+
report+=`\n ${message}`;
|
523
|
+
}
|
524
|
+
report+=`\n\n*********************************************************`;
|
525
|
+
report+=`\n NETWORK`;
|
526
|
+
report+=`\n*********************************************************`;
|
527
|
+
|
528
|
+
report+=`\n\nNETWORK TASKS:`;
|
529
|
+
const networkCategory:string = 'Network'
|
530
|
+
if(!assessment.orgServices || !assessment.orgServices.find(param=> param.service === 'guardduty.amazonaws.com')){
|
531
|
+
const taskGuardDutyDelegated:Task = {title: 'Enable AWS GuardDuty', category: networkCategory, detail: `Enable AWS GuardDuty in AWS Organization`}
|
532
|
+
tasks.push(taskGuardDutyDelegated);
|
533
|
+
const message:string = `${taskGuardDutyDelegated.title} - ${taskGuardDutyDelegated.category} - ${taskGuardDutyDelegated.detail}`
|
534
|
+
report+=`\n ${message}`;
|
535
|
+
}
|
536
|
+
if(!assessment.orgServices || !assessment.orgServices.find(param=> param.service === 'ipam.amazonaws.com')){
|
537
|
+
const orgServiceIpamTask:Task={title: 'Enable AWS IPAM', category: networkCategory, detail: `Enable AWS IPAM in AWS Organization`}
|
538
|
+
tasks.push(orgServiceIpamTask);
|
539
|
+
const message:string = `${orgServiceIpamTask.title} - ${orgServiceIpamTask.category} - ${orgServiceIpamTask.detail}`
|
540
|
+
report+=`\n ${message}`;
|
541
|
+
}
|
542
|
+
if(!assessment.orgServices || !assessment.orgServices.find(param=> param.service === 'ram.amazonaws.com')){
|
543
|
+
const orgServiceRamTask:Task={title: 'Enable AWS Resource Access Manager', category: networkCategory, detail: `Enable AWS Resource Access Manager in AWS Organization`}
|
544
|
+
tasks.push(orgServiceRamTask);
|
545
|
+
const message:string = `${orgServiceRamTask.title} - ${orgServiceRamTask.category} - ${orgServiceRamTask.detail}`
|
546
|
+
report+=`\n ${message}`;
|
547
|
+
}
|
548
|
+
if(!ipamDelegated){
|
549
|
+
const taskIpamDelegated:Task = {title: 'Delegate administration of AWS IPAM', category: networkCategory, detail: `Delegate administration to AWS IPAM`}
|
550
|
+
tasks.push(taskIpamDelegated);
|
551
|
+
const message:string = `${taskIpamDelegated.title} - ${taskIpamDelegated.category} - ${taskIpamDelegated.detail}`
|
552
|
+
report+=`\n ${message}`;
|
553
|
+
}
|
554
|
+
if(!assessment.scpEnabled) {
|
555
|
+
const taskScpDelegated:Task = {title: 'Enable AWS Service Control Policy', category: networkCategory, detail: `Enable AWS Service Control Policy in AWS Organization`}
|
556
|
+
tasks.push(taskScpDelegated);
|
557
|
+
const message:string = `${taskScpDelegated.title} - ${taskScpDelegated.category} - ${taskScpDelegated.detail}`
|
558
|
+
report+=`\n ${message}`;
|
559
|
+
}
|
560
|
+
report+=`\n\n*********************************************************`;
|
561
|
+
report+=`\n OBSERVABILITY`;
|
562
|
+
report+=`\n*********************************************************`;
|
563
|
+
|
564
|
+
report+=`\n\nOBSERVABILITY TASKS:`;
|
565
|
+
const obCategory:string = 'Observability'
|
566
|
+
if(!assessment.orgServices || !assessment.orgServices.find(param=> param.service === 'account.amazonaws.com')){
|
567
|
+
const orgServiceAccountTask:Task={title: 'Enable AWS Account', category: obCategory, detail: `Enable AWS Account in AWS Organization`}
|
568
|
+
tasks.push(orgServiceAccountTask);
|
569
|
+
const message:string = `${orgServiceAccountTask.title} - ${orgServiceAccountTask.category} - ${orgServiceAccountTask.detail}`
|
570
|
+
report+=`\n ${message}`;
|
571
|
+
}
|
572
|
+
if(!accountDelegated){
|
573
|
+
const taskAccountDelegated:Task = {title: 'Delegate administration of AWS Account', category: obCategory, detail: `Delegate administration to AWS Account`}
|
574
|
+
tasks.push(taskAccountDelegated);
|
575
|
+
const message:string = `${taskAccountDelegated.title} - ${taskAccountDelegated.category} - ${taskAccountDelegated.detail}`
|
576
|
+
report+=`\n ${message}`;
|
577
|
+
}
|
578
|
+
report+=`\n\n*********************************************************`;
|
579
|
+
report+=`\n BACKUP AND RECOVERY`;
|
580
|
+
report+=`\n*********************************************************`;
|
581
|
+
report+=`\n\nBACKUP AND RECOVERY TASKS:`;
|
582
|
+
const backupWaypoint:string = 'Backup and Recovery'
|
583
|
+
if(!assessment.orgServices || !assessment.orgServices.find(param=> param.service === 'backup.amazonaws.com')){
|
584
|
+
const orgServiceBackupTask:Task={title: 'Enable AWS Backup', category: backupWaypoint, detail: `Enable AWS Backup in AWS Organization`}
|
585
|
+
tasks.push(orgServiceBackupTask);
|
586
|
+
const message:string = `${orgServiceBackupTask.title} - ${orgServiceBackupTask.category} - ${orgServiceBackupTask.detail}`
|
587
|
+
report+=`\n ${message}`;
|
588
|
+
}
|
589
|
+
if(!backupDelegated){
|
590
|
+
const taskBackupDelegated:Task = {title: 'Delegate administration of AWS Backup', category: backupWaypoint, detail: `Delegate administration to AWS Backup`}
|
591
|
+
tasks.push(taskBackupDelegated);
|
592
|
+
const message:string = `${taskBackupDelegated.title} - ${taskBackupDelegated.category} - ${taskBackupDelegated.detail}`
|
593
|
+
report+=`\n ${message}`;
|
594
|
+
}
|
595
|
+
if(!assessment.backupPolicyEnabled) {
|
596
|
+
const backupPolicyEnabledTask:Task = {title: 'Enable AWS Backup Policy', category: backupWaypoint, detail: `Enable AWS Backup Policy in AWS Organization`}
|
597
|
+
tasks.push(backupPolicyEnabledTask);
|
598
|
+
const message:string = `${backupPolicyEnabledTask.title} - ${backupPolicyEnabledTask.category} - ${backupPolicyEnabledTask.detail}`
|
599
|
+
report+=`\n ${message}`;
|
600
|
+
}
|
601
|
+
if(!assessment.scpEnabled) {
|
602
|
+
const enablePolicyTypeTask:Task = {title: 'Enable AWS Service Control Policy', category: backupWaypoint, detail: `Enable AWS Service Control Policy in AWS Organization`}
|
603
|
+
tasks.push(enablePolicyTypeTask);
|
604
|
+
const message:string = `${enablePolicyTypeTask.title} - ${enablePolicyTypeTask.category} - ${enablePolicyTypeTask.detail}`
|
605
|
+
report+=`\n ${message}`;
|
606
|
+
}
|
607
|
+
report+=`\n\n\n END REVIEW`;
|
608
|
+
const reportFilePath:string = "./cfat.txt"
|
609
|
+
console.log(`compiling report...`)
|
610
|
+
console.log(`saving report to ./cfat/cfat.txt...`)
|
611
|
+
fs.appendFileSync(reportFilePath, report);
|
612
|
+
|
613
|
+
return tasks
|
614
|
+
}
|
615
|
+
|
616
|
+
export default createReport;
|
@@ -0,0 +1,51 @@
|
|
1
|
+
import { AccountType } from '../types';
|
2
|
+
|
3
|
+
import { STSClient, GetCallerIdentityCommand } from "@aws-sdk/client-sts";
|
4
|
+
import { OrganizationsClient, DescribeOrganizationCommand, } from "@aws-sdk/client-organizations";
|
5
|
+
|
6
|
+
async function getAccountId(region:string): Promise<string> {
|
7
|
+
const stsClient:STSClient = new STSClient({region});
|
8
|
+
try {
|
9
|
+
const getCallerIdentityCommand = new GetCallerIdentityCommand({});
|
10
|
+
const Account = await stsClient.send(getCallerIdentityCommand);
|
11
|
+
return Account.Account!
|
12
|
+
} catch (error) {
|
13
|
+
console.error("Error getting account ID:", error);
|
14
|
+
throw error;
|
15
|
+
}
|
16
|
+
};
|
17
|
+
|
18
|
+
// function checking if management account, member account, or standalone account
|
19
|
+
export const defineAccountType = async (region: string): Promise<AccountType> => {
|
20
|
+
const organizationsClient = new OrganizationsClient({ region });
|
21
|
+
let isInOrganization:boolean = false
|
22
|
+
let isManagementAccount:boolean = false
|
23
|
+
try {
|
24
|
+
const currentAccountId:string = await getAccountId(region);
|
25
|
+
if(currentAccountId){
|
26
|
+
const describeOrganizationCommand = new DescribeOrganizationCommand({});
|
27
|
+
const describeOrganizationResponse = await organizationsClient.send(describeOrganizationCommand);
|
28
|
+
// the account is not standalone and part of AWS Organization
|
29
|
+
if (describeOrganizationResponse.Organization?.MasterAccountId) {
|
30
|
+
const managementAccountId:string = describeOrganizationResponse.Organization?.MasterAccountId
|
31
|
+
if(managementAccountId == currentAccountId){
|
32
|
+
// this is an organization and this is the management account
|
33
|
+
isManagementAccount = true;
|
34
|
+
isInOrganization = true;
|
35
|
+
}
|
36
|
+
else{
|
37
|
+
// there is an organization, but this isn't the management account
|
38
|
+
isInOrganization = true;
|
39
|
+
}
|
40
|
+
} else {
|
41
|
+
// there isn't an organization and this account is standalone
|
42
|
+
isInOrganization = false;
|
43
|
+
}
|
44
|
+
}
|
45
|
+
} catch (error) {
|
46
|
+
console.error("Error:", error);
|
47
|
+
} finally {
|
48
|
+
organizationsClient.destroy();
|
49
|
+
}
|
50
|
+
return { isInOrganization, isManagementAccount };
|
51
|
+
};
|