@@ -68,15 +68,26 @@ var (
6868 QuestionCloudtrailName = "Name of cloudtrail integration (optional):"
6969 QuestionCloudtrailAdvanced = "Configure advanced options?"
7070
71+ // CloudTrail Control Tower questions
72+ QuestionControlTower = "Is your AWS organzation using Control Tower?"
73+ QuestionControlTowerS3BucketArn = "AWS Control Tower S3 bucket ARN:"
74+ QuestionControlTowerSnsTopicArn = "AWS Control Tower SNS topic ARN:"
75+ QuestionControlTowerAuditAccountProfile = "AWS Control Tower audit account profile:"
76+ QuestionControlTowerAuditAccountRegion = "AWS Control Tower audit account region:"
77+ QuestionControlTowerLogArchiveAccountProfile = "AWS Control Tower log archive account profile:"
78+ QuestionControlTowerLogArchiveAccountRegion = "AWS Control Tower log archive account region:"
79+ QuestionControlTowerKmsKeyArn = "AWS Control Tower custom KMS Key ARN (optional):"
80+
7181 // CloudTrail advanced options
7282 OptCloudtrailMessage = "Which options would you like to configure?"
7383
74- OptCloudtrailOrg = "Configure org account mappings"
75- OptCloudtrailS3 = "Configure S3 bucket"
76- OptCloudtrailSNS = "Configure SNS topic"
77- OptCloudtrailSQS = "Configure SQS queue"
78- OptCloudtrailIAM = "Configure an existing IAM role"
79- OptCloudtrailDone = "Done"
84+ OptCloudtrailOrg = "Configure org account mappings"
85+ OptCloudtrailKmsKeyArn = "Configure custom KMS key"
86+ OptCloudtrailS3 = "Configure S3 bucket"
87+ OptCloudtrailSNS = "Configure SNS topic"
88+ OptCloudtrailSQS = "Configure SQS queue"
89+ OptCloudtrailIAM = "Configure an existing IAM role"
90+ OptCloudtrailDone = "Done"
8091
8192 // CloudTrail Org questions
8293 QuestionCloudtrailOrgAccountMappingsDefaultLWAccount = "Org account mappings default Lacework account:"
@@ -188,6 +199,10 @@ See help output for more details on the parameter value(s) required for Terrafor
188199 aws .WithConfigOrgId (GenerateAwsCommandState .ConfigOrgId ),
189200 aws .WithConfigOrgUnits (GenerateAwsCommandState .ConfigOrgUnits ),
190201 aws .WithConfigOrgCfResourcePrefix (GenerateAwsCommandState .ConfigOrgCfResourcePrefix ),
202+ aws .WithControlTower (GenerateAwsCommandState .ControlTower ),
203+ aws .WithControlTowerAuditAccount (GenerateAwsCommandState .ControlTowerAuditAccount ),
204+ aws .WithControlTowerLogArchiveAccount (GenerateAwsCommandState .ControlTowerLogArchiveAccount ),
205+ aws .WithControlTowerKmsKeyArn (GenerateAwsCommandState .ControlTowerKmsKeyArn ),
191206 aws .WithConsolidatedCloudtrail (GenerateAwsCommandState .ConsolidatedCloudtrail ),
192207 aws .WithCloudtrailUseExistingS3 (GenerateAwsCommandState .CloudtrailUseExistingS3 ),
193208 aws .WithCloudtrailUseExistingSNSTopic (GenerateAwsCommandState .CloudtrailUseExistingSNSTopic ),
@@ -399,6 +414,28 @@ See help output for more details on the parameter value(s) required for Terrafor
399414 GenerateAwsCommandState .AgentlessScanningAccounts = accounts
400415 }
401416
417+ // Parse passed in Control Tower Audit account
418+ if GenerateAwsCommandExtraState .ControlTowerAuditAccount != "" {
419+ accounts , err := parseAwsAccountsFromCommandFlag (
420+ []string {GenerateAwsCommandExtraState .ControlTowerAuditAccount },
421+ )
422+ if err != nil {
423+ return err
424+ }
425+ GenerateAwsCommandState .ControlTowerAuditAccount = & accounts [0 ]
426+ }
427+
428+ // Parse passed in Control Tower Log Archive account
429+ if GenerateAwsCommandExtraState .ControlTowerLogArchiveAccount != "" {
430+ accounts , err := parseAwsAccountsFromCommandFlag (
431+ []string {GenerateAwsCommandExtraState .ControlTowerLogArchiveAccount },
432+ )
433+ if err != nil {
434+ return err
435+ }
436+ GenerateAwsCommandState .ControlTowerLogArchiveAccount = & accounts [0 ]
437+ }
438+
402439 return nil
403440 },
404441 }
@@ -461,6 +498,26 @@ func initGenerateAwsTfCommandFlags() {
461498 "agentless_scanning_accounts" ,
462499 []string {},
463500 "AWS scanning accounts for Agentless integrations; value format must be <aws profile>:<region>" )
501+ generateAwsTfCommand .PersistentFlags ().BoolVar (
502+ & GenerateAwsCommandState .ControlTower ,
503+ "controltower" ,
504+ false ,
505+ "enable Control Tower integration" )
506+ generateAwsTfCommand .PersistentFlags ().StringVar (
507+ & GenerateAwsCommandExtraState .ControlTowerAuditAccount ,
508+ "controltower_audit_account" ,
509+ "" ,
510+ "specify AWS Control Tower Audit account; value format must be <aws profile>:<region>" )
511+ generateAwsTfCommand .PersistentFlags ().StringVar (
512+ & GenerateAwsCommandExtraState .ControlTowerLogArchiveAccount ,
513+ "controltower_log_archive_account" ,
514+ "" ,
515+ "specify AWS Control Tower Log Archive account; value format must be <aws profile>:<region>" )
516+ generateAwsTfCommand .PersistentFlags ().StringVar (
517+ & GenerateAwsCommandState .ControlTowerKmsKeyArn ,
518+ "controltower_kms_key_arn" ,
519+ "" ,
520+ "specify AWS Control Tower custom kMS key ARN" )
464521 generateAwsTfCommand .PersistentFlags ().BoolVar (
465522 & GenerateAwsCommandState .Cloudtrail ,
466523 "cloudtrail" ,
@@ -955,10 +1012,17 @@ func promptCloudtrailQuestions(
9551012 return nil
9561013 }
9571014
1015+ if err := promptCloudtrailControlTowerQuestions (config ); err != nil {
1016+ return err
1017+ }
1018+
1019+ noControlTower := ! config .ControlTower
1020+
9581021 if err := SurveyQuestionInteractiveOnly (SurveyQuestionWithValidationArgs {
9591022 Icon : IconCloudTrail ,
9601023 Prompt : & survey.Confirm {Message : QuestionCloudtrailUseConsolidated , Default : config .ConsolidatedCloudtrail },
9611024 Response : & config .ConsolidatedCloudtrail ,
1025+ Checks : []* bool {& noControlTower },
9621026 }); err != nil {
9631027 return err
9641028 }
@@ -983,6 +1047,13 @@ func promptCloudtrailQuestions(
9831047 OptCloudtrailDone ,
9841048 }
9851049 if config .AwsOrganization {
1050+ if config .ControlTower {
1051+ options = []string {
1052+ OptCloudtrailKmsKeyArn ,
1053+ OptCloudtrailIAM ,
1054+ OptCloudtrailDone ,
1055+ }
1056+ }
9861057 options = append ([]string {OptCloudtrailOrg }, options ... )
9871058 }
9881059 for answer != OptCloudtrailDone {
@@ -1001,6 +1072,10 @@ func promptCloudtrailQuestions(
10011072 if err := promptCloudtrailOrgQuestions (config ); err != nil {
10021073 return err
10031074 }
1075+ case OptCloudtrailKmsKeyArn :
1076+ if err := promptCloudtrailKmsKeyQuestions (config ); err != nil {
1077+ return err
1078+ }
10041079 case OptCloudtrailS3 :
10051080 if err := promptCloudtrailS3Questions (config ); err != nil {
10061081 return err
@@ -1024,6 +1099,128 @@ func promptCloudtrailQuestions(
10241099 return nil
10251100}
10261101
1102+ func promptCloudtrailControlTowerQuestions (config * aws.GenerateAwsTfConfigurationArgs ) error {
1103+ if err := SurveyQuestionInteractiveOnly (SurveyQuestionWithValidationArgs {
1104+ Icon : IconCloudTrail ,
1105+ Prompt : & survey.Confirm {Message : QuestionControlTower , Default : config .ControlTower },
1106+ Response : & config .ControlTower ,
1107+ Checks : []* bool {& config .AwsOrganization },
1108+ }); err != nil {
1109+ return err
1110+ }
1111+
1112+ if ! config .ControlTower {
1113+ return nil
1114+ }
1115+
1116+ if err := SurveyMultipleQuestionWithValidation ([]SurveyQuestionWithValidationArgs {
1117+ {
1118+ Icon : IconCloudTrail ,
1119+ Prompt : & survey.Input {
1120+ Message : QuestionControlTowerS3BucketArn ,
1121+ Default : config .ExistingCloudtrailBucketArn ,
1122+ },
1123+ Required : true ,
1124+ Opts : []survey.AskOpt {survey .WithValidator (validateAwsArnFormat )},
1125+ Response : & config .ExistingCloudtrailBucketArn ,
1126+ },
1127+ {
1128+ Icon : IconCloudTrail ,
1129+ Prompt : & survey.Input {
1130+ Message : QuestionControlTowerSnsTopicArn ,
1131+ Default : config .ExistingSnsTopicArn ,
1132+ },
1133+ Required : true ,
1134+ Opts : []survey.AskOpt {survey .WithValidator (validateAwsArnFormat )},
1135+ Response : & config .ExistingSnsTopicArn ,
1136+ },
1137+ }); err != nil {
1138+ return err
1139+ }
1140+
1141+ profile := ""
1142+ region := ""
1143+ defaultProfile := ""
1144+ defaultRegion := ""
1145+ if config .ControlTowerAuditAccount != nil {
1146+ defaultProfile = config .ControlTowerAuditAccount .AwsProfile
1147+ }
1148+ if config .ControlTowerAuditAccount != nil {
1149+ defaultRegion = config .ControlTowerAuditAccount .AwsRegion
1150+ }
1151+
1152+ if err := SurveyMultipleQuestionWithValidation ([]SurveyQuestionWithValidationArgs {
1153+ {
1154+ Icon : IconCloudTrail ,
1155+ Prompt : & survey.Input {
1156+ Message : QuestionControlTowerAuditAccountProfile ,
1157+ Default : defaultProfile ,
1158+ },
1159+ Required : true ,
1160+ Response : & profile ,
1161+ },
1162+ {
1163+ Icon : IconCloudTrail ,
1164+ Prompt : & survey.Input {
1165+ Message : QuestionControlTowerAuditAccountRegion ,
1166+ Default : defaultRegion ,
1167+ },
1168+ Required : true ,
1169+ Opts : []survey.AskOpt {survey .WithValidator (validateAwsRegion )},
1170+ Response : & region ,
1171+ },
1172+ }); err != nil {
1173+ return err
1174+ }
1175+
1176+ config .ControlTowerAuditAccount = & aws.AwsSubAccount {
1177+ AwsProfile : profile ,
1178+ AwsRegion : region ,
1179+ Alias : fmt .Sprintf ("%s-%s" , profile , region ),
1180+ }
1181+
1182+ defaultProfile = ""
1183+ defaultRegion = ""
1184+ if config .ControlTowerLogArchiveAccount != nil {
1185+ defaultProfile = config .ControlTowerLogArchiveAccount .AwsProfile
1186+ }
1187+ if config .ControlTowerLogArchiveAccount != nil {
1188+ defaultRegion = config .ControlTowerLogArchiveAccount .AwsRegion
1189+ }
1190+
1191+ if err := SurveyMultipleQuestionWithValidation ([]SurveyQuestionWithValidationArgs {
1192+ {
1193+ Icon : IconCloudTrail ,
1194+ Prompt : & survey.Input {
1195+ Message : QuestionControlTowerLogArchiveAccountProfile ,
1196+ Default : defaultProfile ,
1197+ },
1198+ Required : true ,
1199+ Response : & profile ,
1200+ },
1201+ {
1202+ Icon : IconCloudTrail ,
1203+ Prompt : & survey.Input {
1204+ Message : QuestionControlTowerLogArchiveAccountRegion ,
1205+ Default : defaultRegion ,
1206+ },
1207+ Required : true ,
1208+ Opts : []survey.AskOpt {survey .WithValidator (validateAwsRegion )},
1209+ Response : & region ,
1210+ },
1211+ }); err != nil {
1212+ return err
1213+ }
1214+
1215+ config .ControlTowerLogArchiveAccount = & aws.AwsSubAccount {
1216+ AwsProfile : profile ,
1217+ AwsRegion : region ,
1218+ Alias : fmt .Sprintf ("%s-%s" , profile , region ),
1219+ }
1220+
1221+ return nil
1222+ }
1223+
10271224func promptCloudtrailOrgAccountMappingQuestions (config * aws.GenerateAwsTfConfigurationArgs ) error {
10281225 mapping := aws.OrgAccountMap {}
10291226 var accountsAnswer string
@@ -1075,6 +1272,22 @@ func promptCloudtrailOrgQuestions(config *aws.GenerateAwsTfConfigurationArgs) er
10751272 return nil
10761273}
10771274
1275+ func promptCloudtrailKmsKeyQuestions (config * aws.GenerateAwsTfConfigurationArgs ) error {
1276+ if err := SurveyQuestionInteractiveOnly (SurveyQuestionWithValidationArgs {
1277+ Icon : IconCloudTrail ,
1278+ Prompt : & survey.Input {
1279+ Message : QuestionControlTowerKmsKeyArn ,
1280+ Default : config .ControlTowerKmsKeyArn ,
1281+ },
1282+ Opts : []survey.AskOpt {survey .WithValidator (validateAwsArnFormat )},
1283+ Response : & config .ControlTowerKmsKeyArn ,
1284+ }); err != nil {
1285+ return err
1286+ }
1287+
1288+ return nil
1289+ }
1290+
10781291func promptCloudtrailS3Questions (config * aws.GenerateAwsTfConfigurationArgs ) error {
10791292 if err := SurveyMultipleQuestionWithValidation ([]SurveyQuestionWithValidationArgs {
10801293 {
0 commit comments