Terraform v0.11.13
+ provider.google v2.6.0
+ provider.google-beta v2.6.0
+ provider.null v2.1.2
+ provider.template v2.1.2
resource "google_storage_bucket_iam_policy" "bucket" {
bucket = "${var.name}"
policy_data = "${data.google_iam_policy.bucket.policy_data}"
}
data "google_iam_policy" "bucket" {
# Multiple policies here...
binding {
role = "roles/storage.objectCreator"
members = [
"${var.storage_object_creators}",
]
}
}
We also tried enforcing members to be a list (which works with project's IAM policy resource - google_project_iam_policy):
binding {
role = "roles/storage.objectCreator"
members = [
"${compact(split(",", join(",", var.storage_object_creators)))}",
]
}
If variable is empty, policy is not applied. If role has members, policy is applied.
If variable is empty, Terraform fails with:
* google_storage_bucket_iam_policy.bucket: Error setting IAM policy for Storage Bucket "xyz": googleapi: Error 400: Must specify one or more members for binding with role: roles/storage.objectCreator
More details:
Reason: invalid, Message: Must specify one or more members for binding with role: roles/storage.objectCreator
There are several objects within GCP that do support removing all IAM permissions from them. However as the error message from the API shows, storage bucket does not allow this to happen. When you have written a config that has an empty list of members as above the only viable actions are to try and do what you specified (send the API request) or reject the configuration as invalid.
We don't reject the configuration because the reason it's invalid is due to business logic in the API that could change at some point and duplicating that logic into the Terraform provider would be brittle.
If you want to conditionally ignore a resource based on the value of a variable you can set count to 0 on the resource.
I don't know the structure of your storage_object_creators var but something like this might work:
resource "google_storage_bucket_iam_policy" "bucket" {
bucket = "${var.name}"
policy_data = "${data.google_iam_policy.bucket.policy_data}"
count = length("${var.storage_object_creators}") > 0 ? 1 : 0
}
But that means bucket IAM policy resource behaves different compared to the project IAM one, right? As the project one, from my understanding, simply removes role bindings with no members before sending it to the google API. And this would work for a bucket, too.
Your suggestion with a condition and count only works in a very limited case, where you can decide based on one variable. If you plan to use some module with input variables for different roles this becomes a mess, as you would need to implement a data provider + resource for each and every combination of empty input variable(s).
In 1.* versions some IAM resources were not always authoritative leading to unpredictable behavior. But I believe that google_project_iam_policy and google_storage_bucket_iam_binding are behaving the same in 2.*. If you set Terraform debug logging you can look at the api request bodies:
Here is the request for an empty member list passed to project iam binding:
---[ REQUEST ]---------------------------------------
POST /v1/projects/your-project-id:setIamPolicy?alt=json&prettyPrint=false HTTP/1.1
Host: cloudresourcemanager.googleapis.com
User-Agent: google-api-go-client/0.5 Terraform/0.12.0 (+https://www.terraform.io) terraform-provider-google/dev
Content-Length: 92
Content-Type: application/json
Accept-Encoding: gzip
2019-05-13T11:23:49.803-0700 [DEBUG] plugin.terraform-provider-google:
{
"policy": {
"bindings": [
{
"role": "roles/editor"
}
]
},
"updateMask": "bindings,etag,auditConfigs"
}
Here is the request for an empty member list passed to storage bucket iam binding:
PUT /storage/v1/b/chrisst-test/iam?alt=json&prettyPrint=false HTTP/1.1
Host: www.googleapis.com
User-Agent: google-api-go-client/0.5 Terraform/0.12.0 (+https://www.terraform.io) terraform-provider-google/dev
Content-Length: 68
Content-Type: application/json
Accept-Encoding: gzip
2019-05-13T11:19:15.963-0700 [DEBUG] plugin.terraform-provider-google:
{
"bindings": [
{
"role": "roles/storage.objectCreator"
}
],
"etag": "CAE="
}
In either case, specifying an empty array in Terraform is something it has to respect and pass to the API. If you are looking for something that won't try and remove members when that variable is empty maybe try using a non-authoritative resource like google_storage_bucket_iam_member.
Trying to remove members from a policy is a valid use of the resource so I don't see this as a bug in the resource even if specific roles won't allow removing all members.
So I was missreading output and that means as long as there is no change on google's APIs one provider will work and the other not. OK - not great and we need to find a way to bypass that issue within our module... ;)
I'm going to lock this issue because it has been closed for _30 days_ ⏳. This helps our maintainers find and focus on the active issues.
If you feel this issue should be reopened, we encourage creating a new issue linking back to this one for added context. If you feel I made an error 🤖 🙉 , please reach out to my human friends 👉 [email protected]. Thanks!