From 1e24a229d2f2c54b81809ccb156a9d4283962c32 Mon Sep 17 00:00:00 2001 From: Salim Afiune Date: Tue, 13 Oct 2020 13:43:19 -0600 Subject: [PATCH] feat(api): trigger initial report automatically (#230) We are implementing a temporal workaround to mimic the behavior that is codified inside the Lacework UI where, it automatically triggers an initial report after the creation of Cloud Account Integrations, specifically for Compliance (`AWS_CFG`, `GCP_CFG`, and `AZURE_CFG`) This pull request coves the following projects: * Go Client: https://github.com/lacework/go-sdk/tree/master/api * Lacework CLI: https://github.com/lacework/go-sdk/tree/master/cli We will remove this workaround when RAIN-13422 is done. JIRA: ALLY-196 Signed-off-by: Salim Afiune Maya --- api/api.go | 7 ++++--- api/compliance.go | 9 +++++++++ api/integrations_aws.go | 31 +++++++++++++++++++++++++++++++ api/integrations_aws_test.go | 8 ++++++++ api/integrations_azure.go | 31 +++++++++++++++++++++++++++++++ api/integrations_azure_test.go | 7 +++++++ api/integrations_gcp.go | 31 +++++++++++++++++++++++++++++++ api/integrations_gcp_test.go | 7 +++++++ 8 files changed, 128 insertions(+), 3 deletions(-) diff --git a/api/api.go b/api/api.go index c5cafe7ae..c584b7d00 100644 --- a/api/api.go +++ b/api/api.go @@ -48,9 +48,10 @@ const ( apiComplianceAzureLatestReport = "external/compliance/azure/GetLatestComplianceReport?AZURE_TENANT_ID=%s&AZURE_SUBS_ID=%s" apiComplianceAzureListSubscriptions = "external/compliance/azure/ListSubscriptionsForTenant?AZURE_TENANT_ID=%s" - apiRunReportGcp = "external/runReport/gcp/%s" - apiRunReportAws = "external/runReport/aws/%s" - apiRunReportAzure = "external/runReport/azure/%s" + apiRunReportIntegration = "external/runReport/integration/%s" + apiRunReportGcp = "external/runReport/gcp/%s" + apiRunReportAws = "external/runReport/aws/%s" + apiRunReportAzure = "external/runReport/azure/%s" apiEventsDetails = "external/events/GetEventDetails" apiEventsDateRange = "external/events/GetEventsForDateRange" diff --git a/api/compliance.go b/api/compliance.go index 4de056e57..82c8ea795 100644 --- a/api/compliance.go +++ b/api/compliance.go @@ -35,6 +35,15 @@ func (svc *ComplianceService) ListGcpProjects(orgID string) ( return } +func (svc *ComplianceService) RunIntegrationReport(intgGuid string) ( + response map[string]interface{}, + err error, +) { + apiPath := fmt.Sprintf(apiRunReportIntegration, intgGuid) + err = svc.client.RequestDecoder("POST", apiPath, nil, &response) + return +} + type compGcpProjectsResponse struct { Data []CompGcpProjects `json:"data"` Ok bool `json:"ok"` diff --git a/api/integrations_aws.go b/api/integrations_aws.go index a725ad5e7..a388ee23a 100644 --- a/api/integrations_aws.go +++ b/api/integrations_aws.go @@ -18,6 +18,8 @@ package api +import "go.uber.org/zap" + // NewAwsIntegration returns an instance of AwsIntegration with the provided // integration type, name and data. The type can only be AwsCfgIntegration or // AwsCloudTrailIntegration @@ -69,6 +71,35 @@ func (svc *IntegrationsService) CreateAws(integration AwsIntegration) ( err error, ) { err = svc.create(integration, &response) + if err != nil { + return + } + + // WORKAROUND (@afiune) The backend is currently not triggering an initial + // report automatically after creation of Cloud Account (CFG) Integrations, + // we are implementing this trigger here until we implement it in the backend + // with RAIN-13422 + if len(response.Data) == 0 { + return + } + if integration.Type != AwsCfgIntegration.String() { + return + } + + intgGuid := response.Data[0].IntgGuid + svc.client.log.Info("triggering compliance report", + zap.String("cloud_integration", integration.Type), + zap.String("int_guid", intgGuid), + ) + _, errComplianceReport := svc.client.Compliance.RunIntegrationReport(intgGuid) + if errComplianceReport != nil { + svc.client.log.Warn("unable to trigger compliance report", + zap.String("cloud_integration", integration.Type), + zap.String("int_guid", intgGuid), + zap.String("error", errComplianceReport.Error()), + ) + } + return } diff --git a/api/integrations_aws_test.go b/api/integrations_aws_test.go index 98535cc40..90d766ee4 100644 --- a/api/integrations_aws_test.go +++ b/api/integrations_aws_test.go @@ -48,6 +48,14 @@ func TestIntegrationsCreateAws(t *testing.T) { intgGUID = intgguid.New() fakeServer = lacework.MockServer() ) + + // WORKAROUND (@afiune) The backend is currently not triggering an initial + // report automatically after creation of Cloud Account (CFG) Integrations, + // we are implementing this trigger here until we implement it in the backend + // with RAIN-13422 + fakeServer.MockAPI("external/runReport/integration/"+intgGUID, func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, "POST", r.Method, "RunReport should be a POST method") + }) fakeServer.MockAPI("external/integrations", func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, "POST", r.Method, "CreateAws should be a POST method") diff --git a/api/integrations_azure.go b/api/integrations_azure.go index 3aacf839f..8d91ff04a 100644 --- a/api/integrations_azure.go +++ b/api/integrations_azure.go @@ -18,6 +18,8 @@ package api +import "go.uber.org/zap" + // NewAzureIntegration returns an instance of AzureIntegration with the provided // integration type, name and data. The type can only be AzureCfgIntegration or // AzureActivityLogIntegration @@ -74,6 +76,35 @@ func (svc *IntegrationsService) CreateAzure(integration AzureIntegration) ( err error, ) { err = svc.create(integration, &response) + if err != nil { + return + } + + // WORKAROUND (@afiune) The backend is currently not triggering an initial + // report automatically after creation of Cloud Account (CFG) Integrations, + // we are implementing this trigger here until we implement it in the backend + // with RAIN-13422 + if len(response.Data) == 0 { + return + } + if integration.Type != AzureCfgIntegration.String() { + return + } + + intgGuid := response.Data[0].IntgGuid + svc.client.log.Info("triggering compliance report", + zap.String("cloud_integration", integration.Type), + zap.String("int_guid", intgGuid), + ) + _, errComplianceReport := svc.client.Compliance.RunIntegrationReport(intgGuid) + if errComplianceReport != nil { + svc.client.log.Warn("unable to trigger compliance report", + zap.String("cloud_integration", integration.Type), + zap.String("int_guid", intgGuid), + zap.String("error", errComplianceReport.Error()), + ) + } + return } diff --git a/api/integrations_azure_test.go b/api/integrations_azure_test.go index 94208c933..c2312d1c5 100644 --- a/api/integrations_azure_test.go +++ b/api/integrations_azure_test.go @@ -36,6 +36,13 @@ func TestIntegrationsCreateAzure(t *testing.T) { intgGUID = intgguid.New() fakeServer = lacework.MockServer() ) + // WORKAROUND (@afiune) The backend is currently not triggering an initial + // report automatically after creation of Cloud Account (CFG) Integrations, + // we are implementing this trigger here until we implement it in the backend + // with RAIN-13422 + fakeServer.MockAPI("external/runReport/integration/"+intgGUID, func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, "POST", r.Method, "RunReport should be a POST method") + }) fakeServer.MockAPI("external/integrations", func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, "POST", r.Method, "CreateAzure should be a POST method") diff --git a/api/integrations_gcp.go b/api/integrations_gcp.go index f1be9f978..b9c554b7c 100644 --- a/api/integrations_gcp.go +++ b/api/integrations_gcp.go @@ -18,6 +18,8 @@ package api +import "go.uber.org/zap" + // gcpResourceLevel determines Project or Organization level integration type gcpResourceLevel int @@ -94,6 +96,35 @@ func (svc *IntegrationsService) CreateGcp(data GcpIntegration) ( err error, ) { err = svc.create(data, &response) + if err != nil { + return + } + + // WORKAROUND (@afiune) The backend is currently not triggering an initial + // report automatically after creation of Cloud Account (CFG) Integrations, + // we are implementing this trigger here until we implement it in the backend + // with RAIN-13422 + if len(response.Data) == 0 { + return + } + if data.Type != GcpCfgIntegration.String() { + return + } + + intgGuid := response.Data[0].IntgGuid + svc.client.log.Info("triggering compliance report", + zap.String("cloud_integration", data.Type), + zap.String("int_guid", intgGuid), + ) + _, errComplianceReport := svc.client.Compliance.RunIntegrationReport(intgGuid) + if errComplianceReport != nil { + svc.client.log.Warn("unable to trigger compliance report", + zap.String("cloud_integration", data.Type), + zap.String("int_guid", intgGuid), + zap.String("error", errComplianceReport.Error()), + ) + } + return } diff --git a/api/integrations_gcp_test.go b/api/integrations_gcp_test.go index 7109b7afd..6bde0ec99 100644 --- a/api/integrations_gcp_test.go +++ b/api/integrations_gcp_test.go @@ -36,6 +36,13 @@ func TestIntegrationsCreateGcp(t *testing.T) { intgGUID = intgguid.New() fakeServer = lacework.MockServer() ) + // WORKAROUND (@afiune) The backend is currently not triggering an initial + // report automatically after creation of Cloud Account (CFG) Integrations, + // we are implementing this trigger here until we implement it in the backend + // with RAIN-13422 + fakeServer.MockAPI("external/runReport/integration/"+intgGUID, func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, "POST", r.Method, "RunReport should be a POST method") + }) fakeServer.MockAPI("external/integrations", func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, "POST", r.Method, "CreateGcp should be a POST method")