Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat sink billing account #129

Open
wants to merge 35 commits into
base: test-pr-sink
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
6d26c13
add suport to billing account logs
renato-rudnicki Feb 14, 2024
690f6e7
small improvements
renato-rudnicki Feb 15, 2024
57ec9f6
create custom log bucket and sink for project destination
renato-rudnicki Feb 15, 2024
85d6844
fix lint
renato-rudnicki Feb 15, 2024
bebcbb2
Fix duplicated sink name
renato-rudnicki Feb 16, 2024
f4f2eb8
fix integration tests
renato-rudnicki Feb 16, 2024
14a3a99
adds unique_writer_identity in internal_project_log_export module
renato-rudnicki Feb 19, 2024
ee3554c
update code
renato-rudnicki Feb 22, 2024
5530ed9
Revert "update code"
renato-rudnicki Feb 22, 2024
4775ef3
Revert "adds unique_writer_identity in internal_project_log_export mo…
renato-rudnicki Feb 22, 2024
df8dc0c
Revert "fix integration tests"
renato-rudnicki Feb 22, 2024
47418a3
Revert "Fix duplicated sink name"
renato-rudnicki Feb 22, 2024
06ec1c1
Revert "fix lint"
renato-rudnicki Feb 22, 2024
5c34cd5
Revert "create custom log bucket and sink for project destination"
renato-rudnicki Feb 22, 2024
fa23017
add randon for billing sink
renato-rudnicki Feb 22, 2024
46e44cb
fix for billing account sink
renato-rudnicki Feb 28, 2024
648ed1a
update README
renato-rudnicki Feb 28, 2024
f3c7fbc
fix lint
renato-rudnicki Feb 28, 2024
db9f4e1
fixes for module log_export_billing
renato-rudnicki Feb 29, 2024
ea4e2c0
add PR suggestions
renato-rudnicki Mar 4, 2024
b6bf537
update
renato-rudnicki Mar 5, 2024
07df788
fixes for log_export_billing
renato-rudnicki Mar 6, 2024
e759cf9
add integration tests for sink under billing account level
renato-rudnicki Mar 12, 2024
b41b322
code review improvements
renato-rudnicki Mar 12, 2024
459fc90
fix lint
renato-rudnicki Mar 12, 2024
32fb194
chore(deps): bump google.golang.org/protobuf from 1.31.0 to 1.33.0 in…
dependabot[bot] Mar 14, 2024
8b17343
Merge branch 'master' into feat_sink_billing_account
renato-rudnicki Mar 14, 2024
1fe50db
removing comments
renato-rudnicki Mar 14, 2024
a8b11b8
change default value for enable_billing_account_sink variable
renato-rudnicki Mar 14, 2024
bc5c46d
adds get sink permission on CICD SA
renato-rudnicki Mar 15, 2024
e1274a6
update resource name for billign account sink
renato-rudnicki Mar 15, 2024
f57a47c
fix!: Groups creation and permissions (#1110)
Samir-Cit Mar 18, 2024
27807fd
Merge branch 'master' into feat_sink_billing_account
apeabody Mar 21, 2024
be6b808
chore: update CODEOWNERS
cloud-foundation-bot Mar 22, 2024
a950798
Merge branch 'master' into feat_sink_billing_account
daniel-cit Mar 25, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions 0-bootstrap/sa.tf
Original file line number Diff line number Diff line change
Expand Up @@ -227,3 +227,10 @@ resource "google_billing_account_iam_member" "billing_admin_user" {
google_billing_account_iam_member.tf_billing_user
]
}

resource "google_billing_account_iam_member" "billing_account_sink" {
billing_account_id = var.billing_account
role = "roles/logging.configWriter"
member = "serviceAccount:${google_service_account.terraform-env-sa["org"].email}"
}

