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

google_service_account_iam_policy not working as expected #1751

Closed
tsadoklevi opened this issue Jul 10, 2018 · 10 comments
Closed

google_service_account_iam_policy not working as expected #1751

tsadoklevi opened this issue Jul 10, 2018 · 10 comments
Labels

Comments

@tsadoklevi
Copy link

Terraform Version

Terraform v0.11.7

  • provider.google v1.15.0
  • provider.random v1.3.1

Affected Resource(s)

google_service_account_iam_policy

Terraform Configuration Files

resource "google_service_account" "default" {
    account_id   = "${var.account_id}"
    display_name = "${var.display_name}"
}
data "google_iam_policy" "default" {
    binding {
        role = "${var.role}"
        members = ["serviceAccount:${google_service_account.default.email}"]
    }
}
resource "google_service_account_iam_policy" "default" {
    # service_account_id  = "${google_service_account.default.account_id}"
    service_account_id  = "${google_service_account.default.email}"
    policy_data         = "${data.google_iam_policy.default.policy_data}"
}

output "iam_policy_etag" {
    value       = "${google_service_account_iam_policy.default.etag}"
    description = "The etag of the service acccount's IAM policy."
}

Debug Output

Error: Error applying plan:
2 error(s) occurred:
* module.service_account_for_storage.output.iam_policy_etag: Resource 'google_service_account_iam_policy.default' not found for variable 'google_service_account_iam_policy.default.etag'

* module.service_account_for_storage.google_service_account_iam_policy.default: "service_account_id" ("malta-prod-storage-sa@[GCP_PROJECT_ID].gserviceaccount.com") doesn't match regexp "projects/(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))/serviceAccounts/((?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))@appspot.gserviceaccount.com|[0-9]{1,20}[email protected]|[a-z](?:[-a-z0-9]{4,28}[a-z0-9])@[-a-z0-9\\.]{1,63}\\.iam\\.gserviceaccount\\.com$)"

Expected Behavior

Service account IAM policy should be created

Actual Behavior

Service account IAM policy is not created

@paddycarver
Copy link
Contributor

In google_service_account_iam_policy use ${google_service_account.default.self_link} not ${google_service_account.default.email} for service_account_id.

Arguably, we should probably support both, or at least have a better error for a common case like that.

@tsadoklevi
Copy link
Author

@paddycarver thank you.

I've tried it and here's what I got:

Error: Error running plan: 1 error(s) occurred:
* module.service_account_for_storage.google_service_account_iam_policy.default: 1 error(s) occurred:
* module.service_account_for_storage.google_service_account_iam_policy.default: Resource 'google_service_account.default' does not have attribute 'self_link' for variable 'google_service_account.default.self_link

Also, when I use

service_account_id  = "projects/${data.google_client_config.default.project}/serviceAccounts/${google_service_account.default.email}"

I get

Error: Error applying plan: 1 error(s) occurred:
* module.service_account_for_storage.google_service_account_iam_policy.default: 1 error(s) occurred:
* google_service_account_iam_policy.default: Error setting IAM policy for service account 'projects/anakatech/serviceAccounts/[email protected]': googleapi: Error 400: Role roles/storage.objectViewer is not supported for this resource., badRequest

And when I use -

 service_account_id  = "${google_service_account.default.email}"

I get -

Error: Error running plan: 1 error(s) occurred:
* module.service_account_for_storage.google_service_account_iam_policy.default: "service_account_id" ("[ACCOUNT_ID]@[GCP_PROJECT_ID].iam.gserviceaccount.com") doesn't match regexp "projects/(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))/serviceAccounts/((?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))@appspot.gserviceaccount.com|[0-9]{1,20}[email protected]|[a-z](?:[-a-z0-9]{4,28}[a-z0-9])@[-a-z0-9\\.]{1,63}\\.iam\\.gserviceaccount\\.com$)"

@paddycarver
Copy link
Contributor

That's what I get for not checking the docs before replying. Sorry about that! You want .name, not .self_link.

@tsadoklevi
Copy link
Author

@paddycarver thank you again.

Actually I think that the docs are wrong -

In google_service_account_key the service_account_id is defined as using .email or unique id -

service_account_id - (Required) The Service account id of the Key Pair. This can be a string in the format {ACCOUNT} or projects/{PROJECT_ID}/serviceAccounts/{ACCOUNT}, where {ACCOUNT} is the email address or unique id of the service account. If the {ACCOUNT} syntax is used, the project will be inferred from the account.

But, in the "Example Usage" section above it none of the above is used and instead the service_account_id is set using .name

data "google_service_account" "myaccount" {
  account_id = "myaccount"
}

data "google_service_account_key" "mykey" {
  service_account_id = "${data.google_service_account.myaccount.name}"
  public_key_type = "TYPE_X509_PEM_FILE"
}

