Skip to content

Commit ab1c338

Browse files
authored
feat: Allow user defined S3 Bucket for the audit log (#1248)
* feat: Allow user defined S3 Bucket for the audit log * refactor: address code review comments * fix: update integration tests
1 parent 938511e commit ab1c338

File tree

5 files changed

+119
-1
lines changed

5 files changed

+119
-1
lines changed

cli/cmd/generate_aws_eks_audit.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ var (
2828
QuestionEksAuditConfigureAdvanced = "Configure advanced integration options?"
2929

3030
// S3 Bucket Questions
31+
QuestionUseExistingBucket = "Use existing bucket?"
32+
QuestionExistingBucketArn = "Specify an existing bucket ARN used for EKS audit log:"
3133
EksAuditConfigureBucket = "Configure bucket settings"
3234
QuestionEksAuditBucketVersioning = "Enable access versioning on the new bucket?"
3335
QuestionEksAuditMfaDeleteS3Bucket = "Should MFA object deletion be required for the new bucket?"
@@ -117,6 +119,7 @@ See help output for more details on the parameter values required for Terraform
117119
aws_eks_audit.WithAwsProfile(GenerateAwsEksAuditCommandState.AwsProfile),
118120
aws_eks_audit.WithLaceworkAccountID(GenerateAwsEksAuditCommandState.LaceworkAccountID),
119121
aws_eks_audit.WithBucketLifecycleExpirationDays(GenerateAwsEksAuditCommandState.BucketLifecycleExpirationDays),
122+
aws_eks_audit.WithExistingBucketArn(GenerateAwsEksAuditCommandState.ExistinglBucketArn),
120123
aws_eks_audit.WithBucketSseAlgorithm(GenerateAwsEksAuditCommandState.BucketSseAlgorithm),
121124
aws_eks_audit.WithBucketSseKeyArn(GenerateAwsEksAuditCommandState.BucketSseKeyArn),
122125
aws_eks_audit.WithEksAuditIntegrationName(GenerateAwsEksAuditCommandState.EksAuditIntegrationName),
@@ -138,6 +141,10 @@ See help output for more details on the parameter values required for Terraform
138141
aws_eks_audit.EnableKmsKeyRotation(GenerateAwsEksAuditCommandState.KmsKeyRotation),
139142
}
140143

144+
if GenerateAwsEksAuditCommandState.UseExistinglBucket {
145+
mods = append(mods, aws_eks_audit.EnableUseExistingBucket())
146+
}
147+
141148
if GenerateAwsEksAuditCommandState.BucketEnableMfaDelete {
142149
mods = append(mods, aws_eks_audit.EnableBucketMfaDelete())
143150
}
@@ -366,6 +373,16 @@ func initGenerateAwsEksAuditTfCommandFlags() {
366373
"bucket_sse_key_arn",
367374
"",
368375
"specify the kms key arn to be used for s3. (required when bucket_sse_algorithm is aws:kms & using an existing kms key)")
376+
generateAwsEksAuditTfCommand.PersistentFlags().StringVar(
377+
&GenerateAwsEksAuditCommandState.ExistinglBucketArn,
378+
"existing_bucket_arn",
379+
"",
380+
"specify existing s3 bucket arn for the audit log")
381+
generateAwsEksAuditTfCommand.PersistentFlags().BoolVar(
382+
&GenerateAwsEksAuditCommandState.UseExistinglBucket,
383+
"use_existing_bucket",
384+
false,
385+
"use existing supplied s3 bucket (default false)")
369386
generateAwsEksAuditTfCommand.PersistentFlags().BoolVar(
370387
&GenerateAwsEksAuditCommandState.BucketVersioning,
371388
"enable_bucket_versioning",
@@ -473,6 +490,26 @@ func validateResponseTypeInt(val interface{}) error {
473490

474491
func promptAwsEksAuditBucketQuestions(config *aws_eks_audit.GenerateAwsEksAuditTfConfigurationArgs) error {
475492
// Only ask these questions if configure bucket is true
493+
if err := SurveyMultipleQuestionWithValidation([]SurveyQuestionWithValidationArgs{
494+
{
495+
Prompt: &survey.Confirm{Message: QuestionUseExistingBucket, Default: config.UseExistinglBucket},
496+
Response: &config.UseExistinglBucket,
497+
},
498+
{
499+
Prompt: &survey.Input{Message: QuestionExistingBucketArn, Default: config.ExistinglBucketArn},
500+
Checks: []*bool{&config.UseExistinglBucket},
501+
Opts: []survey.AskOpt{survey.WithValidator(validateAwsArnFormat)},
502+
Response: &config.ExistinglBucketArn,
503+
},
504+
}); err != nil {
505+
return err
506+
}
507+
508+
// Only ask the next questions if the user did not indicate they wanted to use and existing bucket
509+
if config.UseExistinglBucket {
510+
return nil
511+
}
512+
476513
if err := SurveyMultipleQuestionWithValidation([]SurveyQuestionWithValidationArgs{
477514
{
478515
Prompt: &survey.Confirm{Message: QuestionEksAuditBucketVersioning, Default: config.BucketVersioning},

integration/aws_eks_audit_generation_test.go

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ func TestGenerationEksSingleRegionAdvancedBucket(t *testing.T) {
8989
MsgRsp{cmd.QuestionEksAuditRegionClusters, "cluster1,cluster2"},
9090
MsgRsp{cmd.QuestionEksAuditConfigureAdvanced, "y"},
9191
MsgMenu{cmd.EksAuditConfigureBucket, 0},
92+
MsgRsp{cmd.QuestionUseExistingBucket, "n"},
9293
MsgRsp{cmd.QuestionEksAuditBucketVersioning, "y"},
9394
MsgRsp{cmd.QuestionEksAuditMfaDeleteS3Bucket, "y"},
9495
MsgRsp{cmd.QuestionEksAuditForceDestroyS3Bucket, "y"},
@@ -139,6 +140,7 @@ func TestGenerationEksSingleRegionAdvancedBucketExistingKey(t *testing.T) {
139140
MsgRsp{cmd.QuestionEksAuditRegionClusters, "cluster1,cluster2"},
140141
MsgRsp{cmd.QuestionEksAuditConfigureAdvanced, "y"},
141142
MsgMenu{cmd.EksAuditConfigureBucket, 0},
143+
MsgRsp{cmd.QuestionUseExistingBucket, "n"},
142144
MsgRsp{cmd.QuestionEksAuditBucketVersioning, "y"},
143145
MsgRsp{cmd.QuestionEksAuditMfaDeleteS3Bucket, "y"},
144146
MsgRsp{cmd.QuestionEksAuditForceDestroyS3Bucket, "y"},
@@ -481,7 +483,7 @@ func TestGenerateEksPrefix(t *testing.T) {
481483
prefix,
482484
)
483485

484-
assertGkeTerraformSaved(t, final)
486+
assertEksAuditTerraformSaved(t, final)
485487

486488
regionClusterMap := make(map[string][]string)
487489
regionClusterMap["us-west-1"] = []string{"cluster1", "cluster2"}
@@ -646,3 +648,41 @@ func TestGenerationEksNonInteractive(t *testing.T) {
646648
buildTf, _ := aws_eks_audit.NewTerraform(aws_eks_audit.WithParsedRegionClusterMap(regionClusterMap)).Generate()
647649
assert.Equal(t, buildTf, tfResult)
648650
}
651+
652+
func TestGenerationSuppliedBucketArn(t *testing.T) {
653+
os.Setenv("LW_NOCACHE", "true")
654+
defer os.Setenv("LW_NOCACHE", "")
655+
var final string
656+
657+
tfResult := runEksAuditGenerateTest(t,
658+
func(c *expect.Console) {
659+
expectsCliOutput(t, c, []MsgRspHandler{
660+
MsgRsp{cmd.QuestionEksAuditMultiRegion, "n"},
661+
MsgRsp{cmd.QuestionEksAuditRegion, "us-west-1"},
662+
MsgRsp{cmd.QuestionEksAuditRegionClusters, "cluster1,cluster2"},
663+
MsgRsp{cmd.QuestionEksAuditConfigureAdvanced, "y"},
664+
MsgMenu{cmd.EksAuditConfigureBucket, 0},
665+
MsgRsp{cmd.QuestionUseExistingBucket, "y"},
666+
MsgRsp{cmd.QuestionExistingBucketArn, "arn:aws:s3:::bucket-name"},
667+
MsgRsp{cmd.QuestionEksAuditAnotherAdvancedOpt, "n"},
668+
MsgRsp{cmd.QuestionRunTfPlan, "n"},
669+
})
670+
671+
final, _ = c.ExpectEOF()
672+
},
673+
"generate",
674+
"k8s",
675+
"eks",
676+
)
677+
678+
assertEksAuditTerraformSaved(t, final)
679+
680+
regionClusterMap := make(map[string][]string)
681+
regionClusterMap["us-west-1"] = []string{"cluster1", "cluster2"}
682+
buildTf, _ := aws_eks_audit.NewTerraform(
683+
aws_eks_audit.WithParsedRegionClusterMap(regionClusterMap),
684+
aws_eks_audit.EnableUseExistingBucket(),
685+
aws_eks_audit.WithExistingBucketArn("arn:aws:s3:::bucket-name"),
686+
).Generate()
687+
assert.Equal(t, buildTf, tfResult)
688+
}

integration/test_resources/help/generate_k8s_eks

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ Flags:
3333
--enable_kms_key_rotation enable automatic kms key rotation (default true)
3434
--enable_mfa_delete_s3 enable mfa delete on s3 bucket. Requires bucket versioning.
3535
--enable_sns_topic_encryption enable encryption on the sns topic (default true)
36+
--existing_bucket_arn string specify existing s3 bucket arn for the audit log
3637
--existing_ca_iam_role_arn string specify existing cross account iam role arn to use
3738
--existing_ca_iam_role_external_id string specify existing cross account iam role external_id to use
3839
--existing_cw_iam_role_arn string specify existing cloudwatch iam role arn to use
@@ -46,6 +47,7 @@ Flags:
4647
--prefix string specify the prefix that will be used at the beginning of every generated resource
4748
--region_clusters stringToString configure eks clusters per aws region. To configure multiple regions pass the flag multiple times. Example format: --region_clusters <region>="cluster,list" (default [])
4849
--sns_topic_encryption_key_arn string specify the kms key arn to be used with the sns topic
50+
--use_existing_bucket use existing supplied s3 bucket (default false)
4951

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

lwgenerate/aws_eks_audit/aws_eks_audit.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,12 @@ type GenerateAwsEksAuditTfConfigurationArgs struct {
132132

133133
// The Lacework AWS Root Account ID
134134
LaceworkAccountID string
135+
136+
// Should we use an existing customer supplied bucket? Defaults to false
137+
UseExistinglBucket bool
138+
139+
// Existing S3 Bucket ARN (Required when using existing bucket)
140+
ExistinglBucketArn string
135141
}
136142

137143
// Ensure all combinations of inputs our valid for supported spec
@@ -360,6 +366,20 @@ func WithLaceworkProfile(name string) AwsEksAuditTerraformModifier {
360366
}
361367
}
362368

369+
// WithExistingBucketArn Set the Lacework Profile to utilize when integrating
370+
func WithExistingBucketArn(name string) AwsEksAuditTerraformModifier {
371+
return func(c *GenerateAwsEksAuditTfConfigurationArgs) {
372+
c.ExistinglBucketArn = name
373+
}
374+
}
375+
376+
// EnableUseExistingBucket Set the S3 ForceDestroy parameter to true for newly created buckets
377+
func EnableUseExistingBucket() AwsEksAuditTerraformModifier {
378+
return func(c *GenerateAwsEksAuditTfConfigurationArgs) {
379+
c.UseExistinglBucket = true
380+
}
381+
}
382+
363383
// Generate new Terraform code based on the supplied args.
364384
func (args *GenerateAwsEksAuditTfConfigurationArgs) Generate() (string, error) {
365385
// Validate inputs
@@ -491,6 +511,11 @@ func createEksAudit(args *GenerateAwsEksAuditTfConfigurationArgs) ([]*hclwrite.B
491511
moduleAttrs["lacework_aws_account_id"] = args.LaceworkAccountID
492512
}
493513

514+
if args.UseExistinglBucket {
515+
moduleAttrs["use_existing_bucket"] = true
516+
moduleAttrs["bucket_arn"] = args.ExistinglBucketArn
517+
}
518+
494519
if args.BucketEnableMfaDelete && args.BucketVersioning {
495520
moduleAttrs["bucket_enable_mfa_delete"] = true
496521
}

lwgenerate/aws_eks_audit/aws_eks_audit_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,20 @@ func TestGenerationEksEnableKmsKeyRotationFalse(t *testing.T) {
394394
assert.Contains(t, strippedHcl, "kms_key_rotation=false")
395395
}
396396

397+
func TestGenerationEksUseExistingBucketKey(t *testing.T) {
398+
clusterMap := make(map[string][]string)
399+
clusterMap["us-east-1"] = []string{"cluster1", "cluster2"}
400+
hcl, err := NewTerraform(WithParsedRegionClusterMap(clusterMap),
401+
EnableUseExistingBucket(),
402+
WithExistingBucketArn("arn:aws:s3:::test-bucket"),
403+
).Generate()
404+
assert.Nil(t, err)
405+
assert.NotNil(t, hcl)
406+
strippedHcl := strings.ReplaceAll(hcl, " ", "")
407+
assert.Contains(t, strippedHcl, "use_existing_bucket=true")
408+
assert.Contains(t, strippedHcl, "bucket_arn=\"arn:aws:s3:::test-bucket\"")
409+
}
410+
397411
var requiredProviders = `terraform {
398412
required_providers {
399413
lacework = {

0 commit comments

Comments
 (0)