Skip to content

Commit 4ea84ca

Browse files
authored
feat Adding custom audit log config for each GCP service (#31)
* feat Adding parameter to be able to select a custom audit log config for each service to be ingested * feat Adding audit log config at the organization level * feat Adding ingestion synk dynamic exclusions * feat Updating the documentation for the new inputs
1 parent c5926a7 commit 4ea84ca

File tree

6 files changed

+154
-30
lines changed

6 files changed

+154
-30
lines changed

modules/services/webhook-datasource/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ No modules.
7272
| <a name="input_role_name"></a> [role\_name](#input\_role\_name) | (Optional) Role name for custom role binding to the service account, with read permissions for data ingestion resources | `string` | `"SysdigIngestionAuthRole"` | no |
7373
| <a name="input_external_id"></a> [external\_id](#input\_external\_id) | (Required) Random string generated unique to a customer | `string` | n/a | yes |
7474
| <a name="input_suffix"></a> [suffix](#input\_suffix) | (Optional) Suffix to uniquely identify resources during multiple installs. If not provided, random value is autogenerated | `string` | `null` | no |
75+
| <a name="input_audit_log_config"></a> [audit\_log\_config](#input\_audit\_log\_config) | List of services and their audit log configurations to be ingested. Default is to ingest all logs. | <pre>list(object({<br> service = string,<br> log_config = list(object({<br> log_type = string,<br> exempted_members = optional(list(string))<br> }))<br> }))</pre> | <pre>[<br> {<br> "log_config": [<br> {<br> "log_type": "ADMIN_READ"<br> },<br> {<br> "log_type": "DATA_READ"<br> },<br> {<br> "log_type": "DATA_WRITE"<br> }<br> ],<br> "service": "allServices"<br> }<br>]</pre> | no |
76+
| <a name="input_exclude_logs_filter"></a> [exclude\_logs\_filter](#input\_exclude\_logs\_filter) | Filter to exclude logs from ingestion. Default is to ingest all google.cloud.audit.AuditLog logs. with no exclusions. | <pre>list(object({<br> name = string,<br> description = optional(string),<br> filter = string,<br> disabled = optional(bool)<br> }))</pre> | `[]` | no |
7577

7678
## Outputs
7779

modules/services/webhook-datasource/main.tf

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,28 @@
2727
# Audit Logs #
2828
#------------#
2929

30-
resource "google_project_iam_audit_config" "audit_config" {
31-
count = var.is_organizational ? 0 : 1
32-
33-
project = var.project_id
34-
service = "allServices"
35-
36-
audit_log_config {
37-
log_type = "ADMIN_READ"
30+
locals {
31+
# Data structure will be a map for each service, that can have multiple audit_log_config
32+
audit_log_config = { for audit in var.audit_log_config :
33+
audit["service"] => {
34+
log_config = audit["log_config"]
35+
}
3836
}
37+
}
3938

40-
audit_log_config {
41-
log_type = "DATA_READ"
42-
}
39+
resource "google_project_iam_audit_config" "audit_config" {
40+
for_each = var.is_organizational ? {} : local.audit_log_config
4341

44-
audit_log_config {
45-
log_type = "DATA_WRITE"
42+
project = var.project_id
43+
service = each.key
44+
45+
dynamic "audit_log_config" {
46+
for_each = each.value.log_config
47+
iterator = log_config
48+
content {
49+
log_type = log_config.value.log_type
50+
exempted_members = log_config.value.exempted_members
51+
}
4652
}
4753
}
4854

@@ -79,6 +85,17 @@ resource "google_logging_project_sink" "ingestion_sink" {
7985

8086
filter = "protoPayload.@type = \"type.googleapis.com/google.cloud.audit.AuditLog\""
8187

88+
# Dynamic block to exclude logs from ingestion
89+
dynamic "exclusions" {
90+
for_each = var.exclude_logs_filter
91+
content {
92+
name = exclusions.value.name
93+
description = exclusions.value.description
94+
filter = exclusions.value.filter
95+
disabled = exclusions.value.disabled
96+
}
97+
}
98+
8299
# NOTE: Used to create a dedicated writer identity and not using the default one
83100
unique_writer_identity = true
84101
}

modules/services/webhook-datasource/organizational.tf

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,18 @@ data "google_organization" "org" {
1111
# Audit Logs #
1212
#------------#
1313
resource "google_organization_iam_audit_config" "audit_config" {
14-
count = var.is_organizational ? 1 : 0
14+
for_each = var.is_organizational ? local.audit_log_config : {}
1515

1616
org_id = data.google_organization.org[0].org_id
17-
service = "allServices"
18-
19-
audit_log_config {
20-
log_type = "ADMIN_READ"
21-
}
17+
service = each.key
2218

23-
audit_log_config {
24-
log_type = "DATA_READ"
25-
}
26-
27-
audit_log_config {
28-
log_type = "DATA_WRITE"
19+
dynamic "audit_log_config" {
20+
for_each = each.value.log_config
21+
iterator = log_config
22+
content {
23+
log_type = log_config.value.log_type
24+
exempted_members = log_config.value.exempted_members
25+
}
2926
}
3027
}
3128

@@ -44,6 +41,17 @@ resource "google_logging_organization_sink" "ingestion_sink" {
4441
destination = "pubsub.googleapis.com/projects/${var.project_id}/topics/${google_pubsub_topic.ingestion_topic.name}"
4542
filter = "protoPayload.@type = \"type.googleapis.com/google.cloud.audit.AuditLog\""
4643

44+
# Dynamic block to exclude logs from ingestion
45+
dynamic "exclusions" {
46+
for_each = var.exclude_logs_filter
47+
content {
48+
name = exclusions.value.name
49+
description = exclusions.value.description
50+
filter = exclusions.value.filter
51+
disabled = exclusions.value.disabled
52+
}
53+
}
54+
4755
# NOTE: The include_children attribute is set to true in order to ingest data
4856
# even from potential sub-organizations
4957
include_children = true

modules/services/webhook-datasource/variables.tf

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,35 @@ variable "suffix" {
7474
description = "Suffix to uniquely identify resources during multiple installs. If not provided, random value is autogenerated"
7575
default = null
7676
}
77+
78+
variable "audit_log_config" {
79+
description = "List of services and their audit log configurations to be ingested. Default is to ingest all logs."
80+
type = list(object({
81+
service = string,
82+
log_config = list(object({
83+
log_type = string,
84+
exempted_members = optional(list(string))
85+
}))
86+
}))
87+
default = [
88+
{
89+
service = "allServices"
90+
log_config = [
91+
{ log_type = "ADMIN_READ" },
92+
{ log_type = "DATA_READ" },
93+
{ log_type = "DATA_WRITE" }
94+
]
95+
}
96+
]
97+
}
98+
99+
variable "exclude_logs_filter" {
100+
description = "Filter to exclude logs from ingestion. Default is to ingest all google.cloud.audit.AuditLog logs. with no exclusions."
101+
type = list(object({
102+
name = string,
103+
description = optional(string),
104+
filter = string,
105+
disabled = optional(bool)
106+
}))
107+
default = []
108+
}

test/examples/secure_threat_detection/organization/main.tf

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,45 @@ provider "google" {
44
}
55

66
module "organization-threat-detection" {
7-
source = "../../../..//modules/services/webhook-datasource"
8-
project_id = "mytestproject"
9-
push_endpoint = "test_sysdig_secure_cloudingestion_endpoint"
10-
is_organizational = true
7+
source = "../../../..//modules/services/webhook-datasource"
8+
project_id = "mytestproject"
9+
push_endpoint = "test_sysdig_secure_cloudingestion_endpoint"
10+
is_organizational = true
1111
organization_domain = "mytestorg.com"
1212
external_id = "external_id"
13+
audit_log_config = [
14+
{
15+
service = "cloudsql.googleapis.com"
16+
log_config = [{ log_type = "DATA_READ",
17+
exempted_members = [
18+
"serviceAccount:[email protected]",
19+
]
20+
},
21+
{ log_type = "DATA_WRITE" }
22+
]
23+
},
24+
{
25+
service = "storage.googleapis.com"
26+
log_config = [{ log_type = "DATA_WRITE"
27+
}]
28+
},
29+
{
30+
service = "container.googleapis.com"
31+
log_config = [{ log_type = "DATA_READ" }]
32+
}
33+
]
34+
exclude_logs_filter = [
35+
{
36+
name = "nsexcllusion2"
37+
description = "Exclude logs from namespace-2 in k8s"
38+
filter = "resource.type = k8s_container resource.labels.namespace_name=\"namespace-2\" "
39+
},
40+
{
41+
name = "nsexcllusion1"
42+
description = "Exclude logs from namespace-1 in k8s"
43+
filter = "resource.type = k8s_container resource.labels.namespace_name=\"namespace-1\" "
44+
}
45+
]
1346
}
1447

1548
module "organization-posture" {

test/examples/secure_threat_detection/single/main.tf

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,39 @@ module "single-project-threat-detection" {
88
project_id = "mytestproject"
99
push_endpoint = "test_sysdig_secure_cloudingestion_endpoint"
1010
external_id = "external_id"
11+
audit_log_config = [
12+
{
13+
service = "cloudsql.googleapis.com"
14+
log_config = [{ log_type = "DATA_READ",
15+
exempted_members = [
16+
"serviceAccount:[email protected]",
17+
]
18+
},
19+
{ log_type = "DATA_WRITE" }
20+
]
21+
},
22+
{
23+
service = "storage.googleapis.com"
24+
log_config = [{ log_type = "DATA_WRITE"
25+
}]
26+
},
27+
{
28+
service = "container.googleapis.com"
29+
log_config = [{ log_type = "DATA_READ" }]
30+
}
31+
]
32+
exclude_logs_filter = [
33+
{
34+
name = "nsexcllusion2"
35+
description = "Exclude logs from namespace-2 in k8s"
36+
filter = "resource.type = k8s_container resource.labels.namespace_name=\"namespace-2\" "
37+
},
38+
{
39+
name = "nsexcllusion1"
40+
description = "Exclude logs from namespace-1 in k8s"
41+
filter = "resource.type = k8s_container resource.labels.namespace_name=\"namespace-1\" "
42+
}
43+
]
1144
}
1245

1346
terraform {
@@ -66,4 +99,3 @@ resource "sysdig_secure_cloud_auth_account" "gcp_project_mytestproject" {
6699
})
67100
}
68101
}
69-

0 commit comments

Comments
 (0)