Skip to content

Commit ff326af

Browse files
authored
feat: CloudTrail S3 bucket notifications (#1269)
1 parent fd9d33a commit ff326af

File tree

6 files changed

+138
-0
lines changed

6 files changed

+138
-0
lines changed

cli/cmd/generate_aws.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ var (
4242
QuestionBucketEnableEncryption = "Enable S3 bucket encryption when creating bucket"
4343
QuestionBucketSseKeyArn = "Specify existing KMS encryption key arn for S3 bucket (optional)"
4444
QuestionBucketName = "Specify name when creating S3 bucket (optional)"
45+
QuestionS3BucketNotification = "Enable S3 bucket notifications"
4546

4647
// SNS Topic Questions
4748
QuestionsUseExistingSNSTopic = "Use an existing SNS topic?"
@@ -125,6 +126,7 @@ See help output for more details on the parameter value(s) required for Terrafor
125126
aws.WithSqsQueueName(GenerateAwsCommandState.SqsQueueName),
126127
aws.WithSqsEncryptionEnabled(GenerateAwsCommandState.SqsEncryptionEnabled),
127128
aws.WithSqsEncryptionKeyArn(GenerateAwsCommandState.SqsEncryptionKeyArn),
129+
aws.WithS3BucketNotification(GenerateAwsCommandState.S3BucketNotification),
128130
}
129131

130132
if GenerateAwsCommandState.ForceDestroyS3Bucket {
@@ -448,6 +450,11 @@ func initGenerateAwsTfCommandFlags() {
448450
"lacework_aws_account_id",
449451
"",
450452
"the Lacework AWS root account id")
453+
generateAwsTfCommand.PersistentFlags().BoolVar(
454+
&GenerateAwsCommandState.S3BucketNotification,
455+
"use_s3_bucket_notification",
456+
false,
457+
"enable S3 bucket notifications")
451458
}
452459

453460
// survey.Validator for aws ARNs
@@ -533,6 +540,12 @@ func promptAwsCtQuestions(config *aws.GenerateAwsTfConfigurationArgs, extraState
533540
Opts: []survey.AskOpt{survey.WithValidator(validateOptionalAwsArnFormat)},
534541
Checks: []*bool{&config.Cloudtrail, &newBucket, &config.BucketEncryptionEnabled},
535542
},
543+
// Allow the user to enable S3 bucket notifications
544+
{
545+
Prompt: &survey.Confirm{Message: QuestionS3BucketNotification, Default: config.S3BucketNotification},
546+
Response: &config.S3BucketNotification,
547+
Checks: []*bool{&config.Cloudtrail, &newBucket},
548+
},
536549
}, config.Cloudtrail); err != nil {
537550
return err
538551
}