1 change: 1 addition & 0 deletions 1-org/envs/shared/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
| Name | Description |
|------|-------------|
| base\_net\_hub\_project\_id | The Base Network hub project ID |
| billing\_sink\_names | The name of the sinks under billing account level. |
| cai\_monitoring\_artifact\_registry | CAI Monitoring Cloud Function Artifact Registry name. |
| cai\_monitoring\_asset\_feed | CAI Monitoring Cloud Function Organization Asset Feed name. |
| cai\_monitoring\_bucket | CAI Monitoring Cloud Function Source Bucket name. |
Expand Down
2 changes: 2 additions & 0 deletions 1-org/envs/shared/log_sinks.tf
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ module "logs_export" {
resources = local.parent_resources
resource_type = local.parent_resource_type
logging_destination_project_id = module.org_audit_logs.project_id
billing_account = local.billing_account


/******************************************
Send logs to Storage
Expand Down
11 changes: 11 additions & 0 deletions 1-org/envs/shared/org_policy.tf
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,13 @@ module "restrict_protocol_fowarding" {
IAM
*******************************************/

resource "time_sleep" "wait_logs_export" {
create_duration = "30s"
depends_on = [
module.logs_export
]
}

module "org_domain_restricted_sharing" {
source = "terraform-google-modules/org-policy/google//modules/domain_restricted_sharing"
version = "~> 5.1"
Expand All @@ -98,6 +105,10 @@ module "org_domain_restricted_sharing" {
folder_id = local.folder_id
policy_for = local.policy_for
domains_to_allow = var.domains_to_allow

depends_on = [
time_sleep.wait_logs_export
]
}

/******************************************
Expand Down
5 changes: 5 additions & 0 deletions 1-org/envs/shared/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ output "logs_export_logbucket_name" {
description = "The log bucket for destination of log exports. See https://cloud.google.com/logging/docs/routing/overview#buckets ."
}

output "billing_sink_names" {
value = module.logs_export.billing_sink_names
description = "The name of the sinks under billing account level."
}

output "logs_export_logbucket_linked_dataset_name" {
value = module.logs_export.logbucket_linked_dataset_name
description = "The resource name of the Log Bucket linked BigQuery dataset created for Log Analytics. See https://cloud.google.com/logging/docs/log-analytics ."
Expand Down
3 changes: 3 additions & 0 deletions 1-org/modules/centralized-logging/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ module "logging_logbucket" {

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| billing\_account | Billing Account ID used in case sinks are under billing account level. Format 000000-000000-000000. | `string` | `null` | no |
| enable\_billing\_account\_sink | If true, a log router sink will be created for the billing account. The billing\_account variable cannot be null. | `bool` | `true` | no |
| logbucket\_options | Destination LogBucket options:<br>- name: The name of the log bucket to be created and used for log entries matching the filter.<br>- logging\_sink\_name: The name of the log sink to be created.<br>- logging\_sink\_filter: The filter to apply when exporting logs. Only log entries that match the filter are exported. Default is "" which exports all logs.<br>- location: The location of the log bucket. Default: global.<br>- enable\_analytics: Whether or not Log Analytics is enabled. A Log bucket with Log Analytics enabled can be queried in the Log Analytics page using SQL queries. Cannot be disabled once enabled.<br>- linked\_dataset\_id: The ID of the linked BigQuery dataset. A valid link dataset ID must only have alphanumeric characters and underscores within it and have up to 100 characters.<br>- linked\_dataset\_description: A use-friendly description of the linked BigQuery dataset. The maximum length of the description is 8000 characters.<br>- retention\_days: The number of days data should be retained for the log bucket. Default 30. | <pre>object({<br> name = optional(string, null)<br> logging_sink_name = optional(string, null)<br> logging_sink_filter = optional(string, "")<br> location = optional(string, "global")<br> enable_analytics = optional(bool, true)<br> linked_dataset_id = optional(string, null)<br> linked_dataset_description = optional(string, null)<br> retention_days = optional(number, 30)<br> })</pre> | `null` | no |
| logging\_destination\_project\_id | The ID of the project that will have the resources where the logs will be created. | `string` | n/a | yes |
| logging\_project\_key | (Optional) The key of logging destination project if it is inside resources map. It is mandatory when resource\_type = project and logging\_target\_type = logbucket. | `string` | `""` | no |
Expand All @@ -71,6 +73,7 @@ module "logging_logbucket" {

| Name | Description |
|------|-------------|
| billing\_sink\_names | Map of log sink names with billing suffix |
| logbucket\_destination\_name | The resource name for the destination Log Bucket. |
| logbucket\_linked\_dataset\_name | The resource name of the Log Bucket linked BigQuery dataset. |
| pubsub\_destination\_name | The resource name for the destination Pub/Sub. |
Expand Down
80 changes: 80 additions & 0 deletions 1-org/modules/centralized-logging/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ locals {
lbk = try(module.destination_logbucket[0].destination_uri, "")
}

destination_resource_name = merge(
var.pubsub_options != null ? { pub = module.destination_pubsub[0].resource_name } : {},
var.storage_options != null ? { sto = module.destination_storage[0].resource_name } : {},
var.logbucket_options != null ? { lbk = module.destination_logbucket[0].resource_name } : {}
)

logging_tgt_prefix = {
pub = "tp-logs-"
sto = try("bkt-logs-${var.logging_destination_project_id}-", "bkt-logs-")
Expand Down Expand Up @@ -90,6 +96,28 @@ module "log_export" {
include_children = local.include_children
}


module "log_export_billing" {
source = "terraform-google-modules/log-export/google"
version = "~> 7.4"

for_each = var.enable_billing_account_sink ? local.destination_resource_name : {}

destination_uri = local.destination_uri_map[each.key]
filter = ""
log_sink_name = "${coalesce(local.destinations_options[each.key].logging_sink_name, local.logging_sink_name_map[each.key])}-billing-${random_string.suffix.result}"
parent_resource_id = var.billing_account
parent_resource_type = "billing_account"
unique_writer_identity = true
}

resource "time_sleep" "wait_sa_iam_membership" {
create_duration = "30s"
depends_on = [
module.log_export_billing
]
}

#-------------------------#
# Send logs to Log Bucket #
#-------------------------#
Expand Down Expand Up @@ -124,6 +152,25 @@ resource "google_project_iam_member" "logbucket_sink_member" {
member = module.log_export["${each.value}_lbk"].writer_identity
}

#------------------------------------------------------------------#
# Log Bucket Service account IAM membership for log_export_billing #
#------------------------------------------------------------------#
resource "google_project_iam_member" "logbucket_sink_member_billing" {
count = var.enable_billing_account_sink == true && var.logbucket_options != null ? 1 : 0

project = var.logging_destination_project_id
role = "roles/logging.bucketWriter"

# Set permission only on sinks for this destination using
# module.log_export_billing key "<resource>_<dest>"
member = module.log_export_billing["lbk"].writer_identity


depends_on = [
time_sleep.wait_sa_iam_membership
]
}

#----------------------#
# Send logs to Storage #
#----------------------#
Expand Down Expand Up @@ -158,6 +205,22 @@ resource "google_storage_bucket_iam_member" "storage_sink_member" {
member = module.log_export["${each.value}_sto"].writer_identity
}

#---------------------------------------------------------------#
# Storage Service account IAM membership for log_export_billing #
#---------------------------------------------------------------#
resource "google_storage_bucket_iam_member" "storage_sink_member_billing" {
count = var.enable_billing_account_sink == true && var.storage_options != null ? length(var.resources) : 0

bucket = module.destination_storage[0].resource_name
role = "roles/storage.objectCreator"
member = module.log_export_billing["sto"].writer_identity


depends_on = [
google_project_iam_member.logbucket_sink_member_billing
]
}


#----------------------#
# Send logs to Pub\Sub #
Expand Down Expand Up @@ -185,3 +248,20 @@ resource "google_pubsub_topic_iam_member" "pubsub_sink_member" {
role = "roles/pubsub.publisher"
member = module.log_export["${each.value}_pub"].writer_identity
}

#--------------------------------------------------------------#
# Pubsub Service account IAM membership for log_export_billing #
#--------------------------------------------------------------#
resource "google_pubsub_topic_iam_member" "pubsub_sink_member_billing" {
count = var.enable_billing_account_sink && var.pubsub_options != null ? length(var.resources) : 0


project = var.logging_destination_project_id
topic = module.destination_pubsub[0].resource_name
role = "roles/pubsub.publisher"
member = module.log_export_billing["pub"].writer_identity

depends_on = [
google_storage_bucket_iam_member.storage_sink_member_billing
]
}
8 changes: 8 additions & 0 deletions 1-org/modules/centralized-logging/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ output "logbucket_destination_name" {
value = try(module.destination_logbucket[0].resource_name, "")
}

output "billing_sink_names" {
description = "Map of log sink names with billing suffix"
value = {
for key, options in local.destinations_options :
key => "${coalesce(options.logging_sink_name, local.logging_sink_name_map[key])}-billing-${random_string.suffix.result}"
}
}

output "logbucket_linked_dataset_name" {
description = "The resource name of the Log Bucket linked BigQuery dataset."
value = try(module.destination_logbucket[0].linked_dataset_name, "")
Expand Down
12 changes: 12 additions & 0 deletions 1-org/modules/centralized-logging/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@ variable "resource_type" {
}
}

variable "billing_account" {
description = "Billing Account ID used in case sinks are under billing account level. Format 000000-000000-000000."
type = string
default = null
}

variable "enable_billing_account_sink" {
romanini-ciandt marked this conversation as resolved.
Show resolved Hide resolved
description = "If true, a log router sink will be created for the billing account. The billing_account variable cannot be null."
type = bool
default = true
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the default should be false because the billing account default value is null, which would make the module if the user did not change one of the values.

changing the default to false will also require that the call to the module uses

billing_account                = local.billing_account
enable_billing_account_sink    = true

}

variable "logging_project_key" {
description = "(Optional) The key of logging destination project if it is inside resources map. It is mandatory when resource_type = project and logging_target_type = logbucket."
type = string
Expand Down
2 changes: 1 addition & 1 deletion test/integration/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ require (
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
google.golang.org/grpc v1.58.3 // indirect
google.golang.org/protobuf v1.31.0 // indirect
google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/kube-openapi v0.0.0-20230905202853-d090da108d2f // indirect
sigs.k8s.io/kustomize/kyaml v0.16.0 // indirect
Expand Down
4 changes: 2 additions & 2 deletions test/integration/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -978,8 +978,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
Expand Down
28 changes: 28 additions & 0 deletions test/integration/org/org_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,34 @@ func TestOrg(t *testing.T) {

}

// Log Sink billing
billingAccount := org.GetTFSetupStringOutput("billing_account")
billingSinkNames := terraform.OutputMap(t, org.GetTFOptions(), "billing_sink_names")
billingLBKSinkName := billingSinkNames["lbk"]
billingPUBSinkName := billingSinkNames["pub"]
billingSTOSinkName := billingSinkNames["sto"]

for _, sinkBilling := range []struct {
name string
destination string
}{
{
name: billingSTOSinkName,
destination: fmt.Sprintf("storage.googleapis.com/%s", logsExportStorageBucketName),
},
{
name: billingLBKSinkName,
destination: fmt.Sprintf("logging.googleapis.com/%s", logBktFullName),
},
{
name: billingPUBSinkName,
destination: fmt.Sprintf("pubsub.googleapis.com/projects/%s/topics/%s", auditLogsProjectID, logsExportTopicName),
},
} {
logSinkBilling := gcloud.Runf(t, "logging sinks describe %s --billing-account %s", sinkBilling.name, billingAccount)
assert.Equal(sinkBilling.destination, logSinkBilling.Get("destination").String(), fmt.Sprintf("sink %s should have destination %s", sinkBilling.name, sinkBilling.destination))
}

// hub and spoke infrastructure
enable_hub_and_spoke, err := strconv.ParseBool(bootstrap.GetTFSetupStringOutput("enable_hub_and_spoke"))
require.NoError(t, err)
Expand Down