terraform-provider-google: google_logging_project_sink does not work for automatically created sinks

Community Note

  • Please vote on this issue by adding a šŸ‘ reaction to the original issue to help the community and maintainers prioritize this request.
  • Please do not leave +1 or me too comments, they generate extra noise for issue followers and do not help prioritize the request.
  • If you are interested in working on this issue or have submitted a pull request, please leave a comment.
  • If an issue is assigned to the modular-magician user, it is either in the process of being autogenerated, or is planned to be autogenerated soon. If an issue is assigned to a user, that user is claiming responsibility for the issue. If an issue is assigned to hashibot, a community member has claimed the issue already.

Terraform Version

Terraform v0.13.5

  • provider registry.terraform.io/hashicorp/google v3.46.0
  • provider registry.terraform.io/hashicorp/google-beta v3.37.0

Affected Resource(s)

  • google_logging_project_sink

Terraform Configuration Files

Elided config file:

resource "google_logging_project_sink" "log_sink" {
  name = "_Default"

  destination = vars.logging_bucket

  # While this is the default filter, it appears that it must be set explicitly.
  filter = <<-endfilter
    NOT LOG_ID("cloudaudit.googleapis.com/activity") AND 
    NOT LOG_ID("externalaudit.googleapis.com/activity") AND
    NOT LOG_ID("cloudaudit.googleapis.com/system_event") AND
    NOT LOG_ID("externalaudit.googleapis.com/system_event") AND
    NOT LOG_ID("cloudaudit.googleapis.com/access_transparency") AND
    NOT LOG_ID("externalaudit.googleapis.com/access_transparency")
  endfilter
}

Debug Output

The error is this:

googleapi: Error 409: Sink _Default already exists, alreadyExists

Attached is a non-debug log: elidedlog.txt It should be enough info to understand this issue but I can provide the full version if necessary.

Panic Output

Expected Behavior

The always-present logging sink should have been updated to point to the non-default bucket.

Actual Behavior

Terraform attempted to create a new sink, which is not possible for _Default.

Note: I also experimented with importing the existing _Default sink, but that failed at the ā€˜delete’ stage.

Error: googleapi: Error 403: Sink _Default cannot be deleted. Consider disabling instead, forbidden

Steps to Reproduce

  1. terraform apply

Important Factoids

References

I am trying to use Terraform to accomplish the steps described here; bucket creation mostly worked but the sink part did not. https://cloud.google.com/logging/docs/regionalized-logs

It looks like the google_logging_project_bucket_config (partly) address a similar issue by acquiring or creating a resource. See some discussion in issue #7587

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 43
  • Comments: 22

Commits related to this issue

Most upvoted comments

@edwardmedia It happened on the first apply.

The key here is that every Google Cloud project has several resources which always exist. That includes the _Default log sink. These resources can neither be created nor deleted. However, a number of properties on them can be changed, and thus it makes sense to be able to manage them with a tool like Terraform.

The other bug I referenced ( #7587 ) calls these singleton resources;

What is the correct way to manage them with Terraform? Some ways I could imagine:

  • Do it like google_logging_project_bucket_config. That is, simply adopt any existing resources if the user asks to ā€˜create’ them by adding it to the terraform configuration.
  • Keep current behavior of google_logging_project_sink . That is, fail on apply when apply attempts to create or delete one of these ā€˜singleton’ resources. Document that the user needs to run import after adding it to their Terraform configuration, and state rm after removing it from their Terraform configuration. Note that I believe this means that running Terraform to create an entire cloud project from scratch presumably will fail on first apply, then require the user to run ā€˜import’ of the resource (which was created by but invisible to terraform), then re-run apply to ensure the setup is complete.
  • Have Terraform know (via some mechanism) about ā€˜singleton’ resources and handle them differently. E.g. adopt instead of attempt to create; warn or error on delete; warn or error on a ā€˜forced replacement’ which would trigger a delete/create. Resources which are not ā€˜known’ as singleton resources continue to behave as today.

Ideally google_logging_project_bucket_config, google_logging_project_sink, and other Google Cloud resources would have similar behavior.

While I would strongly prefer being able to handle natively in Terraform, I was able to do a workaround using a null_resource to run the required gcloud commands:

resource "null_resource" "default_sink_disable_logging" {

 triggers = {
    project     = google_project.gtm.project_id
  }

  provisioner "local-exec" {
    command     = <<-EOT
    gcloud auth login --cred-file=./credentials.json
    gcloud config set project ${google_project.gtm.project_id}
    gcloud logging sinks update _Default --project=${google_project.gtm.project_id} --log-filter='NOT LOG_ID("cloudaudit.googleapis.com/activity") AND NOT LOG_ID("externalaudit.googleapis.com/activity") AND NOT LOG_ID("cloudaudit.googleapis.com/system_event") AND NOT LOG_ID("externalaudit.googleapis.com/system_event") AND NOT LOG_ID("cloudaudit.googleapis.com/access_transparency") AND NOT LOG_ID("externalaudit.googleapis.com/access_transparency")
    NOT LOG_ID("appengine.googleapis.com/nginx.request") AND NOT LOG_ID("appengine.googleapis.com/request_log")'
    EOT
  }
}

Hi @matthewblain or @estliberitas, are there any updates on this?

Starting in Terraform 1.5 you can now define imports as part of the Terraform configuration, so it should be possible to manage the default sinks with something akin to the below (not tested):

It’s worth noting the limitations with the import statement having tried doing this myself:

  1. You cannot use variables inside of the statement
  2. import statements can only live in the root module

Hi, is there any update on this issue?

Starting in Terraform 1.5 you can now define imports as part of the Terraform configuration, so it should be possible to manage the default sinks with something akin to the below (not tested):

import {
  to = google_logging_project_sink.default
  id = "projects/${var.project}/sinks/_Default"
}

resource "google_logging_project_sink" "default" {
  name = "_Default"
  project = var.project
  destination = "logging.googleapis.com/projects/${var.project}/locations/global/buckets/_Default"
  filter = "NOT LOG_ID(\"cloudaudit.googleapis.com/activity\") AND NOT LOG_ID(\"externalaudit.googleapis.com/activity\") AND NOT LOG_ID(\"cloudaudit.googleapis.com/system_event\") AND NOT LOG_ID(\"externalaudit.googleapis.com/system_event\") AND NOT LOG_ID(\"cloudaudit.googleapis.com/access_transparency\") AND NOT LOG_ID(\"externalaudit.googleapis.com/access_transparency\")"

  unique_writer_identity = true
}

For anyone else with this issue: You can change your Organization default to disable the _Default sink on new projects. Then you can use Terraform to create/manage a different sink, and pretend the _Default one doesn’t exist. Note: this will not update your existing projects.

I’m sure there are many use-cases that this will not be appropriate for, but it’s an acceptable workaround for me (far better than crashing-out, then importing, then retrying).