cli/docs/lacework_generate_cloud-account_aws.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ lacework generate cloud-account aws [flags]
6262
--sqs_encryption_enabled enable encryption on SQS queue when creating (default true)
6363
--sqs_encryption_key_arn string specify existing KMS encryption key arn for SQS queue
6464
--sqs_queue_name string specify SQS queue name if creating new one
65+
--use_s3_bucket_notification enable S3 bucket notifications
6566
```
6667

6768
### Options inherited from parent commands

integration/aws_generation_test.go

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ func TestGenerationAwsAdvancedOptsConsolidatedAndForceDestroy(t *testing.T) {
221221
MsgRsp{cmd.QuestionBucketName, ""},
222222
MsgRsp{cmd.QuestionBucketEnableEncryption, "y"},
223223
MsgRsp{cmd.QuestionBucketSseKeyArn, ""},
224+
MsgRsp{cmd.QuestionS3BucketNotification, ""},
224225
// SNS Topic Questions
225226
MsgRsp{cmd.QuestionsUseExistingSNSTopic, "n"},
226227
MsgRsp{cmd.QuestionSnsTopicName, ""},
@@ -329,6 +330,7 @@ func TestGenerationAwsAdvancedOptsConsolidatedWithSubAccounts(t *testing.T) {
329330
MsgRsp{cmd.QuestionBucketName, ""},
330331
MsgRsp{cmd.QuestionBucketEnableEncryption, "y"},
331332
MsgRsp{cmd.QuestionBucketSseKeyArn, ""},
333+
MsgRsp{cmd.QuestionS3BucketNotification, ""},
332334
// SNS Topic Questions
333335
MsgRsp{cmd.QuestionsUseExistingSNSTopic, "n"},
334336
MsgRsp{cmd.QuestionSnsTopicName, ""},
@@ -594,6 +596,7 @@ func TestGenerationAwsAdvancedOptsCreateNewElements(t *testing.T) {
594596
MsgRsp{cmd.QuestionBucketName, bucketName},
595597
MsgRsp{cmd.QuestionBucketEnableEncryption, "y"},
596598
MsgRsp{cmd.QuestionBucketSseKeyArn, kmsArn},
599+
MsgRsp{cmd.QuestionS3BucketNotification, ""},
597600
// SNS Topic Questions
598601
MsgRsp{cmd.QuestionsUseExistingSNSTopic, "n"},
599602
MsgRsp{cmd.QuestionSnsTopicName, topicName},
@@ -823,6 +826,96 @@ func TestGenerationAwsLaceworkProfile(t *testing.T) {
823826
assert.Equal(t, buildTf, tfResult)
824827
}
825828

829+
func TestGenerationAwsS3BucketNotification(t *testing.T) {
830+
os.Setenv("LW_NOCACHE", "true")
831+
defer os.Setenv("LW_NOCACHE", "")
832+
var final string
833+
var runError error
834+
region := "us-west-2"
835+
836+
tfResult := runGenerateTest(t,
837+
func(c *expect.Console) {
838+
expectsCliOutput(t, c, []MsgRspHandler{
839+
MsgRsp{cmd.QuestionAwsEnableConfig, "n"},
840+
MsgRsp{cmd.QuestionEnableCloudtrail, "y"},
841+
MsgRsp{cmd.QuestionAwsRegion, region},
842+
MsgRsp{cmd.QuestionAwsConfigAdvanced, "n"},
843+
MsgRsp{cmd.QuestionRunTfPlan, "n"},
844+
})
845+
846+
final, _ = c.ExpectEOF()
847+
},
848+
"generate",
849+
"cloud-account",
850+
"aws",
851+
"--use_s3_bucket_notification",
852+
)
853+
854+
assert.Nil(t, runError)
855+
assert.Contains(t, final, "Terraform code saved in")
856+
857+
buildTf, _ := aws.NewTerraform(region, false, true,
858+
aws.WithS3BucketNotification(true),
859+
).Generate()
860+
assert.Equal(t, buildTf, tfResult)
861+
}
862+
863+
func TestGenerationAwsS3BucketNotificationInteractive(t *testing.T) {
864+
os.Setenv("LW_NOCACHE", "true")
865+
defer os.Setenv("LW_NOCACHE", "")
866+
var final string
867+
var runError error
868+
region := "us-west-2"
869+
870+
tfResult := runGenerateTest(t,
871+
func(c *expect.Console) {
872+
expectsCliOutput(t, c, []MsgRspHandler{
873+
MsgRsp{cmd.QuestionAwsEnableConfig, "n"},
874+
MsgRsp{cmd.QuestionEnableCloudtrail, "y"},
875+
MsgRsp{cmd.QuestionAwsRegion, region},
876+
877+
MsgRsp{cmd.QuestionAwsConfigAdvanced, "y"},
878+
MsgMenu{cmd.AwsAdvancedOptDone, 0},
879+
880+
MsgRsp{cmd.QuestionConsolidatedCloudtrail, ""},
881+
MsgRsp{cmd.QuestionUseExistingCloudtrail, ""},
882+
MsgRsp{cmd.QuestionCloudtrailName, ""},
883+
// S3 Questions
884+
MsgRsp{cmd.QuestionForceDestroyS3Bucket, ""},
885+
MsgRsp{cmd.QuestionBucketName, ""},
886+
MsgRsp{cmd.QuestionBucketEnableEncryption, ""},
887+
MsgRsp{cmd.QuestionBucketSseKeyArn, ""},
888+
MsgRsp{cmd.QuestionS3BucketNotification, "y"},
889+
// SNS Topic Questions
890+
MsgRsp{cmd.QuestionsUseExistingSNSTopic, ""},
891+
MsgRsp{cmd.QuestionSnsTopicName, ""},
892+
MsgRsp{cmd.QuestionSnsEnableEncryption, ""},
893+
MsgRsp{cmd.QuestionSnsEncryptionKeyArn, ""},
894+
// SQS Questions
895+
MsgRsp{cmd.QuestionSqsQueueName, ""},
896+
MsgRsp{cmd.QuestionSqsEnableEncryption, ""},
897+
MsgRsp{cmd.QuestionSqsEncryptionKeyArn, ""},
898+
899+
MsgRsp{cmd.QuestionAwsAnotherAdvancedOpt, "n"},
900+
MsgRsp{cmd.QuestionRunTfPlan, "n"},
901+
})
902+
903+
final, _ = c.ExpectEOF()
904+
},
905+
"generate",
906+
"cloud-account",
907+
"aws",
908+
)
909+
910+
assert.Nil(t, runError)
911+
assert.Contains(t, final, "Terraform code saved in")
912+
913+
buildTf, _ := aws.NewTerraform(region, false, true,
914+
aws.WithS3BucketNotification(true),
915+
).Generate()
916+
assert.Equal(t, buildTf, tfResult)
917+
}
918+
826919
func runGenerateTest(t *testing.T, conditions func(*expect.Console), args ...string) string {
827920
os.Setenv("HOME", tfPath)
828921

integration/test_resources/help/generate_cloud-account_aws

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ Flags:
4646
--sqs_encryption_enabled enable encryption on SQS queue when creating (default true)
4747
--sqs_encryption_key_arn string specify existing KMS encryption key arn for SQS queue
4848
--sqs_queue_name string specify SQS queue name if creating new one
49+
--use_s3_bucket_notification enable S3 bucket notifications
4950

5051
Global Flags:
5152
-a, --account string account subdomain of URL (i.e. <ACCOUNT>.lacework.net)

lwgenerate/aws/aws.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,8 @@ type GenerateAwsTfConfigurationArgs struct {
150150

151151
// The Lacework AWS Root Account ID
152152
LaceworkAccountID string
153+
154+
S3BucketNotification bool
153155
}
154156

155157
// Ensure all combinations of inputs our valid for supported spec
@@ -340,6 +342,12 @@ func WithSqsEncryptionKeyArn(ssqEncryptionKeyArn string) AwsTerraformModifier {
340342
}
341343
}
342344

345+
func WithS3BucketNotification(s3BucketNotifiaction bool) AwsTerraformModifier {
346+
return func(c *GenerateAwsTfConfigurationArgs) {
347+
c.S3BucketNotification = s3BucketNotifiaction
348+
}
349+
}
350+
343351
// Generate new Terraform code based on the supplied args.
344352
func (args *GenerateAwsTfConfigurationArgs) Generate() (string, error) {
345353
// Validate inputs
@@ -578,6 +586,10 @@ func createCloudtrail(args *GenerateAwsTfConfigurationArgs) (*hclwrite.Block, er
578586
attributes["iam_role_external_id"] = args.ExistingIamRole.ExternalId
579587
}
580588

589+
if args.S3BucketNotification {
590+
attributes["use_s3_bucket_notification"] = true
591+
}
592+
581593
if len(args.SubAccounts) > 0 {
582594
modDetails = append(modDetails, lwgenerate.HclModuleWithProviderDetails(map[string]string{"aws": "aws.main"}))
583595
}

lwgenerate/aws/aws_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,17 @@ func TestGenerationPartialExistingIamValues(t *testing.T) {
314314
})
315315
}
316316

317+
func TestGenerationCloudTrailS3BucketNotification(t *testing.T) {
318+
hcl, err := NewTerraform("us-east-2", false, true, WithS3BucketNotification(true)).Generate()
319+
assert.Nil(t, err)
320+
assert.NotNil(t, hcl)
321+
assert.Equal(
322+
t,
323+
reqProviderAndRegion(moduleImportCtWithS3BucketNotification),
324+
hcl,
325+
)
326+
}
327+
317328
var requiredProviders = `terraform {
318329
required_providers {
319330
lacework = {
@@ -437,3 +448,10 @@ var moduleImportCtWithLaceworkAccountID = `module "main_cloudtrail" {
437448
use_existing_iam_role = true
438449
}
439450
`
451+
452+
var moduleImportCtWithS3BucketNotification = `module "main_cloudtrail" {
453+
source = "lacework/cloudtrail/aws"
454+
version = "~> 2.0"
455+
use_s3_bucket_notification = true
456+
}
457+
`

0 commit comments

Comments
 (0)