Skip to content

Commit 135ffc6

Browse files
committed
feat: add account mapping option to GCP agentless
1 parent 940dd63 commit 135ffc6

File tree

4 files changed

+148
-54
lines changed

4 files changed

+148
-54
lines changed

lacework/account_mapping_helper.go

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,15 @@ func (f *accountMappingsFile) Empty() bool {
1313
return f.DefaultLaceworkAccount == ""
1414
}
1515

16-
func getResourceOrgAccountMappings(d *schema.ResourceData) *accountMappingsFile {
16+
type typeStruct struct {
17+
awsAccounts string
18+
gcpProjects string
19+
}
20+
21+
var awsMappingType string = "aws_accounts"
22+
var gcpMappingType string = "gcp_projects"
23+
24+
func getResourceOrgAccountMappings(d *schema.ResourceData, mappingsType string) *accountMappingsFile {
1725
accountMapFile := new(accountMappingsFile)
1826
accMapsInt := d.Get("org_account_mappings").([]interface{})
1927
if len(accMapsInt) != 0 && accMapsInt[0] != nil {
@@ -28,7 +36,7 @@ func getResourceOrgAccountMappings(d *schema.ResourceData) *accountMappingsFile
2836
for _, m := range mappingSet.List() {
2937
mapping := m.(map[string]interface{})
3038
accountMapFile.Mappings[mapping["lacework_account"].(string)] = map[string]interface{}{
31-
"aws_accounts": castStringSlice(mapping["aws_accounts"].(*schema.Set).List()),
39+
mappingsType: castStringSlice(mapping[mappingsType].(*schema.Set).List()),
3240
}
3341
}
3442

@@ -37,7 +45,7 @@ func getResourceOrgAccountMappings(d *schema.ResourceData) *accountMappingsFile
3745
return accountMapFile
3846
}
3947

40-
func flattenOrgAccountMappings(mappingFile *accountMappingsFile) []map[string]interface{} {
48+
func flattenOrgAccountMappings(mappingFile *accountMappingsFile, mappingsType string) []map[string]interface{} {
4149
orgAccMappings := make([]map[string]interface{}, 0, 1)
4250

4351
if mappingFile.Empty() {
@@ -46,26 +54,27 @@ func flattenOrgAccountMappings(mappingFile *accountMappingsFile) []map[string]in
4654

4755
mappings := map[string]interface{}{
4856
"default_lacework_account": mappingFile.DefaultLaceworkAccount,
49-
"mapping": flattenMappings(mappingFile.Mappings),
57+
"mapping": flattenMappings(mappingFile.Mappings, mappingsType),
5058
}
5159

5260
orgAccMappings = append(orgAccMappings, mappings)
5361
return orgAccMappings
5462
}
5563

56-
func flattenMappings(mappings map[string]interface{}) *schema.Set {
64+
func flattenMappings(mappings map[string]interface{}, mappingsType string) *schema.Set {
5765
var (
5866
orgAccountMappingsSchema = awsCloudTrailIntegrationSchema["org_account_mappings"].Elem.(*schema.Resource)
5967
mappingSchema = orgAccountMappingsSchema.Schema["mapping"].Elem.(*schema.Resource)
60-
awsAccountsSchema = mappingSchema.Schema["aws_accounts"].Elem.(*schema.Schema)
68+
accountsSchema = mappingSchema.Schema[mappingsType].Elem.(*schema.Schema)
6169
res = schema.NewSet(schema.HashResource(mappingSchema), []interface{}{})
6270
)
71+
6372
for laceworkAccount, m := range mappings {
6473
mappingValue := m.(map[string]interface{})
6574
res.Add(map[string]interface{}{
6675
"lacework_account": laceworkAccount,
67-
"aws_accounts": schema.NewSet(schema.HashSchema(awsAccountsSchema),
68-
mappingValue["aws_accounts"].([]interface{}),
76+
mappingsType: schema.NewSet(schema.HashSchema(accountsSchema),
77+
mappingValue[mappingsType].([]interface{}),
6978
),
7079
})
7180
}

lacework/resource_lacework_integration_aws_ct.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ func resourceLaceworkIntegrationAwsCloudTrailCreate(d *schema.ResourceData, meta
135135
}
136136
)
137137
// verify if the user provided an account mapping
138-
accountMapFile := getResourceOrgAccountMappings(d)
138+
accountMapFile := getResourceOrgAccountMappings(d, awsMappingType)
139139
if !accountMapFile.Empty() {
140140
accountMapFileBytes, err := json.Marshal(accountMapFile)
141141
if err != nil {
@@ -234,7 +234,7 @@ func resourceLaceworkIntegrationAwsCloudTrailRead(d *schema.ResourceData, meta i
234234

235235
}
236236

237-
err = d.Set("org_account_mappings", flattenOrgAccountMappings(accountMapFile))
237+
err = d.Set("org_account_mappings", flattenOrgAccountMappings(accountMapFile, awsMappingType))
238238
if err != nil {
239239
return fmt.Errorf("Error flattening organization account mapping: %s", err)
240240
}
@@ -262,7 +262,7 @@ func resourceLaceworkIntegrationAwsCloudTrailUpdate(d *schema.ResourceData, meta
262262
)
263263

264264
// verify if the user provided an account mapping
265-
accountMapFile := getResourceOrgAccountMappings(d)
265+
accountMapFile := getResourceOrgAccountMappings(d, awsMappingType)
266266
if !accountMapFile.Empty() {
267267
accountMapFileBytes, err := json.Marshal(accountMapFile)
268268
if err != nil {

lacework/resource_lacework_integration_aws_org_agentless_scanning.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ func resourceLaceworkIntegrationAwsOrgAgentlessScanningCreate(d *schema.Resource
214214
}
215215

216216
// verify if the user provided an account mapping
217-
accountMapFile := getResourceOrgAccountMappings(d)
217+
accountMapFile := getResourceOrgAccountMappings(d, awsMappingType)
218218
if !accountMapFile.Empty() {
219219
accountMapFileBytes, err := json.Marshal(accountMapFile)
220220
if err != nil {
@@ -318,7 +318,7 @@ func resourceLaceworkIntegrationAwsOrgAgentlessScanningRead(d *schema.ResourceDa
318318

319319
}
320320

321-
err = d.Set("org_account_mappings", flattenOrgAccountMappings(accountMapFile))
321+
err = d.Set("org_account_mappings", flattenOrgAccountMappings(accountMapFile, awsMappingType))
322322
if err != nil {
323323
return fmt.Errorf("Error flattening organization account mapping: %s", err)
324324
}
@@ -354,7 +354,7 @@ func resourceLaceworkIntegrationAwsOrgAgentlessScanningUpdate(d *schema.Resource
354354
}
355355

356356
// verify if the user provided an account mapping
357-
accountMapFile := getResourceOrgAccountMappings(d)
357+
accountMapFile := getResourceOrgAccountMappings(d, awsMappingType)
358358
if !accountMapFile.Empty() {
359359
accountMapFileBytes, err := json.Marshal(accountMapFile)
360360
if err != nil {

lacework/resource_lacework_integration_gcp_agentless_scanning.go

Lines changed: 125 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package lacework
22

33
import (
44
"context"
5+
"encoding/json"
56
"fmt"
67
"log"
78
"strings"
@@ -208,6 +209,41 @@ func resourceLaceworkIntegrationGcpAgentlessScanning() *schema.Resource {
208209
Default: nil,
209210
Description: "List of Projects to specifically include/exclude.",
210211
},
212+
"org_account_mappings": {
213+
Type: schema.TypeList,
214+
Optional: true,
215+
Description: "Mapping of AWS accounts to Lacework accounts within a Lacework organization.",
216+
Elem: &schema.Resource{
217+
Schema: map[string]*schema.Schema{
218+
"default_lacework_account": {
219+
Type: schema.TypeString,
220+
Required: true,
221+
Description: "The default Lacework account name where any non-mapped AWS account will appear",
222+
},
223+
"mapping": {
224+
Type: schema.TypeSet,
225+
Required: true,
226+
Description: "A map of AWS accounts to Lacework account. This can be specified multiple times to map multiple Lacework accounts.",
227+
Elem: &schema.Resource{
228+
Schema: map[string]*schema.Schema{
229+
"lacework_account": {
230+
Type: schema.TypeString,
231+
Required: true,
232+
Description: "The Lacework account name where the CloudTrail activity from the selected AWS accounts will appear.",
233+
},
234+
"aws_accounts": {
235+
Type: schema.TypeSet,
236+
Elem: &schema.Schema{Type: schema.TypeString},
237+
MinItems: 1,
238+
Required: true,
239+
Description: "The list of AWS account IDs to map.",
240+
},
241+
},
242+
},
243+
},
244+
},
245+
},
246+
},
211247
},
212248
}
213249
}
@@ -226,28 +262,43 @@ func resourceLaceworkIntegrationGcpAgentlessScanningCreate(d *schema.ResourceDat
226262
}
227263
log.Printf("[INFO] Creating %s integration\n", api.GcpSidekickCloudAccount.String())
228264

265+
gcpSidekickData := api.GcpSidekickData{
266+
ID: d.Get("resource_id").(string),
267+
IDType: resourceLevel.String(),
268+
Credentials: api.GcpSidekickCredentials{
269+
ClientID: d.Get("credentials.0.client_id").(string),
270+
ClientEmail: d.Get("credentials.0.client_email").(string),
271+
PrivateKeyID: d.Get("credentials.0.private_key_id").(string),
272+
PrivateKey: d.Get("credentials.0.private_key").(string),
273+
TokenUri: d.Get("credentials.0.token_uri").(string),
274+
},
275+
SharedBucket: d.Get("bucket_name").(string),
276+
ScanningProjectId: d.Get("scanning_project_id").(string),
277+
ScanFrequency: d.Get("scan_frequency").(int),
278+
ScanContainers: d.Get("scan_containers").(bool),
279+
ScanHostVulnerabilities: d.Get("scan_host_vulnerabilities").(bool),
280+
ScanMultiVolume: d.Get("scan_multi_volume").(bool),
281+
ScanStoppedInstances: d.Get("scan_stopped_instances").(bool),
282+
QueryText: d.Get("query_text").(string),
283+
FilterList: strings.Join(castAttributeToStringSlice(d, "filter_list"), ", "),
284+
}
285+
286+
// verify if the user provided an account mapping
287+
if d.Get("resource_level") == api.GcpOrganizationIntegration {
288+
accountMapFile := getResourceOrgAccountMappings(d, gcpMappingType)
289+
if !accountMapFile.Empty() {
290+
accountMapFileBytes, err := json.Marshal(accountMapFile)
291+
if err != nil {
292+
return err
293+
}
294+
295+
gcpSidekickData.EncodeAccountMappingFile(accountMapFileBytes)
296+
}
297+
}
298+
229299
data := api.NewCloudAccount(d.Get("name").(string),
230300
api.GcpSidekickCloudAccount,
231-
api.GcpSidekickData{
232-
ID: d.Get("resource_id").(string),
233-
IDType: resourceLevel.String(),
234-
Credentials: api.GcpSidekickCredentials{
235-
ClientID: d.Get("credentials.0.client_id").(string),
236-
ClientEmail: d.Get("credentials.0.client_email").(string),
237-
PrivateKeyID: d.Get("credentials.0.private_key_id").(string),
238-
PrivateKey: d.Get("credentials.0.private_key").(string),
239-
TokenUri: d.Get("credentials.0.token_uri").(string),
240-
},
241-
SharedBucket: d.Get("bucket_name").(string),
242-
ScanningProjectId: d.Get("scanning_project_id").(string),
243-
ScanFrequency: d.Get("scan_frequency").(int),
244-
ScanContainers: d.Get("scan_containers").(bool),
245-
ScanHostVulnerabilities: d.Get("scan_host_vulnerabilities").(bool),
246-
ScanMultiVolume: d.Get("scan_multi_volume").(bool),
247-
ScanStoppedInstances: d.Get("scan_stopped_instances").(bool),
248-
QueryText: d.Get("query_text").(string),
249-
FilterList: strings.Join(castAttributeToStringSlice(d, "filter_list"), ", "),
250-
},
301+
gcpSidekickData,
251302
)
252303

253304
if !d.Get("enabled").(bool) {
@@ -290,6 +341,27 @@ func resourceLaceworkIntegrationGcpAgentlessScanningCreate(d *schema.ResourceDat
290341
d.Set("server_token", integration.ServerToken)
291342
d.Set("uri", integration.Uri)
292343

344+
accountMapFileBytes, err := integration.Data.DecodeAccountMappingFile()
345+
if err != nil {
346+
return resource.NonRetryableError(err)
347+
}
348+
349+
accountMapFile := new(accountMappingsFile)
350+
if len(accountMapFileBytes) != 0 {
351+
// The integration has an account mapping file
352+
// unmarshal its content into the account mapping struct
353+
err := json.Unmarshal(accountMapFileBytes, accountMapFile)
354+
if err != nil {
355+
return resource.NonRetryableError(fmt.Errorf("Error decoding organization account mapping: %s", err))
356+
}
357+
358+
}
359+
360+
err = d.Set("org_account_mappings", flattenOrgAccountMappings(accountMapFile, gcpMappingType))
361+
if err != nil {
362+
return resource.NonRetryableError(fmt.Errorf("Error flattening organization account mapping: %s", err))
363+
}
364+
293365
log.Printf("[INFO] Created %s integration with guid: %v\n",
294366
api.GcpSidekickCloudAccount.String(), integration.IntgGuid)
295367
return nil
@@ -360,28 +432,41 @@ func resourceLaceworkIntegrationGcpAgentlessScanningUpdate(d *schema.ResourceDat
360432
resourceLevel = api.GcpOrganizationIntegration
361433
}
362434

435+
gcpSidekickData := api.GcpSidekickData{
436+
ID: d.Get("resource_id").(string),
437+
IDType: resourceLevel.String(),
438+
Credentials: api.GcpSidekickCredentials{
439+
ClientID: d.Get("credentials.0.client_id").(string),
440+
ClientEmail: d.Get("credentials.0.client_email").(string),
441+
PrivateKeyID: d.Get("credentials.0.private_key_id").(string),
442+
PrivateKey: d.Get("credentials.0.private_key").(string),
443+
TokenUri: d.Get("credentials.0.token_uri").(string),
444+
},
445+
SharedBucket: d.Get("bucket_name").(string),
446+
ScanningProjectId: d.Get("scanning_project_id").(string),
447+
ScanFrequency: d.Get("scan_frequency").(int),
448+
ScanContainers: d.Get("scan_containers").(bool),
449+
ScanHostVulnerabilities: d.Get("scan_host_vulnerabilities").(bool),
450+
ScanMultiVolume: d.Get("scan_multi_volume").(bool),
451+
ScanStoppedInstances: d.Get("scan_stopped_instances").(bool),
452+
QueryText: d.Get("query_text").(string),
453+
FilterList: strings.Join(castAttributeToStringSlice(d, "filter_list"), ", "),
454+
}
455+
456+
// verify if the user provided an account mapping
457+
accountMapFile := getResourceOrgAccountMappings(d, gcpMappingType)
458+
if !accountMapFile.Empty() {
459+
accountMapFileBytes, err := json.Marshal(accountMapFile)
460+
if err != nil {
461+
return err
462+
}
463+
464+
gcpSidekickData.EncodeAccountMappingFile(accountMapFileBytes)
465+
}
466+
363467
data := api.NewCloudAccount(d.Get("name").(string),
364468
api.GcpSidekickCloudAccount,
365-
api.GcpSidekickData{
366-
ID: d.Get("resource_id").(string),
367-
IDType: resourceLevel.String(),
368-
Credentials: api.GcpSidekickCredentials{
369-
ClientID: d.Get("credentials.0.client_id").(string),
370-
ClientEmail: d.Get("credentials.0.client_email").(string),
371-
PrivateKeyID: d.Get("credentials.0.private_key_id").(string),
372-
PrivateKey: d.Get("credentials.0.private_key").(string),
373-
TokenUri: d.Get("credentials.0.token_uri").(string),
374-
},
375-
SharedBucket: d.Get("bucket_name").(string),
376-
ScanningProjectId: d.Get("scanning_project_id").(string),
377-
ScanFrequency: d.Get("scan_frequency").(int),
378-
ScanContainers: d.Get("scan_containers").(bool),
379-
ScanHostVulnerabilities: d.Get("scan_host_vulnerabilities").(bool),
380-
ScanMultiVolume: d.Get("scan_multi_volume").(bool),
381-
ScanStoppedInstances: d.Get("scan_stopped_instances").(bool),
382-
QueryText: d.Get("query_text").(string),
383-
FilterList: strings.Join(castAttributeToStringSlice(d, "filter_list"), ", "),
384-
},
469+
gcpSidekickData,
385470
)
386471

387472
if !d.Get("enabled").(bool) {

0 commit comments

Comments
 (0)