Skip to content

Commit

Permalink
feat(GROW-2949): Provide organization_id for project level agentless …
Browse files Browse the repository at this point in the history
…integration (#1648)

* feat(GROW-2949): Provide organization_id for project level integration

Signed-off-by: Lei Jin <lei.jin@lacework.net>

* feat: remove restriction on org level integration

Signed-off-by: Lei Jin <lei.jin@lacework.net>

* feat: Require org_id for gcp agentless integration

Signed-off-by: Lei Jin <lei.jin@lacework.net>

---------

Signed-off-by: Lei Jin <lei.jin@lacework.net>
  • Loading branch information
leijin-lw authored Jul 18, 2024
1 parent cbe5213 commit 152359d
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 25 deletions.
5 changes: 3 additions & 2 deletions cli/cdk/go/proto/v1/cdk.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions cli/cdk/go/proto/v1/cdk_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 10 additions & 2 deletions cli/cmd/generate_gcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ func initGenerateGcpTfCommandFlags() {
&GenerateGcpCommandState.GcpOrganizationId,
"organization_id",
"",
"specify the organization id (only set if organization_integration is set)")
"specify the organization id (only set if agentless integration or organization_integration is set)")
generateGcpTfCommand.PersistentFlags().StringVar(
&GenerateGcpCommandState.GcpProjectId,
"project_id",
Expand Down Expand Up @@ -736,9 +736,17 @@ func promptGcpGenerate(
Prompt: &survey.Confirm{Message: QuestionGcpOrganizationIntegration, Default: config.OrganizationIntegration},
Response: &config.OrganizationIntegration,
},
}); err != nil {
return err
}

organizationIdRequired := config.Agentless || config.OrganizationIntegration

