From 00d8d435585bda710d248d58782ae067673c7bc3 Mon Sep 17 00:00:00 2001 From: Ross Date: Thu, 30 Jun 2022 12:05:21 +0100 Subject: [PATCH] feat(GcpGkeAudit): Add support for GcpGkeAudit apiv2 cloud account integration (#327) * feat(GcpGkeAudit): Add support for GcpGkeAudit apiv2 cloud account integration Signed-off-by: Ross * chore(test): re-enable TestIntegrationAwsEksAuditLog Signed-off-by: Ross * feat(GcpGkeAudit): Resolve errors in gke_audit_log integration resource Signed-off-by: Ross * feat(GcpGkeAudit): Make organization_id optional Signed-off-by: Ross * feat(GcpGkeAudit): Mark private_key output as sensitive Signed-off-by: Ross * feat(GcpGkeAudit): Update GcpGkeAudit integration tests to use google creds Signed-off-by: Ross * feat(GcpGkeAudit): Update GcpGkeAudit integration test to use real pubsub subscription Signed-off-by: Ross * feat(GcpGkeAudit): Update DiffSuppressFunc to check for correct fields Signed-off-by: Ross * chore(GcpGkeAudit): Update go.mod & go.sum with latest go-sdk Signed-off-by: Ross * feat(GcpGkeAudit): Set cred fields in Read func. Also remove PrivateKey & PrivateKeyId from tests Signed-off-by: Ross * chore(docs): Add gcp_gke_audit_log resource docs Signed-off-by: Ross * feat(GcpGkeAuditLog): Add create and update validation on organization_id when integration_type is ORGANIZATION Signed-off-by: Ross --- .../main.tf | 85 +++++ go.mod | 4 +- go.sum | 7 +- integration/integration.go | 11 + ...work_integration_aws_eks_audit_log_test.go | 3 +- ...work_integration_gcp_gke_audit_log_test.go | 97 ++++++ lacework/provider.go | 1 + ..._lacework_integration_gcp_gke_audit_log.go | 317 ++++++++++++++++++ ...lacework_integration_gcp_gke_audit_test.go | 162 +++++++++ .../hashicorp/terraform-json/config.go | 3 + .../hashicorp/terraform-json/plan.go | 13 + .../hashicorp/terraform-json/schemas.go | 7 + .../hashicorp/terraform-json/state.go | 28 ++ vendor/github.com/lacework/go-sdk/api/api.go | 3 + .../api/cloud_accounts_gcp_gke_audit.go | 4 +- .../github.com/lacework/go-sdk/api/policy.go | 9 +- .../lacework/go-sdk/api/policy_exceptions.go | 109 ++++++ vendor/github.com/lacework/go-sdk/api/v2.go | 2 +- .../github.com/lacework/go-sdk/api/version.go | 4 +- .../go-sdk/api/vulnerabilities_container.go | 2 +- vendor/modules.txt | 4 +- ...ntegration_gcp_gke_audit_log.html.markdown | 61 ++++ website/lacework.erb | 3 + 23 files changed, 923 insertions(+), 16 deletions(-) create mode 100644 examples/resource_lacework_integration_gcp_gke_audit_log/main.tf create mode 100644 integration/resource_lacework_integration_gcp_gke_audit_log_test.go create mode 100644 lacework/resource_lacework_integration_gcp_gke_audit_log.go create mode 100644 lacework/resource_lacework_integration_gcp_gke_audit_test.go create mode 100644 vendor/github.com/lacework/go-sdk/api/policy_exceptions.go create mode 100644 website/docs/r/integration_gcp_gke_audit_log.html.markdown diff --git a/examples/resource_lacework_integration_gcp_gke_audit_log/main.tf b/examples/resource_lacework_integration_gcp_gke_audit_log/main.tf new file mode 100644 index 000000000..259416d7b --- /dev/null +++ b/examples/resource_lacework_integration_gcp_gke_audit_log/main.tf @@ -0,0 +1,85 @@ +terraform { + required_providers { + lacework = { + source = "lacework/lacework" + } + } +} + +variable "name" { + type = string + default = "GCP GKE audit log integration example" +} + +variable "client_id" { + type = string + default = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" +} + +variable "client_email" { + type = string + default = "email@some-project-name.iam.gserviceaccount.com" +} + +variable "private_key_id" { + type = string + default = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" +} + +variable "private_key" { + type = string + default = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +} + +variable "integration_type" { + type = string + default = "PROJECT" +} + +variable "project_id" { + type = string + default = "example-project-id" +} + +variable "subscription" { + type = string + default = "projects/example-project-id/subscriptions/example-subscription" +} + +resource "lacework_integration_gcp_gke_audit_log" "example" { + name = var.name + credentials { + client_id = var.client_id + client_email = var.client_email + private_key_id = var.private_key_id + private_key = var.private_key + } + integration_type = var.integration_type + project_id = var.project_id + subscription = var.subscription + retries = 10 +} + +output "name" { + value = lacework_integration_gcp_gke_audit_log.example.name +} + +output "client_id" { + value = lacework_integration_gcp_gke_audit_log.example.credentials[0].client_id +} + +output "client_email" { + value = lacework_integration_gcp_gke_audit_log.example.credentials[0].client_email +} + +output "integration_type" { + value = lacework_integration_gcp_gke_audit_log.example.integration_type +} + +output "project_id" { + value = lacework_integration_gcp_gke_audit_log.example.project_id +} + +output "subscription" { + value = lacework_integration_gcp_gke_audit_log.example.subscription +} \ No newline at end of file diff --git a/go.mod b/go.mod index 8627b5f86..9e9a915da 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( github.com/gruntwork-io/terratest v0.40.17 github.com/hashicorp/terraform-plugin-sdk/v2 v2.13.0 - github.com/lacework/go-sdk v0.36.1-0.20220621101646-85d5214a6d09 + github.com/lacework/go-sdk v0.37.0 github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.7.3 golang.org/x/text v0.3.7 @@ -41,7 +41,7 @@ require ( github.com/hashicorp/hcl/v2 v2.12.0 // indirect github.com/hashicorp/logutils v1.0.0 // indirect github.com/hashicorp/terraform-exec v0.16.1 // indirect - github.com/hashicorp/terraform-json v0.13.0 // indirect + github.com/hashicorp/terraform-json v0.14.0 // indirect github.com/hashicorp/terraform-plugin-go v0.8.0 // indirect github.com/hashicorp/terraform-plugin-log v0.3.0 // indirect github.com/hashicorp/terraform-registry-address v0.0.0-20210412075316-9b2996cce896 // indirect diff --git a/go.sum b/go.sum index 501830e7a..a84e4b118 100644 --- a/go.sum +++ b/go.sum @@ -243,8 +243,9 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO github.com/hashicorp/terraform-exec v0.16.0/go.mod h1:wB5JHmjxZ/YVNZuv9npAXKmz5pGyxy8PSi0GRR0+YjA= github.com/hashicorp/terraform-exec v0.16.1 h1:NAwZFJW2L2SaCBVZoVaH8LPImLOGbPLkSHy0IYbs2uE= github.com/hashicorp/terraform-exec v0.16.1/go.mod h1:aj0lVshy8l+MHhFNoijNHtqTJQI3Xlowv5EOsEaGO7M= -github.com/hashicorp/terraform-json v0.13.0 h1:Li9L+lKD1FO5RVFRM1mMMIBDoUHslOniyEi5CM+FWGY= github.com/hashicorp/terraform-json v0.13.0/go.mod h1:y5OdLBCT+rxbwnpxZs9kGL7R9ExU76+cpdY8zHwoazk= +github.com/hashicorp/terraform-json v0.14.0 h1:sh9iZ1Y8IFJLx+xQiKHGud6/TSUCM0N8e17dKDpqV7s= +github.com/hashicorp/terraform-json v0.14.0/go.mod h1:5A9HIWPkk4e5aeeXIBbkcOvaZbIYnAIkEyqP2pNSckM= github.com/hashicorp/terraform-plugin-go v0.8.0 h1:MvY43PcDj9VlBjYifBWCO/6j1wf106xU8d5Tob/WRs0= github.com/hashicorp/terraform-plugin-go v0.8.0/go.mod h1:E3GuvfX0Pz2Azcl6BegD6t51StXsVZMOYQoGO8mkHM0= github.com/hashicorp/terraform-plugin-log v0.3.0 h1:NPENNOjaJSVX0f7JJTl4f/2JKRPQ7S2ZN9B4NSqq5kA= @@ -294,8 +295,8 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/lacework/go-sdk v0.36.1-0.20220621101646-85d5214a6d09 h1:Xd4AwUYdfwptB0tHsoPmrLGHs+Qxh5VshuVxeLz8wUc= -github.com/lacework/go-sdk v0.36.1-0.20220621101646-85d5214a6d09/go.mod h1:GBudIEhnE2fYt4EPIerH2nAoZsIsKA4qnhpzuDaMhGw= +github.com/lacework/go-sdk v0.37.0 h1:/9E47M+zFHG/ifGJbpMnGeojF3WqWUlkcZ9sK/gaxEc= +github.com/lacework/go-sdk v0.37.0/go.mod h1:7puR6CiRN3sS47CQxDjKwk1BJZhOzXwiVrwshmLPMTA= github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= diff --git a/integration/integration.go b/integration/integration.go index 42d1987b6..1002785b7 100644 --- a/integration/integration.go +++ b/integration/integration.go @@ -68,6 +68,17 @@ func GetCloudAccountEksAuditLogData(result string) api.AwsEksAuditData { return response.Data.Data } +func GetCloudAccountGkeAuditLogData(result string) api.GcpGkeAuditData { + id := GetIDFromTerraResults(result) + + response, err := LwClient.V2.CloudAccounts.GetGcpGkeAudit(id) + if err != nil { + log.Fatalf("Unable to find gke audit log id: %s\n Response: %v", id, response) + } + + return response.Data.Data +} + func GetIntegrationName(result string, integration string) string { var res api.V2CommonIntegration id := GetIDFromTerraResults(result) diff --git a/integration/resource_lacework_integration_aws_eks_audit_log_test.go b/integration/resource_lacework_integration_aws_eks_audit_log_test.go index 0997d265a..0601f9139 100644 --- a/integration/resource_lacework_integration_aws_eks_audit_log_test.go +++ b/integration/resource_lacework_integration_aws_eks_audit_log_test.go @@ -12,8 +12,7 @@ import ( // // It uses the go-sdk to verify the created integration, // applies an update with new integration name and destroys it -//nolint -func _TestIntegrationAwsEksAuditLog(t *testing.T) { +func TestIntegrationAwsEksAuditLog(t *testing.T) { terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ TerraformDir: "../examples/resource_lacework_integration_aws_eks_audit_log", Vars: map[string]interface{}{ diff --git a/integration/resource_lacework_integration_gcp_gke_audit_log_test.go b/integration/resource_lacework_integration_gcp_gke_audit_log_test.go new file mode 100644 index 000000000..88119dbb0 --- /dev/null +++ b/integration/resource_lacework_integration_gcp_gke_audit_log_test.go @@ -0,0 +1,97 @@ +package integration + +import ( + "testing" + + "github.com/gruntwork-io/terratest/modules/terraform" + "github.com/stretchr/testify/assert" +) + +// TestIntegrationGcpGkeAuditLog applies integration terraform: +// => '../examples/resource_lacework_integration_gcp_gke_audit_log' +// +// It uses the go-sdk to verify the created integration, +// applies an update with new integration name and destroys it +func TestIntegrationGcpGkeAuditLog(t *testing.T) { + gcreds, err := googleLoadDefaultCredentials() + if assert.Nil(t, err, "this test requires you to set GOOGLE_CREDENTIALS environment variable") { + terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ + TerraformDir: "../examples/resource_lacework_integration_gcp_gke_audit_log", + Vars: map[string]interface{}{ + "name": "GCP GKE audit log integration example", + "client_id": gcreds.ClientID, + "client_email": gcreds.ClientEmail, + "private_key_id": gcreds.PrivateKeyID, + "private_key": gcreds.PrivateKey, + "integration_type": "PROJECT", + "project_id": gcreds.ProjectID, + "subscription": "projects/techally-hipstershop-275821/subscriptions/gcp-gke-audit-log-subscription", + }, + }) + defer terraform.Destroy(t, terraformOptions) + + // Create new GcpGkeAudit Integration + create := terraform.InitAndApplyAndIdempotent(t, terraformOptions) + actualClientId := terraform.Output(t, terraformOptions, "client_id") + actualClientEmail := terraform.Output(t, terraformOptions, "client_email") + actualIntegrationType := terraform.Output(t, terraformOptions, "integration_type") + actualProjectId := terraform.Output(t, terraformOptions, "project_id") + actualSubscription := terraform.Output(t, terraformOptions, "subscription") + assert.Equal( + t, + "GCP GKE audit log integration example", + GetCloudAccountIntegrationName(create), + ) + assert.Equal(t, gcreds.ClientID, actualClientId) + assert.Equal(t, gcreds.ClientEmail, actualClientEmail) + assert.Equal(t, "PROJECT", actualIntegrationType) + assert.Equal(t, gcreds.ProjectID, actualProjectId) + assert.Equal(t, "projects/techally-hipstershop-275821/subscriptions/gcp-gke-audit-log-subscription", actualSubscription) + + // Update GcpGkeAudit Integration + terraformOptions.Vars = map[string]interface{}{ + "name": "GcpGkeAudit log integration updated", + "client_id": gcreds.ClientID, + "client_email": gcreds.ClientEmail, + "private_key_id": gcreds.PrivateKeyID, + "private_key": gcreds.PrivateKey, + "integration_type": "PROJECT", + "project_id": gcreds.ProjectID, + "subscription": "projects/techally-hipstershop-275821/subscriptions/gcp-gke-audit-log-subscription", + } + + update := terraform.ApplyAndIdempotent(t, terraformOptions) + actualClientId = terraform.Output(t, terraformOptions, "client_id") + actualClientEmail = terraform.Output(t, terraformOptions, "client_email") + actualIntegrationType = terraform.Output(t, terraformOptions, "integration_type") + actualProjectId = terraform.Output(t, terraformOptions, "project_id") + actualSubscription = terraform.Output(t, terraformOptions, "subscription") + assert.Equal( + t, + "GcpGkeAudit log integration updated", + GetCloudAccountIntegrationName(update), + ) + assert.Equal(t, gcreds.ClientID, actualClientId) + assert.Equal(t, gcreds.ClientEmail, actualClientEmail) + assert.Equal(t, "PROJECT", actualIntegrationType) + assert.Equal(t, gcreds.ProjectID, actualProjectId) + assert.Equal(t, "projects/techally-hipstershop-275821/subscriptions/gcp-gke-audit-log-subscription", actualSubscription) + + // Update GcpGkeAudit with invalid configuration + terraformOptions.Vars = map[string]interface{}{ + "name": "GcpGkeAudit log integration updated", + "client_id": gcreds.ClientID, + "client_email": gcreds.ClientEmail, + "private_key_id": gcreds.PrivateKeyID, + "private_key": gcreds.PrivateKey, + "integration_type": "ORGANIZATION", + "project_id": gcreds.ProjectID, + "subscription": "projects/techally-hipstershop-275821/subscriptions/gcp-gke-audit-log-subscription", + } + + _, err = terraform.ApplyAndIdempotentE(t, terraformOptions) + assert.Contains(t, err.Error(), + "error updating cloud account integration: organization_id MUST be"+ + " set when integration_type is ORGANIZATION") + } +} diff --git a/lacework/provider.go b/lacework/provider.go index 17a820b23..d1d09d139 100644 --- a/lacework/provider.go +++ b/lacework/provider.go @@ -92,6 +92,7 @@ func Provider() *schema.Provider { "lacework_integration_ecr": resourceLaceworkIntegrationEcr(), "lacework_integration_gcp_cfg": resourceLaceworkIntegrationGcpCfg(), "lacework_integration_gcp_at": resourceLaceworkIntegrationGcpAt(), + "lacework_integration_gcp_gke_audit_log": resourceLaceworkIntegrationGcpGkeAuditLog(), "lacework_integration_gar": resourceLaceworkIntegrationGar(), "lacework_integration_gcr": resourceLaceworkIntegrationGcr(), "lacework_integration_ghcr": resourceLaceworkIntegrationGhcr(), diff --git a/lacework/resource_lacework_integration_gcp_gke_audit_log.go b/lacework/resource_lacework_integration_gcp_gke_audit_log.go new file mode 100644 index 000000000..47d849035 --- /dev/null +++ b/lacework/resource_lacework_integration_gcp_gke_audit_log.go @@ -0,0 +1,317 @@ +package lacework + +import ( + "context" + "fmt" + "log" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/lacework/go-sdk/api" +) + +func resourceLaceworkIntegrationGcpGkeAuditLog() *schema.Resource { + return &schema.Resource{ + Create: resourceLaceworkIntegrationGcpGkeAuditLogCreate, + Read: resourceLaceworkIntegrationGcpGkeAuditLogRead, + Update: resourceLaceworkIntegrationGcpGkeAuditLogUpdate, + Delete: resourceLaceworkIntegrationGcpGkeAuditLogDelete, + Schema: gcpGkeAuditLogIntegrationSchema, + Importer: &schema.ResourceImporter{State: importLaceworkIntegration}, + } +} + +var gcpGkeAuditLogIntegrationSchema = map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + Description: "The integration name.", + }, + "intg_guid": { + Type: schema.TypeString, + Computed: true, + }, + "enabled": { + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "The state of the external integration.", + }, + "retries": { + Type: schema.TypeInt, + Optional: true, + Default: 5, + Description: "The number of attempts to create the external integration.", + }, + "credentials": { + Type: schema.TypeList, + MaxItems: 1, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "client_id": { + Type: schema.TypeString, + Required: true, + }, + "private_key_id": { + Type: schema.TypeString, + Required: true, + Sensitive: true, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + // @afiune we can't compare this element since our API, for security reasons, + // does NOT return the private key configured in the Lacework server. So if + // any other element changed from the credentials then we trigger a diff + return !d.HasChanges( + "name", "integration_type", "project_id", "organization_id", + "subscription", "enabled", + "credentials.0.client_id", + "credentials.0.client_email", + ) + }, + }, + "client_email": { + Type: schema.TypeString, + Required: true, + }, + "private_key": { + Type: schema.TypeString, + Required: true, + Sensitive: true, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + // @afiune we can't compare this element since our API, for security reasons, + // does NOT return the private key configured in the Lacework server. So if + // any other element changed from the credentials then we trigger a diff + return !d.HasChanges( + "name", "integration_type", "project_id", "organization_id", + "subscription", "enabled", + "credentials.0.client_id", + "credentials.0.client_email", + ) + }, + }, + }, + }, + }, + "integration_type": { + Type: schema.TypeString, + Required: true, + StateFunc: func(val interface{}) string { + return strings.ToUpper(val.(string)) + }, + ValidateFunc: func(value interface{}, key string) ([]string, []error) { + switch strings.ToUpper(value.(string)) { + case "PROJECT", "ORGANIZATION": + return nil, nil + default: + return nil, []error{ + fmt.Errorf("%s: can only be either 'PROJECT' or 'ORGANIZATION'", key), + } + } + }, + }, + "organization_id": { + Type: schema.TypeString, + Optional: true, + Description: "The GCP Organization ID (required when integration_type is organization).", + }, + "project_id": { + Type: schema.TypeString, + Required: true, + Description: "The GCP Project ID.", + }, + "subscription": { + Type: schema.TypeString, + Required: true, + Description: "The PubSub Subscription.", + }, + "is_org": { + Type: schema.TypeBool, + Computed: true, + }, + "created_or_updated_time": { + Type: schema.TypeString, + Computed: true, + }, + "created_or_updated_by": { + Type: schema.TypeString, + Computed: true, + }, +} + +func resourceLaceworkIntegrationGcpGkeAuditLogCreate(d *schema.ResourceData, meta interface{}) error { + var ( + lacework = meta.(*api.Client) + retries = d.Get("retries").(int) + gcpGkeAuditLogData = api.GcpGkeAuditData{ + Credentials: api.GcpGkeAuditCredentials{ + ClientId: d.Get("credentials.0.client_id").(string), + ClientEmail: d.Get("credentials.0.client_email").(string), + PrivateKeyId: d.Get("credentials.0.private_key_id").(string), + PrivateKey: d.Get("credentials.0.private_key").(string), + }, + IntegrationType: strings.ToUpper(d.Get("integration_type").(string)), + OrganizationId: d.Get("organization_id").(string), + ProjectId: d.Get("project_id").(string), + SubscriptionName: d.Get("subscription").(string), + } + ) + + if d.Get("integration_type").(string) == "ORGANIZATION" && + (d.Get("organization_id") == nil || d.Get("organization_id") == "") { + return fmt.Errorf("error creating cloud account integration: " + + "organization_id MUST be set when integration_type is ORGANIZATION, ") + } + + gcpGkeAuditLog := api.NewCloudAccount(d.Get("name").(string), + api.GcpGkeAuditCloudAccount, + gcpGkeAuditLogData, + ) + + if !d.Get("enabled").(bool) { + gcpGkeAuditLog.Enabled = 0 + } + + return resource.RetryContext(context.Background(), d.Timeout(schema.TimeoutCreate), func() *resource.RetryError { + retries-- + log.Printf("[INFO] Creating %s cloud account integration\n", api.GcpGkeAuditCloudAccount.String()) + response, err := lacework.V2.CloudAccounts.Create(gcpGkeAuditLog) + if err != nil { + if retries <= 0 { + return resource.NonRetryableError( + fmt.Errorf("error creating %s cloud account integration: %s", + api.GcpGkeAuditCloudAccount.String(), err, + )) + } + log.Printf( + "[INFO] Unable to create %s cloud account integration. (retrying %d more time(s))\n%s\n", + api.GcpGkeAuditCloudAccount.String(), retries, err, + ) + return resource.RetryableError(fmt.Errorf( + "unable to create %s cloud account integration (retrying %d more time(s))", + api.GcpGkeAuditCloudAccount.String(), retries, + )) + } + + cloudAccount := response.Data + d.SetId(cloudAccount.IntgGuid) + d.Set("name", cloudAccount.Name) + d.Set("intg_guid", cloudAccount.IntgGuid) + d.Set("enabled", cloudAccount.Enabled == 1) + + d.Set("created_or_updated_time", cloudAccount.CreatedOrUpdatedTime) + d.Set("created_or_updated_by", cloudAccount.CreatedOrUpdatedBy) + d.Set("type_name", cloudAccount.Type) // @afiune should we deprecate? + d.Set("is_org", cloudAccount.IsOrg == 1) + + log.Printf("[INFO] Created %s cloud account integration with guid: %v\n", + api.GcpGkeAuditCloudAccount.String(), cloudAccount.IntgGuid) + return nil + }) +} + +func resourceLaceworkIntegrationGcpGkeAuditLogRead(d *schema.ResourceData, meta interface{}) error { + lacework := meta.(*api.Client) + + log.Printf("[INFO] Reading %s cloud account integration with guid: %v\n", api.GcpGkeAuditCloudAccount.String(), d.Id()) + response, err := lacework.V2.CloudAccounts.GetGcpGkeAudit(d.Id()) + if err != nil { + return resourceNotFound(d, err) + } + + cloudAccount := response.Data + if cloudAccount.IntgGuid == d.Id() { + d.Set("name", cloudAccount.Name) + d.Set("intg_guid", cloudAccount.IntgGuid) + d.Set("enabled", cloudAccount.Enabled == 1) + d.Set("created_or_updated_time", cloudAccount.CreatedOrUpdatedTime) + d.Set("created_or_updated_by", cloudAccount.CreatedOrUpdatedBy) + d.Set("type_name", cloudAccount.Type) + d.Set("org_level", cloudAccount.IsOrg == 1) + + creds := make(map[string]string) + creds["client_id"] = response.Data.Data.Credentials.ClientId + creds["client_email"] = response.Data.Data.Credentials.ClientEmail + + d.Set("credentials", []map[string]string{creds}) + d.Set("integration_type", cloudAccount.Data.IntegrationType) + d.Set("organization_id", cloudAccount.Data.OrganizationId) + d.Set("project_id", cloudAccount.Data.ProjectId) + d.Set("subscription", cloudAccount.Data.SubscriptionName) + + log.Printf("[INFO] Read %s cloud account integration with guid: %v\n", + api.GcpGkeAuditCloudAccount.String(), cloudAccount.IntgGuid, + ) + return nil + } + + d.SetId("") + return nil +} + +func resourceLaceworkIntegrationGcpGkeAuditLogUpdate(d *schema.ResourceData, meta interface{}) error { + var ( + lacework = meta.(*api.Client) + gcpGkeAuditLogData = api.GcpGkeAuditData{ + Credentials: api.GcpGkeAuditCredentials{ + ClientId: d.Get("credentials.0.client_id").(string), + ClientEmail: d.Get("credentials.0.client_email").(string), + PrivateKeyId: d.Get("credentials.0.private_key_id").(string), + PrivateKey: d.Get("credentials.0.private_key").(string), + }, + IntegrationType: strings.ToUpper(d.Get("integration_type").(string)), + OrganizationId: d.Get("organization_id").(string), + ProjectId: d.Get("project_id").(string), + SubscriptionName: d.Get("subscription").(string), + } + ) + + gcpGkeAuditLog := api.NewCloudAccount(d.Get("name").(string), + api.GcpGkeAuditCloudAccount, + gcpGkeAuditLogData, + ) + + if d.Get("integration_type").(string) == "ORGANIZATION" && + (d.Get("organization_id") == nil || d.Get("organization_id") == "") { + return fmt.Errorf("error updating cloud account integration: " + + "organization_id MUST be set when integration_type is ORGANIZATION") + } + + if !d.Get("enabled").(bool) { + gcpGkeAuditLog.Enabled = 0 + } + + gcpGkeAuditLog.IntgGuid = d.Id() + + log.Printf("[INFO] Updating %s integration with data:\n%+v\n", api.GcpGkeAuditCloudAccount.String(), gcpGkeAuditLog.IntgGuid) + response, err := lacework.V2.CloudAccounts.UpdateGcpGkeAudit(gcpGkeAuditLog) + if err != nil { + return err + } + + cloudAccount := response.Data + d.Set("name", cloudAccount.Name) + d.Set("intg_guid", cloudAccount.IntgGuid) + d.Set("enabled", cloudAccount.Enabled == 1) + d.Set("created_or_updated_time", cloudAccount.CreatedOrUpdatedTime) + d.Set("created_or_updated_by", cloudAccount.CreatedOrUpdatedBy) + d.Set("type_name", cloudAccount.Type) + d.Set("is_org", cloudAccount.IsOrg == 1) + + log.Printf("[INFO] Updated %s cloud account integration with guid: %v\n", api.GcpGkeAuditCloudAccount.String(), d.Id()) + return nil +} + +func resourceLaceworkIntegrationGcpGkeAuditLogDelete(d *schema.ResourceData, meta interface{}) error { + lacework := meta.(*api.Client) + + log.Printf("[INFO] Deleting %s cloud account integration with guid: %v\n", api.GcpGkeAuditCloudAccount.String(), d.Id()) + err := lacework.V2.CloudAccounts.Delete(d.Id()) + if err != nil { + return err + } + + log.Printf("[INFO] Deleted %s cloud account integration with guid: %v\n", api.GcpGkeAuditCloudAccount.String(), d.Id()) + return nil +} diff --git a/lacework/resource_lacework_integration_gcp_gke_audit_test.go b/lacework/resource_lacework_integration_gcp_gke_audit_test.go new file mode 100644 index 000000000..3539564f4 --- /dev/null +++ b/lacework/resource_lacework_integration_gcp_gke_audit_test.go @@ -0,0 +1,162 @@ +package lacework + +import ( + "fmt" + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/lacework/go-sdk/api" +) + +const ( + testAccIntegrationGcpGkeAuditResourceType = "GcpGkeAudit" + testAccIntegrationGcpGkeAuditResourceName = "example" + + // Environment variables for testing GCP GKE Audit + testAccIntegrationGcpGkeIntegrationType = "Project" + testAccIntegrationGcpGkeProjectID = "GCP_GKE_PROJECT" + testAccIntegrationGcpGkeOrganizationID = "GCP_GKE_ORG" + testAccIntegrationGcpGkeSubscription = "GCP_SUBSCRIPTION" +) + +func TestAccIntegrationGcpGkeAudit(t *testing.T) { + resourceTypeAndName := fmt.Sprintf("%s.%s", + testAccIntegrationGcpGkeAuditResourceType, + testAccIntegrationGcpGkeAuditResourceName, + ) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccIntegrationGcpGkeAuditEnvVarsPreCheck(t) + }, + Providers: testAccProviders, + CheckDestroy: testAccCheckIntegrationGcpGkeAuditDestroy, + Steps: []resource.TestStep{ + { + Config: testAccIntegrationGcpGkeAuditConfig( + true, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckIntegrationGcpGkeAuditExists(resourceTypeAndName), + resource.TestCheckResourceAttr(resourceTypeAndName, "enabled", "true"), + ), + }, + { + Config: testAccIntegrationGcpGkeAuditConfig( + false, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckIntegrationGcpGkeAuditExists(resourceTypeAndName), + resource.TestCheckResourceAttr(resourceTypeAndName, "enabled", "false"), + ), + }, + }, + }) +} + +func testAccCheckIntegrationGcpGkeAuditDestroy(s *terraform.State) error { + lacework := testAccProvider.Meta().(*api.Client) + + for _, rs := range s.RootModule().Resources { + + if rs.Type != testAccIntegrationGcpGkeAuditResourceType { + continue + } + + response, err := lacework.Integrations.GetGcp(rs.Primary.ID) + if err != nil { + return err + } + + for _, integration := range response.Data { + if integration.IntgGuid == rs.Primary.ID { + return fmt.Errorf("the Google GKE Audit integration (%s) still exists", + rs.Primary.ID) + } + } + } + + return nil +} + +func testAccCheckIntegrationGcpGkeAuditExists(resourceTypeAndName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + lacework := testAccProvider.Meta().(*api.Client) + + rs, ok := s.RootModule().Resources[resourceTypeAndName] + if !ok { + return fmt.Errorf("resource (%s) not found", resourceTypeAndName) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("resource (%s) ID not set", resourceTypeAndName) + } + + response, err := lacework.Integrations.GetGcp(rs.Primary.ID) + if err != nil { + return err + } + + if len(response.Data) < 1 { + return fmt.Errorf("the Google GKE Audit integration (%s) doesn't exist", rs.Primary.ID) + } + + for _, integration := range response.Data { + if integration.IntgGuid == rs.Primary.ID { + return nil + } + } + + return fmt.Errorf("the Google GKE Audit integration (%s) doesn't exist", rs.Primary.ID) + } +} + +func testAccIntegrationGcpGkeAuditEnvVarsPreCheck(t *testing.T) { + if v := os.Getenv(testAccIntegrationGcpEnvClientID); v == "" { + t.Fatalf("%s must be set for acceptance tests", testAccIntegrationGcpEnvClientID) + } + if v := os.Getenv(testAccIntegrationGcpEnvPrivateKeyID); v == "" { + t.Fatalf("%s must be set for acceptance tests", testAccIntegrationGcpEnvPrivateKeyID) + } + if v := os.Getenv(testAccIntegrationGcpEnvPrivateKey); v == "" { + t.Fatalf("%s must be set for acceptance tests", testAccIntegrationGcpEnvPrivateKey) + } + if v := os.Getenv(testAccIntegrationGcpEnvClientEmail); v == "" { + t.Fatalf("%s must be set for acceptance tests", testAccIntegrationGcpEnvClientEmail) + } +} + +func testAccIntegrationGcpGkeAuditConfig(enabled bool) string { + return fmt.Sprintf(` +resource "%s" "%s" { + name = "Example-GCP-GKE-Audit-Integration" + enabled = %t + credentials { + client_id = "%s" + client_email = "%s" + private_key_id = "%s" + private_key = "%s" + } + integration_type = "%s" + project_id = "%s" + organization_id = "%s" + subscription = "%s" +} +`, + testAccIntegrationGcpGkeAuditResourceType, + testAccIntegrationGcpGkeAuditResourceName, + enabled, + os.Getenv(testAccIntegrationGcpEnvClientID), + os.Getenv(testAccIntegrationGcpEnvClientEmail), + os.Getenv(testAccIntegrationGcpEnvPrivateKeyID), + os.Getenv(testAccIntegrationGcpEnvPrivateKey), + testAccIntegrationGcpGkeIntegrationType, + testAccIntegrationGcpGkeProjectID, + testAccIntegrationGcpGkeOrganizationID, + testAccIntegrationGcpGkeSubscription, + ) +} diff --git a/vendor/github.com/hashicorp/terraform-json/config.go b/vendor/github.com/hashicorp/terraform-json/config.go index e093cfa8b..5ebe4bc84 100644 --- a/vendor/github.com/hashicorp/terraform-json/config.go +++ b/vendor/github.com/hashicorp/terraform-json/config.go @@ -48,6 +48,9 @@ type ProviderConfig struct { // The name of the provider, ie: "aws". Name string `json:"name,omitempty"` + // The fully-specified name of the provider, ie: "registry.terraform.io/hashicorp/aws". + FullName string `json:"full_name,omitempty"` + // The alias of the provider, ie: "us-east-1". Alias string `json:"alias,omitempty"` diff --git a/vendor/github.com/hashicorp/terraform-json/plan.go b/vendor/github.com/hashicorp/terraform-json/plan.go index 1de5bc82a..274006a01 100644 --- a/vendor/github.com/hashicorp/terraform-json/plan.go +++ b/vendor/github.com/hashicorp/terraform-json/plan.go @@ -55,6 +55,19 @@ type Plan struct { // The Terraform configuration used to make the plan. Config *Config `json:"configuration,omitempty"` + + // RelevantAttributes represents any resource instances and their + // attributes which may have contributed to the planned changes + RelevantAttributes []ResourceAttribute `json:"relevant_attributes,omitempty"` +} + +// ResourceAttribute describes a full path to a resource attribute +type ResourceAttribute struct { + // Resource describes resource instance address (e.g. null_resource.foo) + Resource string `json:"resource"` + // Attribute describes the attribute path using a lossy representation + // of cty.Path. (e.g. ["id"] or ["objects", 0, "val"]). + Attribute []json.RawMessage `json:"attribute"` } // Validate checks to ensure that the plan is present, and the diff --git a/vendor/github.com/hashicorp/terraform-json/schemas.go b/vendor/github.com/hashicorp/terraform-json/schemas.go index 2360231d0..027224b62 100644 --- a/vendor/github.com/hashicorp/terraform-json/schemas.go +++ b/vendor/github.com/hashicorp/terraform-json/schemas.go @@ -223,6 +223,13 @@ type SchemaAttribute struct { Sensitive bool `json:"sensitive,omitempty"` } +// jsonSchemaAttribute describes an attribute within a schema block +// in a middle-step internal representation before marshalled into +// a more useful SchemaAttribute with cty.Type. +// +// This avoid panic on marshalling cty.NilType (from cty upstream) +// which the default Go marshaller cannot ignore because it's a +// not nil-able struct. type jsonSchemaAttribute struct { AttributeType json.RawMessage `json:"type,omitempty"` AttributeNestedType *SchemaNestedAttributeType `json:"nested_type,omitempty"` diff --git a/vendor/github.com/hashicorp/terraform-json/state.go b/vendor/github.com/hashicorp/terraform-json/state.go index bece5c220..3c3f6a4b0 100644 --- a/vendor/github.com/hashicorp/terraform-json/state.go +++ b/vendor/github.com/hashicorp/terraform-json/state.go @@ -7,6 +7,7 @@ import ( "fmt" "github.com/hashicorp/go-version" + "github.com/zclconf/go-cty/cty" ) // StateFormatVersionConstraints defines the versions of the JSON state format @@ -175,4 +176,31 @@ type StateOutput struct { // The value of the output. Value interface{} `json:"value,omitempty"` + + // The type of the output. + Type cty.Type `json:"type,omitempty"` +} + +// jsonStateOutput describes an output value in a middle-step internal +// representation before marshalled into a more useful StateOutput with cty.Type. +// +// This avoid panic on marshalling cty.NilType (from cty upstream) +// which the default Go marshaller cannot ignore because it's a +// not nil-able struct. +type jsonStateOutput struct { + Sensitive bool `json:"sensitive"` + Value interface{} `json:"value,omitempty"` + Type json.RawMessage `json:"type,omitempty"` +} + +func (so *StateOutput) MarshalJSON() ([]byte, error) { + jsonSa := &jsonStateOutput{ + Sensitive: so.Sensitive, + Value: so.Value, + } + if so.Type != cty.NilType { + outputType, _ := so.Type.MarshalJSON() + jsonSa.Type = outputType + } + return json.Marshal(jsonSa) } diff --git a/vendor/github.com/lacework/go-sdk/api/api.go b/vendor/github.com/lacework/go-sdk/api/api.go index bfd3879f7..c96157ee0 100644 --- a/vendor/github.com/lacework/go-sdk/api/api.go +++ b/vendor/github.com/lacework/go-sdk/api/api.go @@ -108,6 +108,9 @@ const ( apiV2AgentAccessTokensSearch = "v2/AgentAccessTokens/search" apiV2AgentAccessTokenFromID = "v2/AgentAccessTokens/%s" + apiV2PolicyExceptions = "v2/Exceptions?policyId=%s" + apiV2PolicyExceptionsFromExceptionID = "v2/Exceptions/%s?policyId=%s" + apiV2Policies = "v2/Policies" apiV2Queries = "v2/Queries" apiV2QueriesExecute = "v2/Queries/execute" diff --git a/vendor/github.com/lacework/go-sdk/api/cloud_accounts_gcp_gke_audit.go b/vendor/github.com/lacework/go-sdk/api/cloud_accounts_gcp_gke_audit.go index c17086761..d5f3ab15c 100644 --- a/vendor/github.com/lacework/go-sdk/api/cloud_accounts_gcp_gke_audit.go +++ b/vendor/github.com/lacework/go-sdk/api/cloud_accounts_gcp_gke_audit.go @@ -57,6 +57,6 @@ type GcpGkeAuditData struct { type GcpGkeAuditCredentials struct { ClientId string `json:"clientId"` ClientEmail string `json:"clientEmail"` - PrivateKeyId string `json:"PrivateKeyID"` - PrivateKey string `json:"PrivateKey"` + PrivateKeyId string `json:"privateKeyId"` + PrivateKey string `json:"privateKey"` } diff --git a/vendor/github.com/lacework/go-sdk/api/policy.go b/vendor/github.com/lacework/go-sdk/api/policy.go index ace5ea977..13b0b3e68 100644 --- a/vendor/github.com/lacework/go-sdk/api/policy.go +++ b/vendor/github.com/lacework/go-sdk/api/policy.go @@ -32,7 +32,14 @@ import ( // PolicyService is a service that interacts with the Custom Policies // endpoints from the Lacework Server type PolicyService struct { - client *Client + client *Client + Exceptions *policyExceptionsService +} + +func NewV2PolicyService(c *Client) *PolicyService { + return &PolicyService{c, + &policyExceptionsService{c}, + } } // ValidPolicySeverities is a list of all valid policy severities diff --git a/vendor/github.com/lacework/go-sdk/api/policy_exceptions.go b/vendor/github.com/lacework/go-sdk/api/policy_exceptions.go new file mode 100644 index 000000000..23b1228c0 --- /dev/null +++ b/vendor/github.com/lacework/go-sdk/api/policy_exceptions.go @@ -0,0 +1,109 @@ +// +// Author:: Darren Murray () +// Copyright:: Copyright 2022, Lacework Inc. +// License:: Apache License, Version 2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package api + +import ( + "errors" + "fmt" +) + +// policyExceptionsService is the service that interacts with +// the Exceptions schema from the Lacework APIv2 Server +type policyExceptionsService struct { + client *Client +} + +// List returns a list of the Policy Exceptions for a policy ID. +func (svc policyExceptionsService) List(policyID string) (response PolicyExceptionsResponse, err error) { + if policyID == "" { + return response, errors.New("specify a policy ID") + } + err = svc.client.RequestDecoder("GET", fmt.Sprintf(apiV2PolicyExceptions, policyID), nil, &response) + return +} + +// Get returns a raw response of the Policy Exception with the matching policy ID and exception ID. +func (svc policyExceptionsService) Get(policyID string, exceptionID string, response interface{}) error { + if exceptionID == "" || policyID == "" { + return errors.New("specify exception and policy IDs") + } + apiPath := fmt.Sprintf(apiV2PolicyExceptionsFromExceptionID, exceptionID, policyID) + return svc.client.RequestDecoder("GET", apiPath, nil, &response) +} + +func (svc policyExceptionsService) Delete(policyID string, exceptionID string) error { + if exceptionID == "" || policyID == "" { + return errors.New("specify exception and policy IDs") + } + + return svc.client.RequestDecoder( + "DELETE", + fmt.Sprintf(apiV2PolicyExceptionsFromExceptionID, exceptionID, policyID), + nil, + nil, + ) +} + +// Create creates a single Policy Exception +func (svc *policyExceptionsService) Create(policyID string, policy PolicyException) ( + response PolicyExceptionResponse, + err error, +) { + if policyID == "" { + return response, errors.New("specify a policy ID") + } + err = svc.client.RequestEncoderDecoder("POST", fmt.Sprintf(apiV2PolicyExceptions, policyID), + policy, &response) + return +} + +// Update updates a single Policy Exception +func (svc policyExceptionsService) Update(policyID string, exception PolicyException) (response PolicyExceptionResponse, err error) { + if exception.ExceptionID == "" || policyID == "" { + return response, errors.New("specify exception and policy IDs") + } + apiPath := fmt.Sprintf(apiV2PolicyExceptionsFromExceptionID, exception.ExceptionID, policyID) + // Request is invalid if it contains the ExceptionID, LastUpdatedTime or LastUpdatedUser fields. + exception.ExceptionID = "" + exception.LastUpdateUser = "" + exception.LastUpdateTime = "" + + err = svc.client.RequestEncoderDecoder("PATCH", apiPath, exception, &response) + return +} + +type PolicyExceptionResponse struct { + Data PolicyException `json:"data"` +} + +type PolicyExceptionsResponse struct { + Data []PolicyException `json:"data"` +} +type PolicyException struct { + ExceptionID string `json:"exceptionId,omitempty"` + Description string `json:"description"` + Constraints []PolicyExceptionConstraint `json:"constraints"` + LastUpdateTime string `json:"lastUpdateTime,omitempty"` + LastUpdateUser string `json:"lastUpdateUser,omitempty"` +} + +type PolicyExceptionConstraint struct { + FieldKey string `json:"fieldKey"` + FieldValues []string `json:"fieldValues"` +} diff --git a/vendor/github.com/lacework/go-sdk/api/v2.go b/vendor/github.com/lacework/go-sdk/api/v2.go index 0e9c73842..63c4ffa4f 100644 --- a/vendor/github.com/lacework/go-sdk/api/v2.go +++ b/vendor/github.com/lacework/go-sdk/api/v2.go @@ -62,7 +62,7 @@ func NewV2Endpoints(c *Client) *V2Endpoints { &ResourceGroupsService{c}, &AgentAccessTokensService{c}, &QueryService{c}, - &PolicyService{c}, + NewV2PolicyService(c), &EntitiesService{c}, &SchemasService{c, map[integrationSchema]V2Service{}}, &DatasourcesService{c}, diff --git a/vendor/github.com/lacework/go-sdk/api/version.go b/vendor/github.com/lacework/go-sdk/api/version.go index b114a9a0c..e6592012b 100644 --- a/vendor/github.com/lacework/go-sdk/api/version.go +++ b/vendor/github.com/lacework/go-sdk/api/version.go @@ -1,5 +1,5 @@ // Code generated by: scripts/version_updater.sh -// File generated at: 20220620101205 +// File generated at: 20220627163708 // // <<< DO NOT EDIT >>> // @@ -7,4 +7,4 @@ package api // Version is the semver coming from the VERSION file -const Version = "0.36.1-dev" +const Version = "0.37.0" diff --git a/vendor/github.com/lacework/go-sdk/api/vulnerabilities_container.go b/vendor/github.com/lacework/go-sdk/api/vulnerabilities_container.go index 28bba1bff..51bcdd7e2 100644 --- a/vendor/github.com/lacework/go-sdk/api/vulnerabilities_container.go +++ b/vendor/github.com/lacework/go-sdk/api/vulnerabilities_container.go @@ -292,7 +292,7 @@ type VulnContainerImageLayer struct { type VulnContainerPackage struct { Name string `json:"name"` - Namespace string `json:"namescape"` + Namespace string `json:"namespace"` Version string `json:"version"` Vulnerabilities []ContainerVulnerability `json:"vulnerabilities"` diff --git a/vendor/modules.txt b/vendor/modules.txt index d0914fc2c..3e008cd76 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -187,7 +187,7 @@ github.com/hashicorp/logutils ## explicit; go 1.17 github.com/hashicorp/terraform-exec/internal/version github.com/hashicorp/terraform-exec/tfexec -# github.com/hashicorp/terraform-json v0.13.0 +# github.com/hashicorp/terraform-json v0.14.0 ## explicit; go 1.13 github.com/hashicorp/terraform-json # github.com/hashicorp/terraform-plugin-go v0.8.0 @@ -258,7 +258,7 @@ github.com/klauspost/compress/huff0 github.com/klauspost/compress/internal/snapref github.com/klauspost/compress/zstd github.com/klauspost/compress/zstd/internal/xxhash -# github.com/lacework/go-sdk v0.36.1-0.20220621101646-85d5214a6d09 +# github.com/lacework/go-sdk v0.37.0 ## explicit; go 1.18 github.com/lacework/go-sdk/api github.com/lacework/go-sdk/internal/array diff --git a/website/docs/r/integration_gcp_gke_audit_log.html.markdown b/website/docs/r/integration_gcp_gke_audit_log.html.markdown new file mode 100644 index 000000000..08a4274a3 --- /dev/null +++ b/website/docs/r/integration_gcp_gke_audit_log.html.markdown @@ -0,0 +1,61 @@ +--- +subcategory: "Cloud Account Integrations" +layout: "lacework" +page_title: "Lacework: lacework_integration_gcp_gke_audit_log" +description: |- + Create and manage GCP GKE Audit Log integrations +--- + +# lacework\_integration\_gcp\_gke\_audit\_log + +Use this resource to configure an [GCP GKE Audit Log integration](https://docs.lacework.com/category/gke-audit-log-integrations) to analyze GKE audit logs. + +## Example Usage + +```hcl +resource "lacework_integration_gcp_gke_audit_log" "account_abc" { + name = "account ABC" + project_id = "ABC-project-id" + subscription = "projects/ABC-project-id/subscriptions/example-subscription" + integration_type = "PROJECT" + credentials { + client_id = "123456789012345678900" + client_email = "email@abc-project-name.iam.gserviceaccount.com" + private_key_id = "1234abcd1234abcd1234abcd1234abcd1234abcd" + private_key = "-----BEGIN PRIVATE KEY-----\n ... -----END PRIVATE KEY-----\n" + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The GCP Audit Trail integration name. +* `organization_id` - (Optional) The organization ID. Required if `integration_type` is set to `ORGANIZATION`. +* `project_id` - (Required) The project ID. +* `subscription` - (Required) The PubSub Subscription. +* `credentials` - (Required) The credentials needed by the integration. See [Credentials](#credentials) below for details. +* `integration_type` - (Optional) The integration type. Must be one of `PROJECT` or `ORGANIZATION`. +* `enabled` - (Optional) The state of the external integration. Defaults to `true`. +* `retries` - (Optional) The number of attempts to create the external integration. Defaults to `5`. + +### Credentials + +`credentials` supports the following arguments: + +* `client_id` - (Required) The service account client ID. +* `client_email` - (Required) The service account client email. +* `private_key_id` - (Required) The service account private key ID. +* `private_key` - (Required) The service account private key. + +## Import + +A Lacework GCP GKE Audit Log integration can be imported using a `INT_GUID`, e.g. + +``` +$ terraform import lacework_integration_gcp_gke_audit_log.account_abc EXAMPLE_1234BAE1E42182964D23973F44CFEA3C4AB63B99E9A1EC5 +``` +-> **Note:** To retrieve the `INT_GUID` from existing integrations in your account, use the + Lacework CLI command `lacework integration list`. To install this tool follow + [this documentation](https://docs.lacework.com/cli/). diff --git a/website/lacework.erb b/website/lacework.erb index 322ef7ec0..55d62aa60 100644 --- a/website/lacework.erb +++ b/website/lacework.erb @@ -131,6 +131,9 @@
  • lacework_integration_gcp_at
  • +
  • + lacework_integration_gcp_gke_audit_log +