diff --git a/.gitignore b/.gitignore index 16c68e1..f9f6f8d 100644 --- a/.gitignore +++ b/.gitignore @@ -28,4 +28,11 @@ override.tf.json # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan # example: *tfplan* -.idea +# Credentials Files +**/credentials.json + +# Local testing variables +*.tfvars + +/.idea/ +.DS_Store \ No newline at end of file diff --git a/gcp/main.tf b/gcp/main.tf new file mode 100644 index 0000000..1d8af31 --- /dev/null +++ b/gcp/main.tf @@ -0,0 +1,164 @@ +provider "google" { + credentials = file(var.credentials_file) + + project = var.project_id + region = var.region + zone = var.zone +} + +data "google_project" "project" { +} + +resource "google_service_account" "service_account" { + account_id = "${var.prefix}-lacework-cfg-sa" + display_name = "${var.prefix}-lacework-cfg-sa" +} + +resource "google_project_iam_member" "project_viewer_binding" { + count = var.org_integration ? 0 : 1 + + member = "serviceAccount:${google_service_account.service_account.email}" + role = "roles/viewer" + project = var.project_id +} + +resource "google_project_iam_member" "project_security_reviewer_binding" { + count = var.org_integration ? 0 : 1 + + member = "serviceAccount:${google_service_account.service_account.email}" + role = "roles/iam.securityReviewer" + project = var.project_id +} + +resource "google_organization_iam_member" "organization_viewer_binding" { + count = var.org_integration ? 1 : 0 + + member = "serviceAccount:${google_service_account.service_account.email}" + role = "roles/viewer" + org_id = var.organization_id +} + +resource "google_organization_iam_member" "organization_security_reviewer_binding" { + count = var.org_integration ? 1 : 0 + + member = "serviceAccount:${google_service_account.service_account.email}" + role = "roles/iam.securityReviewer" + org_id = var.organization_id +} + +resource "google_organization_iam_member" "organization_resource_viewer_binding" { + count = var.org_integration ? 1 : 0 + + member = "serviceAccount:${google_service_account.service_account.email}" + role = "roles/resourcemanager.organizationViewer" + org_id = var.organization_id +} + +resource "google_service_account_key" "service-account-key-lacework" { + service_account_id = google_service_account.service_account.name +} + +resource "google_storage_bucket" "lacework_bucket" { + count = var.existing_bucket_name != "" && var.audit_log ? 0 : 1 + + name = "${var.prefix}-${var.project_id}-lacework-bucket" +} + +resource "google_storage_bucket_iam_member" "bucket_object_viewer" { + bucket = var.existing_bucket_name != "" && var.audit_log ? var.existing_bucket_name : google_storage_bucket.lacework_bucket[0].name + member = "serviceAccount:${google_service_account.service_account.email}" + role = "roles/storage.objectViewer" +} + +resource "google_storage_bucket_iam_binding" "legacy_bucket_owner" { + count = var.existing_bucket_name != "" && var.audit_log ? 0 : 1 + + bucket = google_storage_bucket.lacework_bucket[count.index].name + role = "roles/storage.legacyBucketOwner" + members = ["projectEditor:${var.project_id}", "projectOwner:${var.project_id}"] +} + +resource "google_storage_bucket_iam_binding" "legacy_bucket_reader" { + count = var.existing_bucket_name != "" && var.audit_log ? 0 : 1 + + bucket = google_storage_bucket.lacework_bucket[count.index].name + role = "roles/storage.legacyBucketReader" + members = ["projectViewer:${var.project_id}"] +} + +resource "google_pubsub_topic" "lacework_topic" { + count = var.existing_bucket_name != "" && var.audit_log ? 0 : 1 + + name = "${var.prefix}-${var.project_id}-lacework-topic" +} + +resource "google_pubsub_topic_iam_member" "topic_publisher" { + count = var.existing_bucket_name != "" && var.audit_log ? 0 : 1 + + member = "serviceAccount:service-${data.google_project.project.number}@gs-project-accounts.iam.gserviceaccount.com" + role = "roles/pubsub.publisher" + topic = google_pubsub_topic.lacework_topic[count.index].name +} + +resource "google_pubsub_subscription" "lacework_subscription" { + count = var.existing_bucket_name != "" && var.audit_log ? 0 : 1 + + name = "${var.prefix}-${var.project_id}-lacework-subscription" + topic = google_pubsub_topic.lacework_topic[count.index].name + ack_deadline_seconds = 300 + message_retention_duration = "432000s" +} + +resource "google_pubsub_subscription_iam_member" "pubsub_subscriber" { + count = var.existing_bucket_name != "" && var.audit_log ? 0 : 1 + + member = "serviceAccount:${google_service_account.service_account.email}" + role = "roles/pubsub.subscriber" + subscription = google_pubsub_subscription.lacework_subscription[count.index].name +} + +resource "google_storage_notification" "lacework_notification" { + count = var.existing_bucket_name != "" && var.audit_log ? 0 : 1 + + bucket = google_storage_bucket.lacework_bucket[count.index].name + payload_format = "JSON_API_V1" + topic = google_pubsub_topic.lacework_topic[count.index].name + event_types = ["OBJECT_FINALIZE"] + + depends_on = [google_pubsub_topic_iam_member.topic_publisher] +} + +resource "google_logging_project_sink" "lacework_project_sink" { + count = var.org_integration && var.audit_log ? 0 : 1 + + destination = "storage.googleapis.com/${var.existing_bucket_name != "" ? var.existing_bucket_name : google_storage_bucket.lacework_bucket[0].name}" + name = "${var.prefix}-${var.project_id}-lacework-sink" + unique_writer_identity = true + filter = "protoPayload.@type=type.googleapis.com/google.cloud.audit.AuditLog AND NOT protoPayload.methodName:'storage.objects'" +} + +resource "google_storage_bucket_iam_member" "project_sink_writer" { + count = var.org_integration && var.audit_log ? 0 : 1 + + bucket = var.existing_bucket_name != "" ? var.existing_bucket_name : google_storage_bucket.lacework_bucket[0].name + role = "roles/storage.objectCreator" + member = google_logging_project_sink.lacework_project_sink[count.index].writer_identity +} + +resource "google_logging_organization_sink" "lacework_organization_sink" { + count = var.org_integration && var.audit_log ? 1 : 0 + + destination = "storage.googleapis.com/${var.existing_bucket_name != "" ? var.existing_bucket_name : google_storage_bucket.lacework_bucket[0].name}" + name = "${var.prefix}-${var.organization_id}-lacework-sink" + org_id = var.organization_id + include_children = true + filter = "protoPayload.@type=type.googleapis.com/google.cloud.audit.AuditLog AND NOT protoPayload.methodName:'storage.objects'" +} + +resource "google_storage_bucket_iam_member" "organization_sink_writer" { + count = var.org_integration && var.audit_log ? 1 : 0 + + bucket = var.existing_bucket_name != "" ? var.existing_bucket_name : google_storage_bucket.lacework_bucket[0].name + role = "roles/storage.objectCreator" + member = google_logging_organization_sink.lacework_organization_sink[count.index].writer_identity +} diff --git a/gcp/output.tf b/gcp/output.tf new file mode 100644 index 0000000..41b46c6 --- /dev/null +++ b/gcp/output.tf @@ -0,0 +1,12 @@ +output "privateKey" { + value = base64decode(google_service_account_key.service-account-key-lacework.private_key) +} + +output "subscription" { + value = "projects/test-project-mobeen/subscriptions/${google_pubsub_subscription.lacework_subscription[0].name}" + depends_on = [google_pubsub_subscription.lacework_subscription] +} + +output "existing_subscription" { + value = var.existing_bucket_name != "" ? "Use existing subscription associated with the existing bucket" : "Use subscription printed with output" +} diff --git a/gcp/variables.tf b/gcp/variables.tf new file mode 100644 index 0000000..6e4f34d --- /dev/null +++ b/gcp/variables.tf @@ -0,0 +1,48 @@ +variable "prefix" { + type = string + description = "The Prefix used for all resources in this example" +} + +variable "credentials_file" { + type = string + description = "Location of the credentials file for gcp" +} + +variable "org_integration" { + type = bool + description = "If set to true, configure an organization level integration" + default = false +} + +variable "project_id" { + type = string + description = "Id of the project" +} + +variable "organization_id" { + type = string + description = "Id of the organization" +} + +variable "region" { + type = string + description = "Region you want to create resources in" + default = "us-central1" +} + +variable "zone" { + type = string + description = "Zone you want to create resources in" + default = "us-central1-c" +} + +variable "audit_log" { + type = bool + description = "If set to true, create resources for both Config and Audit Logs" +} + +variable "existing_bucket_name" { + type = string + description = "Name of an existing bucket you want to send the logs to" + default = "" +}