if err := SurveyMultipleQuestionWithValidation(
[]SurveyQuestionWithValidationArgs{
{
Prompt: &survey.Input{Message: QuestionGcpOrganizationID, Default: config.GcpOrganizationId},
Checks: []*bool{&config.OrganizationIntegration},
Checks: []*bool{&organizationIdRequired},
Required: true,
Response: &config.GcpOrganizationId,
},
Expand Down
2 changes: 1 addition & 1 deletion cli/docs/lacework_generate_cloud-account_gcp.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ lacework generate cloud-account gcp [flags]
-h, --help help for gcp
--include_root_projects Disables logic that includes root-level projects if excluding folders (default true)
--k8s_filter filter out GKE logs from GCP Audit Log sinks (default true)
--organization_id string specify the organization id (only set if organization_integration is set)
--organization_id string specify the organization id (only set if agentless integration or organization_integration is set)
--organization_integration enable organization integration
--output string location to write generated content (default is ~/lacework/gcp)
--prefix string prefix that will be used at the beginning of every generated resource
Expand Down
42 changes: 42 additions & 0 deletions integration/gcp_generation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,48 @@ func TestGenerationGcpAgentless(t *testing.T) {
assert.Equal(t, buildTf, tfResult)
}

// Test Agentless only generation
func TestGenerationGcpAgentlessProjectLevel(t *testing.T) {
os.Setenv("LW_NOCACHE", "true")
defer os.Setenv("LW_NOCACHE", "")
var final string

tfResult := runGcpGenerateTest(t,
func(c *expect.Console) {
expectsCliOutput(t, c, []MsgRspHandler{
MsgRsp{cmd.QuestionGcpEnableAgentless, "y"},
MsgRsp{cmd.QuestionGcpEnableConfiguration, "n"},
MsgRsp{cmd.QuestionGcpEnableAuditLog, "n"},
MsgRsp{cmd.QuestionGcpProjectID, projectId},
MsgRsp{cmd.QuestionGcpRegions, "us-east1"},
MsgRsp{cmd.QuestionGcpOrganizationIntegration, "n"},
MsgRsp{cmd.QuestionGcpOrganizationID, organizationId},
MsgRsp{cmd.QuestionGcpConfigureAdvanced, "y"},
MsgMenu{cmd.GcpAdvancedOptAgentless, 0},
MsgRsp{cmd.QuestionGcpProjectFilterList, "p1,p2"},
MsgRsp{cmd.QuestionGcpAnotherAdvancedOpt, "n"},
MsgRsp{cmd.QuestionRunTfPlan, "n"},
})

final, _ = c.ExpectEOF()
},
"generate",
"cloud-account",
"gcp",
)

assertTerraformSaved(t, final)

buildTf, _ := gcp.NewTerraform(true, false, false, true,
gcp.WithProjectId(projectId),
gcp.WithOrganizationIntegration(false),
gcp.WithOrganizationId(organizationId),
gcp.WithRegions([]string{"us-east1"}),
gcp.WithProjectFilterList([]string{"p1", "p2"}),
).Generate()
assert.Equal(t, buildTf, tfResult)
}

// Test configuration only generation
func TestGenerationGcpConfig(t *testing.T) {
os.Setenv("LW_NOCACHE", "true")
Expand Down
2 changes: 1 addition & 1 deletion integration/test_resources/help/generate_cloud-account_gcp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Flags:
-h, --help help for gcp
--include_root_projects Disables logic that includes root-level projects if excluding folders (default true)
--k8s_filter filter out GKE logs from GCP Audit Log sinks (default true)
--organization_id string specify the organization id (only set if organization_integration is set)
--organization_id string specify the organization id (only set if agentless integration or organization_integration is set)
--organization_integration enable organization integration
--output string location to write generated content (default is ~/lacework/gcp)
--prefix string prefix that will be used at the beginning of every generated resource
Expand Down
7 changes: 2 additions & 5 deletions lwgenerate/gcp/gcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,11 +173,6 @@ func (args *GenerateGcpTfConfigurationArgs) validate() error {
return errors.New("an Organization ID must be provided for an Organization Integration")
}

// Validate if an organization id has been provided that this is and organization integration
if !args.OrganizationIntegration && args.GcpOrganizationId != "" {
return errors.New("to provide an Organization ID, Organization Integration must be true")
}

// Validate existing Service Account values, if set
if args.ExistingServiceAccount != nil {
if args.ExistingServiceAccount.Name == "" ||
Expand Down Expand Up @@ -631,6 +626,8 @@ func createAgentless(args *GenerateGcpTfConfigurationArgs) ([]*hclwrite.Block, e
}
if args.OrganizationIntegration {
attributes["integration_type"] = "ORGANIZATION"
}
if len(args.GcpOrganizationId) > 0 {
attributes["organization_id"] = args.GcpOrganizationId
}
}
Expand Down
41 changes: 27 additions & 14 deletions lwgenerate/gcp/gcp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,17 @@ func TestGenerateGcpTfConfigurationArgs_Generate_AuditLog(t *testing.T) {
gcp.WithProjectId(projectName)),
ReqProvider(projectName, moduleImportProjectLevelPubSubAuditLogWithoutConfiguration),
},
{
"TestGenerationProjectLevelPubSubAuditLogWithoutConfigWithOrgId",
gcp.NewTerraform(
false,
false,
true,
true,
gcp.WithGcpServiceAccountCredentials("/path/to/credentials"),
gcp.WithProjectId(projectName), gcp.WithOrganizationId("123456789")),
ReqProvider(projectName, moduleImportProjectLevelPubSubAuditLogWithoutConfiguration),
},
{
"TestGenerationProjectLevelAuditLogWithoutCredentialsAndProject",
gcp.NewTerraform(false, false, true, false),
Expand Down Expand Up @@ -513,6 +524,16 @@ func TestGenerateGcpTfConfigurationArgs_Generate_Configuration(t *testing.T) {
),
ReqProvider(projectName, moduleImportProjectLevelConfigurationExistingSA),
},
{
"TestGenerationProjectLevelConfigurationExistingSAWithOrgId",
gcp.NewTerraform(false, true, false, false,
gcp.WithGcpServiceAccountCredentials("/path/to/credentials"),
gcp.WithProjectId(projectName),
gcp.WithOrganizationId("123456789"),
gcp.WithExistingServiceAccount(gcp.NewExistingServiceAccountDetails("foo", "123456789")),
),
ReqProvider(projectName, moduleImportProjectLevelConfigurationExistingSA),
},
{
"TestGenerationProjectLevelConfigurationCustomIntegrationName",
gcp.NewTerraform(false, true, false, false,
Expand Down Expand Up @@ -720,6 +741,7 @@ func TestGenerateGcpTfConfigurationArgs_Generate_Agentless(t *testing.T) {
"TestGenerationProjectLevelAgentless",
gcp.NewTerraform(true, false, false, false,
gcp.WithProjectId(projectName),
gcp.WithOrganizationId("123456789"),
gcp.WithRegions([]string{"us-east1"}),
),
fmt.Sprintf("%s\n%s", RequiredProviders, moduleImportProjectLevelAgentless),
Expand Down Expand Up @@ -769,16 +791,6 @@ func TestGenerationOrganizationLevelAuditLogNoOrgId(t *testing.T) {
assert.EqualError(t, err, "invalid inputs: an Organization ID must be provided for an Organization Integration")
}

func TestGenerationOrganizationLevelAuditLogNoOrgIntegrationFlag(t *testing.T) {
hcl, err := gcp.NewTerraform(false, false, true, false,
gcp.WithGcpServiceAccountCredentials("/path/to/credentials"),
gcp.WithProjectId(projectName),
gcp.WithOrganizationId("123456789"),
).Generate()
assert.Empty(t, hcl)
assert.EqualError(t, err, "invalid inputs: to provide an Organization ID, Organization Integration must be true")
}

func TestGenerationNoIntegration(t *testing.T) {
hcl, err := gcp.NewTerraform(false, false, false, false,
gcp.WithGcpServiceAccountCredentials("/path/to/credentials"),
Expand Down Expand Up @@ -1181,10 +1193,11 @@ var moduleImportProjectLevelAgentless = `provider "google" {
}
module "lacework_gcp_agentless_scanning_global" {
source = "lacework/agentless-scanning/gcp"
version = "~> 2.0"
global = true
regional = true
source = "lacework/agentless-scanning/gcp"
version = "~> 2.0"
global = true
organization_id = "123456789"
regional = true
providers = {
google = google.us-east1
Expand Down

0 comments on commit 152359d

Please sign in to comment.