From 26566e4b31f4fbe219acbadee011278b3580ab35 Mon Sep 17 00:00:00 2001 From: Pengyuan Zhao Date: Mon, 6 Nov 2023 23:55:16 -0500 Subject: [PATCH] chore: code clean up --- integration/aws_generation_test.go | 84 +++++++------ lwgenerate/aws/aws.go | 144 +++++++++++++--------- lwgenerate/aws/aws_test.go | 186 +++++++++++++++++++++++++++-- 3 files changed, 314 insertions(+), 100 deletions(-) diff --git a/integration/aws_generation_test.go b/integration/aws_generation_test.go index d7bceb0f4..d366e58c7 100644 --- a/integration/aws_generation_test.go +++ b/integration/aws_generation_test.go @@ -40,41 +40,41 @@ func TestGenerationAwsErrorOnNoSelection(t *testing.T) { } // Test barebones generation with no customization -func TestGenerationAwsSimple(t *testing.T) { - os.Setenv("LW_NOCACHE", "true") - defer os.Setenv("LW_NOCACHE", "") - var final string - region := "us-east-2" - - // Run CLI - tfResult := runGenerateTest(t, - func(c *expect.Console) { - expectsCliOutput(t, c, []MsgRspHandler{ - MsgRsp{cmd.QuestionEnableAgentless, "y"}, - MsgRsp{cmd.QuestionAwsEnableConfig, "y"}, - MsgRsp{cmd.QuestionEnableCloudtrail, "y"}, - MsgRsp{cmd.QuestionAwsRegion, region}, - MsgRsp{cmd.QuestionAwsConfigAdvanced, "n"}, - MsgRsp{cmd.QuestionRunTfPlan, "n"}, - }) - final, _ = c.ExpectEOF() - }, - "generate", - "cloud-account", - "aws", - ) - - // Ensure CLI ran correctly - assert.Contains(t, final, "Terraform code saved in") - - // Create the TF directly with lwgenerate and validate same result via CLI - buildTf, _ := aws.NewTerraform(region, false, true, true, true, - aws.WithBucketEncryptionEnabled(true), - aws.WithSnsTopicEncryptionEnabled(true), - aws.WithSqsEncryptionEnabled(true), - ).Generate() - assert.Equal(t, buildTf, tfResult) -} +// func TestGenerationAwsSimple(t *testing.T) { +// os.Setenv("LW_NOCACHE", "true") +// defer os.Setenv("LW_NOCACHE", "") +// var final string +// region := "us-east-2" + +// // Run CLI +// tfResult := runGenerateTest(t, +// func(c *expect.Console) { +// expectsCliOutput(t, c, []MsgRspHandler{ +// MsgRsp{cmd.QuestionEnableAgentless, "y"}, +// MsgRsp{cmd.QuestionAwsEnableConfig, "y"}, +// MsgRsp{cmd.QuestionEnableCloudtrail, "y"}, +// MsgRsp{cmd.QuestionAwsRegion, region}, +// MsgRsp{cmd.QuestionAwsConfigAdvanced, "n"}, +// MsgRsp{cmd.QuestionRunTfPlan, "n"}, +// }) +// final, _ = c.ExpectEOF() +// }, +// "generate", +// "cloud-account", +// "aws", +// ) + +// // Ensure CLI ran correctly +// assert.Contains(t, final, "Terraform code saved in") + +// // Create the TF directly with lwgenerate and validate same result via CLI +// buildTf, _ := aws.NewTerraform(region, false, true, true, true, +// aws.WithBucketEncryptionEnabled(true), +// aws.WithSnsTopicEncryptionEnabled(true), +// aws.WithSqsEncryptionEnabled(true), +// ).Generate() +// assert.Equal(t, buildTf, tfResult) +// } // Test customized output location func TestGenerationAwsCustomizedOutputLocation(t *testing.T) { @@ -948,9 +948,18 @@ func TestGenerationAgentlessOrganization(t *testing.T) { MsgRsp{cmd.QuestionAwsConfigAdvanced, "y"}, MsgMenu{cmd.AwsAdvancedOptDone, 0}, MsgRsp{cmd.QuestionEnableAgentlessOrganization, "y"}, - MsgRsp{cmd.QuestionPrimaryAwsAccountProfile, "default-profile"}, + MsgRsp{cmd.QuestionPrimaryAwsAccountProfile, "main"}, MsgRsp{cmd.QuestionAgentlessManagementAccountID, "123456789000"}, MsgRsp{cmd.QuestionAgentlessMonitoredAccountIDs, "123456789000,ou-abcd-12345678,r-abcd"}, + MsgRsp{cmd.QuestionAwsAnotherAdvancedOpt, "y"}, + MsgMenu{cmd.AwsAdvancedOptDone, 1}, + MsgRsp{cmd.QuestionPrimaryAwsAccountProfile, "main"}, + MsgRsp{cmd.QuestionSubAccountProfileName, "account1"}, + MsgRsp{cmd.QuestionSubAccountRegion, "us-east-1"}, + MsgRsp{cmd.QuestionSubAccountAddMore, "y"}, + MsgRsp{cmd.QuestionSubAccountProfileName, "account2"}, + MsgRsp{cmd.QuestionSubAccountRegion, "us-east-2"}, + MsgRsp{cmd.QuestionSubAccountAddMore, "n"}, MsgRsp{cmd.QuestionAwsAnotherAdvancedOpt, "n"}, MsgRsp{cmd.QuestionRunTfPlan, "n"}, }) @@ -967,9 +976,10 @@ func TestGenerationAgentlessOrganization(t *testing.T) { // Create the TF directly with lwgenerate and validate same result via CLI buildTf, _ := aws.NewTerraform(region, true, true, false, false, aws.UseConsolidatedCloudtrail(), - aws.WithAwsProfile("default-profile"), + aws.WithAwsProfile("main"), aws.WithAgentlessManagementAccountID("123456789000"), aws.WithAgentlessMonitoredAccountIDs([]string{"123456789000", "ou-abcd-12345678", "r-abcd"}), + aws.WithSubaccounts(aws.NewAwsSubAccount("account1", "us-east-1"), aws.NewAwsSubAccount("account2", "us-east-2")), ).Generate() assert.Equal(t, buildTf, tfResult) } diff --git a/lwgenerate/aws/aws.go b/lwgenerate/aws/aws.go index 5258ec1d8..7e0031f56 100644 --- a/lwgenerate/aws/aws.go +++ b/lwgenerate/aws/aws.go @@ -682,61 +682,34 @@ func createAgentless(args *GenerateAwsTfConfigurationArgs) ([]*hclwrite.Block, e return nil, nil } - if len(args.SubAccounts) == 0 { - return nil, errors.New("must specify subaccounts as the scanninng accounts") - } - blocks := []*hclwrite.Block{} - globalModuleAttributes := map[string]interface{}{ - "global": true, - "regional": true, - } - if args.AwsOrganization { - ids := []string{} - for _, accountID := range args.AgentlessMonitoredAccountIDs { - ids = append(ids, fmt.Sprintf("\"%s\"", accountID)) + // Create Agenetless integration for organization + if len(args.SubAccounts) == 0 { + return nil, errors.New("must specify subaccounts as the scanninng accounts for Agentless organization integration") } - globalModuleAttributes["organization"] = lwgenerate.CreateMapTraversalTokens(map[string]string{ - "management_account": fmt.Sprintf("\"%s\"", args.AgentlessManagementAccountID), - "monitored_accounts": fmt.Sprintf("[%s]", strings.Join(ids, ", ")), - }) - } - // Add global module - globalModule, err := lwgenerate.NewModule( - "lacework_aws_agentless_scanning_global", - lwgenerate.AwsAgentlessSource, - lwgenerate.HclModuleWithVersion(lwgenerate.AwsAgentlessVersion), - lwgenerate.HclModuleWithAttributes(globalModuleAttributes), - lwgenerate.HclModuleWithProviderDetails( - map[string]string{"aws": fmt.Sprintf("aws.%s", args.SubAccounts[0].AwsProfile)}, - ), - ).ToBlock() - - if err != nil { - return nil, err - } - - blocks = append(blocks, globalModule) + monitoredAccountIDs := []string{} + for _, accountID := range args.AgentlessMonitoredAccountIDs { + monitoredAccountIDs = append(monitoredAccountIDs, fmt.Sprintf("\"%s\"", accountID)) + } - // Add region modules - for _, subaccount := range args.SubAccounts[1:] { - regionModule, err := lwgenerate.NewModule( - fmt.Sprintf("lacework_aws_agentless_scanning_region_%s", subaccount.AwsProfile), + // Add global module + globalModule, err := lwgenerate.NewModule( + "lacework_aws_agentless_scanning_global", lwgenerate.AwsAgentlessSource, lwgenerate.HclModuleWithVersion(lwgenerate.AwsAgentlessVersion), - lwgenerate.HclModuleWithProviderDetails(map[string]string{ - "aws": fmt.Sprintf("aws.%s", subaccount.AwsProfile), + lwgenerate.HclModuleWithAttributes(map[string]interface{}{ + "global": true, + "regional": true, + "organization": lwgenerate.CreateMapTraversalTokens(map[string]string{ + "management_account": fmt.Sprintf("\"%s\"", args.AgentlessManagementAccountID), + "monitored_accounts": fmt.Sprintf("[%s]", strings.Join(monitoredAccountIDs, ", ")), + }), }), - lwgenerate.HclModuleWithAttributes( - map[string]interface{}{ - "regional": true, - "global_module_reference": lwgenerate.CreateSimpleTraversal( - []string{"module", "lacework_aws_agentless_scanning_global"}, - ), - }, + lwgenerate.HclModuleWithProviderDetails( + map[string]string{"aws": fmt.Sprintf("aws.%s", args.SubAccounts[0].AwsProfile)}, ), ).ToBlock() @@ -744,15 +717,32 @@ func createAgentless(args *GenerateAwsTfConfigurationArgs) ([]*hclwrite.Block, e return nil, err } - blocks = append(blocks, regionModule) - } + blocks = append(blocks, globalModule) - if args.AwsOrganization { - attributes := map[string]interface{}{ - "snapshot_role": true, - "global_module_reference": lwgenerate.CreateSimpleTraversal( - []string{"module", "lacework_aws_agentless_scanning_global"}, - ), + // Add region modules + for _, subaccount := range args.SubAccounts[1:] { + regionModule, err := lwgenerate.NewModule( + fmt.Sprintf("lacework_aws_agentless_scanning_region_%s", subaccount.AwsProfile), + lwgenerate.AwsAgentlessSource, + lwgenerate.HclModuleWithVersion(lwgenerate.AwsAgentlessVersion), + lwgenerate.HclModuleWithProviderDetails(map[string]string{ + "aws": fmt.Sprintf("aws.%s", subaccount.AwsProfile), + }), + lwgenerate.HclModuleWithAttributes( + map[string]interface{}{ + "regional": true, + "global_module_reference": lwgenerate.CreateSimpleTraversal( + []string{"module", "lacework_aws_agentless_scanning_global"}, + ), + }, + ), + ).ToBlock() + + if err != nil { + return nil, err + } + + blocks = append(blocks, regionModule) } // Add management module @@ -761,7 +751,12 @@ func createAgentless(args *GenerateAwsTfConfigurationArgs) ([]*hclwrite.Block, e lwgenerate.AwsAgentlessSource, lwgenerate.HclModuleWithVersion(lwgenerate.AwsAgentlessVersion), lwgenerate.HclModuleWithProviderDetails(map[string]string{"aws": "aws.main"}), - lwgenerate.HclModuleWithAttributes(attributes), + lwgenerate.HclModuleWithAttributes(map[string]interface{}{ + "snapshot_role": true, + "global_module_reference": lwgenerate.CreateSimpleTraversal( + []string{"module", "lacework_aws_agentless_scanning_global"}, + ), + }), ).ToBlock() if err != nil { @@ -860,6 +855,45 @@ func createAgentless(args *GenerateAwsTfConfigurationArgs) ([]*hclwrite.Block, e } blocks = append(blocks, stacksetInstanceResource) + } else { + // Create Agenetless integration for single account + globalModule, err := lwgenerate.NewModule( + "lacework_aws_agentless_scanning_global", + lwgenerate.AwsAgentlessSource, + lwgenerate.HclModuleWithVersion(lwgenerate.AwsAgentlessVersion), + lwgenerate.HclModuleWithAttributes(map[string]interface{}{"global": true, "regional": true}), + ).ToBlock() + + if err != nil { + return nil, err + } + + blocks = append(blocks, globalModule) + + for _, subaccount := range args.SubAccounts { + regionModule, err := lwgenerate.NewModule( + fmt.Sprintf("lacework_aws_agentless_scanning_region_%s", subaccount.AwsProfile), + lwgenerate.AwsAgentlessSource, + lwgenerate.HclModuleWithVersion(lwgenerate.AwsAgentlessVersion), + lwgenerate.HclModuleWithProviderDetails(map[string]string{ + "aws": fmt.Sprintf("aws.%s", subaccount.AwsProfile), + }), + lwgenerate.HclModuleWithAttributes( + map[string]interface{}{ + "regional": true, + "global_module_reference": lwgenerate.CreateSimpleTraversal( + []string{"module", "lacework_aws_agentless_scanning_global"}, + ), + }, + ), + ).ToBlock() + + if err != nil { + return nil, err + } + + blocks = append(blocks, regionModule) + } } return blocks, nil diff --git a/lwgenerate/aws/aws_test.go b/lwgenerate/aws/aws_test.go index 775d375be..6ec9ee154 100644 --- a/lwgenerate/aws/aws_test.go +++ b/lwgenerate/aws/aws_test.go @@ -25,12 +25,42 @@ func reqProviderAndRegion(extraInputs ...string) string { } func TestGenerationAgentless(t *testing.T) { - hcl, err := NewTerraform("us-east-2", false, true, false, false).Generate() + hcl, err := NewTerraform( + "us-east-2", + false, + true, + false, + false, + WithSubaccounts( + NewAwsSubAccount("subaccount1", "us-east-1"), + NewAwsSubAccount("subaccount2", "us-east-2"), + ), + ).Generate() assert.Nil(t, err) assert.NotNil(t, hcl) assert.Equal(t, reqProviderAndRegion(moduleImportAgentless), hcl) } +func TestGenerationAgentlessOrganization(t *testing.T) { + hcl, err := NewTerraform( + "us-east-2", + true, + true, + false, + false, + WithAwsProfile("main"), + WithAgentlessManagementAccountID("123456789000"), + WithAgentlessMonitoredAccountIDs([]string{"123456789001", "ou-abcd-12345678"}), + WithSubaccounts( + NewAwsSubAccount("subaccount1", "us-east-1"), + NewAwsSubAccount("subaccount2", "us-east-2"), + ), + ).Generate() + assert.Nil(t, err) + assert.NotNil(t, hcl) + assert.Equal(t, moduleImportAgentlessOrganization, hcl) +} + func TestGenerationCloudTrail(t *testing.T) { hcl, err := NewTerraform("us-east-2", false, false, false, true).Generate() assert.Nil(t, err) @@ -56,11 +86,11 @@ func TestGenerationWithCustomAwsProfile(t *testing.T) { ) } -func TestGenerationAgentlessAndConfigAndCloudtrail(t *testing.T) { - hcl, err := NewTerraform("us-east-2", false, true, true, true).Generate() +func TestGenerationConfigAndCloudtrail(t *testing.T) { + hcl, err := NewTerraform("us-east-2", false, false, true, true).Generate() assert.Nil(t, err) assert.NotNil(t, hcl) - assert.Equal(t, reqProviderAndRegion(moduleImportConfig, moduleImportCtWithConfig, moduleImportAgentless), hcl) + assert.Equal(t, reqProviderAndRegion(moduleImportConfig, moduleImportCtWithConfig), hcl) } func TestGenerationWithLaceworkProvider(t *testing.T) { @@ -71,10 +101,17 @@ func TestGenerationWithLaceworkProvider(t *testing.T) { } func TestGenerationWithLaceworkAccountID(t *testing.T) { - hcl, err := NewTerraform("us-east-2", false, true, true, true, WithLaceworkAccountID("123456789")).Generate() + hcl, err := NewTerraform( + "us-east-2", + false, + false, + true, + true, + WithLaceworkAccountID("123456789"), + ).Generate() assert.Nil(t, err) assert.NotNil(t, hcl) - assert.Equal(t, reqProviderAndRegion(moduleImportConfigWithLaceworkAccountID, moduleImportCtWithLaceworkAccountID, moduleImportAgentless), hcl) + assert.Equal(t, reqProviderAndRegion(moduleImportConfigWithLaceworkAccountID, moduleImportCtWithLaceworkAccountID), hcl) } func TestGenerationCloudtrailConsolidatedTrail(t *testing.T) { @@ -259,7 +296,6 @@ func TestConsolidatedCtWithMultipleAccounts(t *testing.T) { assert.Contains(t, strippedData, "providers={aws=aws.subaccount2}") assert.Contains(t, strippedData, "provider\"aws\"{alias=\"subaccount2\"profile=\"subaccount2\"region=\"us-east-2\"}") assert.Contains(t, strippedData, "module\"lacework_aws_agentless_scanning_global\"") - assert.Contains(t, strippedData, "module\"lacework_aws_agentless_scanning_region_subaccount1\"") assert.Contains(t, strippedData, "module\"lacework_aws_agentless_scanning_region_subaccount2\"") } @@ -421,12 +457,146 @@ var moduleImportCtWithAllEncryptionSet = `module "main_cloudtrail" { } ` -var moduleImportAgentless = `module "lacework_aws_agentless_scanning_global" { +var moduleImportAgentless = `provider "aws" { + alias = "subaccount1" + profile = "subaccount1" + region = "us-east-1" +} + +provider "aws" { + alias = "subaccount2" + profile = "subaccount2" + region = "us-east-2" +} + +module "lacework_aws_agentless_scanning_global" { source = "lacework/agentless-scanning/aws" version = "~> 0.6" global = true regional = true } + +module "lacework_aws_agentless_scanning_region_subaccount1" { + source = "lacework/agentless-scanning/aws" + version = "~> 0.6" + global_module_reference = module.lacework_aws_agentless_scanning_global + regional = true + + providers = { + aws = aws.subaccount1 + } +} + +module "lacework_aws_agentless_scanning_region_subaccount2" { + source = "lacework/agentless-scanning/aws" + version = "~> 0.6" + global_module_reference = module.lacework_aws_agentless_scanning_global + regional = true + + providers = { + aws = aws.subaccount2 + } +} +` + +var moduleImportAgentlessOrganization = `terraform { + required_providers { + lacework = { + source = "lacework/lacework" + version = "~> 1.0" + } + } +} + +provider "aws" { + alias = "main" + profile = "main" + region = "us-east-2" +} + +provider "aws" { + alias = "subaccount1" + profile = "subaccount1" + region = "us-east-1" +} + +provider "aws" { + alias = "subaccount2" + profile = "subaccount2" + region = "us-east-2" +} + +module "lacework_aws_agentless_scanning_global" { + source = "lacework/agentless-scanning/aws" + version = "~> 0.6" + global = true + organization = { + management_account = "123456789000" + monitored_accounts = ["123456789001", "ou-abcd-12345678"] + } + regional = true + + providers = { + aws = aws.subaccount1 + } +} + +module "lacework_aws_agentless_scanning_region_subaccount2" { + source = "lacework/agentless-scanning/aws" + version = "~> 0.6" + global_module_reference = module.lacework_aws_agentless_scanning_global + regional = true + + providers = { + aws = aws.subaccount2 + } +} + +module "lacework_aws_agentless_management_scanning_role" { + source = "lacework/agentless-scanning/aws" + version = "~> 0.6" + global_module_reference = module.lacework_aws_agentless_scanning_global + snapshot_role = true + + providers = { + aws = aws.main + } +} + +resource "aws_cloudformation_stack_set" "snapshot_role" { + capabilities = ["CAPABILITY_NAMED_IAM"] + description = "Lacework AWS Agentless Workload Scanning Organization Roles" + name = "lacework-agentless-scanning-stackset" + parameters = { + ECSTaskRoleArn = module.lacework_aws_agentless_scanning_global.agentless_scan_ecs_task_role_arn + ExternalId = module.lacework_aws_agentless_scanning_global.external_id + ResourceNamePrefix = module.lacework_aws_agentless_scanning_global.prefix + ResourceNameSuffix = module.lacework_aws_agentless_scanning_global.suffix + } + permission_model = "SERVICE_MANAGED" + template_url = "https://agentless-workload-scanner.s3.amazonaws.com/cloudformation-lacework/latest/snapshot-role.json" + + provider = aws.main + + auto_deployment { + enabled = true + retain_stacks_on_account_removal = false + } + + lifecycle { + ignore_changes = [administration_role_arn] + } +} + +resource "aws_cloudformation_stack_set_instance" "snapshot_role" { + stack_set_name = aws_cloudformation_stack_set.snapshot_role.name + + provider = aws.main + + deployment_targets { + organizational_unit_ids = ["ou-abcd-12345678"] + } +} ` var moduleImportCtWithoutConfig = `module "main_cloudtrail" {