output "mykey_public_key" {
  value = "${data.google_service_account_key.mykey.public_key}"
}

Moreover, in IAM policy for service account
the service_account_id is defined as -

service_account_id - (Required) The service account id to apply policy to.

and all the examples use -

service_account_id = "your-service-account-id"

IMHO when someone reads service_account_id s/he infers account_id and not '.unique_idor '.email' and surely not.name`.

I hope that the good people at behind Terraform would fix the docs and moreover fix the kind of value used in service_account_id so it would use account_id.

@tsadoklevi
Copy link
Author

Adding to the comment above I should note that I haven't been able to add roles/storage.objectViewer role to the above mentioned service account. Using this -

resource "google_service_account" "default" {
    account_id   = "${var.account_id}"
    display_name = "${var.display_name}"
}
data "google_iam_policy" "default" {
    binding {
        role = "roles/storage.objectViewer"
        members = ["serviceAccount:${google_service_account.default.email}"]
    }
}
resource "google_service_account_iam_policy" "default" {
    service_account_id  = "${google_service_account.default.name}"
    policy_data         = "${data.google_iam_policy.default.policy_data}"
}

... I received Error 400: Role roles/storage.objectViewer is not supported for this resource:

* module.service_account_for_storage.google_service_account_iam_policy.default: 1 error(s) occurred:
* google_service_account_iam_policy.default: Error setting IAM policy for service account 'projects/[PROJECT_ID]/serviceAccounts/[ACCOUNT_ID]@[PROJECT_ID].iam.gserviceaccount.com': googleapi: Error 400: Role roles/storage.objectViewer is not supported for this resource., badRequest
* google_container_node_pool.default: 1 error(s) occurred:

On the other hand I could add roles/storage.objectViewer role for a specified bucket using

resource "google_storage_bucket_iam_member" "member" {
    bucket          = "${google_storage_bucket.terraform_state.name}"
    role            = "roles/storage.objectViewer"
    member          = "serviceAccount:${module.service_account_for_storage.email}"
}

Any insights?

@walterdolce
Copy link
Contributor

Possibly related to #2180

@walterdolce
Copy link
Contributor

Hi @tsadoklevi, I suggest you resort to using the google_project_iam_member or google_project_iam_binding as suggested here: #1225 (comment)

I suspect all the google_service_account_iam_* resources are currently either broken and/or incomplete. Or maybe they're not. But they are definitely confusing.

https://github.com/terraform-providers/terraform-provider-google/issues/

@tsadoklevi
Copy link
Author

Hi @walterdolce - thank you for you comments.

I used google_project_iam_binding resource as follows and It worked -

resource "google_service_account" "cloudsql-sa" {
    account_id   = "cloudsql-sa"
}
resource "google_project_iam_binding" "cloudsql-sa-cloudsql-admin-role" {
    role    = "roles/cloudsql.admin"
    members = [
        "serviceAccount:${google_service_account.cloudsql-sa.email}"
    ]
}

This is equivalent to -

export PROJECT_ID=$(gcloud config list --format 'value(core.project)')
export SA_EMAIL= $(google_service_account.cloudsql-sa.email)
export ROLE="roles/cloudsql.admin"

gcloud projects add-iam-policy-binding $PROJECT_ID --member serviceAccount:$SA_EMAIL --role $ROLE

But as commented in #1225 the "side effect" of using this resource is that upon terraform destroy I lost all the members that were previously added to the role (!)

So, the right resource for adding a service account (or other types of members) is google_project_iam_member, as follows -

resource "google_service_account" "cloudsql-sa" {
    account_id   = "cloudsql-sa"
}
resource "google_project_iam_member" "cloudsql-sa-cloudsql-admin-role" {
    role    = "roles/cloudsql.admin"
    member = "serviceAccount:${google_service_account.cloudsql-sa.email}"
}

@paddycarver
Copy link
Contributor

More information on the iam resources possible for the project is available at https://www.terraform.io/docs/providers/google/r/google_project_iam.html. We're always happy to field suggestions on how to improve this to make it clearer.

In this case, the original problem (#1751 (comment)) is because the service_account_iam_policy is to determine who is allowed to use the service account, and what permissions they have on it (https://cloud.google.com/iam/docs/service-accounts#service_account_permissions), so you can't set the storage.objectViewer permission on it, because that's not a permission that makes sense in that context. You wanted to use the google_project_iam_member/google_project_iam_policy/google_project_iam_binding resource with the service account being the member, and storage.objectViewer being the role.

It looks like we got to a solution, however, so I'm going to close this out. Feel free to comment if you feel there's more to do here.

@ghost
Copy link

ghost commented Nov 17, 2018

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!

@ghost ghost locked and limited conversation to collaborators Nov 17, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

3 participants