From 36972446d45c2d78555ebc293bb9d638475e83b2 Mon Sep 17 00:00:00 2001 From: The Magician Date: Mon, 11 Nov 2019 13:18:38 -0800 Subject: [PATCH] add IAM conditions support for generated IAM resources (#1352) Signed-off-by: Modular Magician --- .../iam_binary_authorization_attestor.go | 7 +- .../iam_cloud_functions_cloud_function.go | 7 +- google-beta/iam_iap_app_engine_service.go | 7 +- google-beta/iam_iap_app_engine_version.go | 12 +- ...m_iap_app_engine_version_generated_test.go | 419 +++++++++++++++++- google-beta/iam_iap_web.go | 7 +- google-beta/iam_iap_web_backend_service.go | 12 +- ..._iap_web_backend_service_generated_test.go | 325 +++++++++++++- google-beta/iam_iap_web_type_app_engine.go | 7 +- google-beta/iam_iap_web_type_compute.go | 7 +- google-beta/iam_pubsub_topic.go | 7 +- google-beta/iam_runtime_config_config.go | 7 +- google-beta/iam_source_repo_repository.go | 7 +- .../iap_app_engine_version_iam.html.markdown | 80 ++++ .../iap_web_backend_service_iam.html.markdown | 74 ++++ 15 files changed, 929 insertions(+), 56 deletions(-) diff --git a/google-beta/iam_binary_authorization_attestor.go b/google-beta/iam_binary_authorization_attestor.go index 00588fa7df..8217a589d9 100644 --- a/google-beta/iam_binary_authorization_attestor.go +++ b/google-beta/iam_binary_authorization_attestor.go @@ -75,8 +75,6 @@ func BinaryAuthorizationAttestorIamUpdaterProducer(d *schema.ResourceData, confi d.Set("project", u.project) d.Set("attestor", u.GetResourceId()) - d.SetId(u.GetResourceId()) - return u, nil } @@ -105,7 +103,7 @@ func BinaryAuthorizationAttestorIdParseFunc(d *schema.ResourceData, config *Conf Config: config, } d.Set("attestor", u.GetResourceId()) - d.SetId(u.GetResourceId()) + return nil } @@ -116,8 +114,9 @@ func (u *BinaryAuthorizationAttestorIamUpdater) GetResourceIamPolicy() (*cloudre if err != nil { return nil, err } + var obj map[string]interface{} - policy, err := sendRequest(u.Config, "GET", project, url, nil) + policy, err := sendRequest(u.Config, "GET", project, url, obj) if err != nil { return nil, errwrap.Wrapf(fmt.Sprintf("Error retrieving IAM policy for %s: {{err}}", u.DescribeResource()), err) } diff --git a/google-beta/iam_cloud_functions_cloud_function.go b/google-beta/iam_cloud_functions_cloud_function.go index 478356ad5d..aa6a26fc9f 100644 --- a/google-beta/iam_cloud_functions_cloud_function.go +++ b/google-beta/iam_cloud_functions_cloud_function.go @@ -89,8 +89,6 @@ func CloudFunctionsCloudFunctionIamUpdaterProducer(d *schema.ResourceData, confi d.Set("region", u.region) d.Set("cloud_function", u.GetResourceId()) - d.SetId(u.GetResourceId()) - return u, nil } @@ -125,7 +123,7 @@ func CloudFunctionsCloudFunctionIdParseFunc(d *schema.ResourceData, config *Conf Config: config, } d.Set("cloud_function", u.GetResourceId()) - d.SetId(u.GetResourceId()) + return nil } @@ -136,8 +134,9 @@ func (u *CloudFunctionsCloudFunctionIamUpdater) GetResourceIamPolicy() (*cloudre if err != nil { return nil, err } + var obj map[string]interface{} - policy, err := sendRequest(u.Config, "GET", project, url, nil) + policy, err := sendRequest(u.Config, "GET", project, url, obj) if err != nil { return nil, errwrap.Wrapf(fmt.Sprintf("Error retrieving IAM policy for %s: {{err}}", u.DescribeResource()), err) } diff --git a/google-beta/iam_iap_app_engine_service.go b/google-beta/iam_iap_app_engine_service.go index 1294fe62c0..206c1a31f7 100644 --- a/google-beta/iam_iap_app_engine_service.go +++ b/google-beta/iam_iap_app_engine_service.go @@ -87,8 +87,6 @@ func IapAppEngineServiceIamUpdaterProducer(d *schema.ResourceData, config *Confi d.Set("app_id", u.appId) d.Set("service", u.GetResourceId()) - d.SetId(u.GetResourceId()) - return u, nil } @@ -118,7 +116,7 @@ func IapAppEngineServiceIdParseFunc(d *schema.ResourceData, config *Config) erro Config: config, } d.Set("service", u.GetResourceId()) - d.SetId(u.GetResourceId()) + return nil } @@ -129,8 +127,9 @@ func (u *IapAppEngineServiceIamUpdater) GetResourceIamPolicy() (*cloudresourcema if err != nil { return nil, err } + var obj map[string]interface{} - policy, err := sendRequest(u.Config, "POST", project, url, nil) + policy, err := sendRequest(u.Config, "POST", project, url, obj) if err != nil { return nil, errwrap.Wrapf(fmt.Sprintf("Error retrieving IAM policy for %s: {{err}}", u.DescribeResource()), err) } diff --git a/google-beta/iam_iap_app_engine_version.go b/google-beta/iam_iap_app_engine_version.go index f542c95ad8..c07506c1e9 100644 --- a/google-beta/iam_iap_app_engine_version.go +++ b/google-beta/iam_iap_app_engine_version.go @@ -99,8 +99,6 @@ func IapAppEngineVersionIamUpdaterProducer(d *schema.ResourceData, config *Confi d.Set("service", u.service) d.Set("version_id", u.GetResourceId()) - d.SetId(u.GetResourceId()) - return u, nil } @@ -131,7 +129,7 @@ func IapAppEngineVersionIdParseFunc(d *schema.ResourceData, config *Config) erro Config: config, } d.Set("version_id", u.GetResourceId()) - d.SetId(u.GetResourceId()) + return nil } @@ -142,8 +140,14 @@ func (u *IapAppEngineVersionIamUpdater) GetResourceIamPolicy() (*cloudresourcema if err != nil { return nil, err } + var obj map[string]interface{} + obj = map[string]interface{}{ + "options": map[string]interface{}{ + "requestedPolicyVersion": iamPolicyVersion, + }, + } - policy, err := sendRequest(u.Config, "POST", project, url, nil) + policy, err := sendRequest(u.Config, "POST", project, url, obj) if err != nil { return nil, errwrap.Wrapf(fmt.Sprintf("Error retrieving IAM policy for %s: {{err}}", u.DescribeResource()), err) } diff --git a/google-beta/iam_iap_app_engine_version_generated_test.go b/google-beta/iam_iap_app_engine_version_generated_test.go index 48491b927b..7de5537681 100644 --- a/google-beta/iam_iap_app_engine_version_generated_test.go +++ b/google-beta/iam_iap_app_engine_version_generated_test.go @@ -26,8 +26,10 @@ func TestAccIapAppEngineVersionIamBindingGenerated(t *testing.T) { t.Parallel() context := map[string]interface{}{ - "random_suffix": acctest.RandString(10), - "role": "roles/iap.httpsResourceAccessor", + "random_suffix": acctest.RandString(10), + "role": "roles/iap.httpsResourceAccessor", + "condition_title": "expires_after_2019_12_31", + "condition_expr": `request.time < timestamp(\"2020-01-01T00:00:00Z\")`, } resource.Test(t, resource.TestCase{ @@ -61,8 +63,10 @@ func TestAccIapAppEngineVersionIamMemberGenerated(t *testing.T) { t.Parallel() context := map[string]interface{}{ - "random_suffix": acctest.RandString(10), - "role": "roles/iap.httpsResourceAccessor", + "random_suffix": acctest.RandString(10), + "role": "roles/iap.httpsResourceAccessor", + "condition_title": "expires_after_2019_12_31", + "condition_expr": `request.time < timestamp(\"2020-01-01T00:00:00Z\")`, } resource.Test(t, resource.TestCase{ @@ -87,8 +91,10 @@ func TestAccIapAppEngineVersionIamPolicyGenerated(t *testing.T) { t.Parallel() context := map[string]interface{}{ - "random_suffix": acctest.RandString(10), - "role": "roles/iap.httpsResourceAccessor", + "random_suffix": acctest.RandString(10), + "role": "roles/iap.httpsResourceAccessor", + "condition_title": "expires_after_2019_12_31", + "condition_expr": `request.time < timestamp(\"2020-01-01T00:00:00Z\")`, } resource.Test(t, resource.TestCase{ @@ -108,6 +114,153 @@ func TestAccIapAppEngineVersionIamPolicyGenerated(t *testing.T) { }) } +func TestAccIapAppEngineVersionIamBindingGenerated_withCondition(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(10), + "role": "roles/iap.httpsResourceAccessor", + "condition_title": "expires_after_2019_12_31", + "condition_expr": `request.time < timestamp(\"2020-01-01T00:00:00Z\")`, + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccIapAppEngineVersionIamBinding_withConditionGenerated(context), + }, + { + ResourceName: "google_iap_app_engine_version_iam_binding.foo", + ImportStateId: fmt.Sprintf("projects/%s/iap_web/appengine-%s/services/%s/versions/%s roles/iap.httpsResourceAccessor %s", getTestProjectFromEnv(), getTestProjectFromEnv(), "default", context["random_suffix"], context["condition_title"]), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccIapAppEngineVersionIamBindingGenerated_withAndWithoutCondition(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(10), + "role": "roles/iap.httpsResourceAccessor", + "condition_title": "expires_after_2019_12_31", + "condition_expr": `request.time < timestamp(\"2020-01-01T00:00:00Z\")`, + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccIapAppEngineVersionIamBinding_withAndWithoutConditionGenerated(context), + }, + { + ResourceName: "google_iap_app_engine_version_iam_binding.foo", + ImportStateId: fmt.Sprintf("projects/%s/iap_web/appengine-%s/services/%s/versions/%s roles/iap.httpsResourceAccessor", getTestProjectFromEnv(), getTestProjectFromEnv(), "default", context["random_suffix"]), + ImportState: true, + ImportStateVerify: true, + }, + { + ResourceName: "google_iap_app_engine_version_iam_binding.foo2", + ImportStateId: fmt.Sprintf("projects/%s/iap_web/appengine-%s/services/%s/versions/%s roles/iap.httpsResourceAccessor %s", getTestProjectFromEnv(), getTestProjectFromEnv(), "default", context["random_suffix"], context["condition_title"]), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccIapAppEngineVersionIamMemberGenerated_withCondition(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(10), + "role": "roles/iap.httpsResourceAccessor", + "condition_title": "expires_after_2019_12_31", + "condition_expr": `request.time < timestamp(\"2020-01-01T00:00:00Z\")`, + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccIapAppEngineVersionIamMember_withConditionGenerated(context), + }, + { + ResourceName: "google_iap_app_engine_version_iam_member.foo", + ImportStateId: fmt.Sprintf("projects/%s/iap_web/appengine-%s/services/%s/versions/%s roles/iap.httpsResourceAccessor user:admin@hashicorptest.com %s", getTestProjectFromEnv(), getTestProjectFromEnv(), "default", context["random_suffix"], context["condition_title"]), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccIapAppEngineVersionIamMemberGenerated_withAndWithoutCondition(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(10), + "role": "roles/iap.httpsResourceAccessor", + "condition_title": "expires_after_2019_12_31", + "condition_expr": `request.time < timestamp(\"2020-01-01T00:00:00Z\")`, + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccIapAppEngineVersionIamMember_withAndWithoutConditionGenerated(context), + }, + { + ResourceName: "google_iap_app_engine_version_iam_member.foo", + ImportStateId: fmt.Sprintf("projects/%s/iap_web/appengine-%s/services/%s/versions/%s roles/iap.httpsResourceAccessor user:admin@hashicorptest.com", getTestProjectFromEnv(), getTestProjectFromEnv(), "default", context["random_suffix"]), + ImportState: true, + ImportStateVerify: true, + }, + { + ResourceName: "google_iap_app_engine_version_iam_member.foo2", + ImportStateId: fmt.Sprintf("projects/%s/iap_web/appengine-%s/services/%s/versions/%s roles/iap.httpsResourceAccessor user:admin@hashicorptest.com %s", getTestProjectFromEnv(), getTestProjectFromEnv(), "default", context["random_suffix"], context["condition_title"]), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccIapAppEngineVersionIamPolicyGenerated_withCondition(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(10), + "role": "roles/iap.httpsResourceAccessor", + "condition_title": "expires_after_2019_12_31", + "condition_expr": `request.time < timestamp(\"2020-01-01T00:00:00Z\")`, + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccIapAppEngineVersionIamPolicy_withConditionGenerated(context), + }, + { + ResourceName: "google_iap_app_engine_version_iam_policy.foo", + ImportStateId: fmt.Sprintf("projects/%s/iap_web/appengine-%s/services/%s/versions/%s", getTestProjectFromEnv(), getTestProjectFromEnv(), "default", context["random_suffix"]), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccIapAppEngineVersionIamMember_basicGenerated(context map[string]interface{}) string { return Nprintf(` resource "google_storage_bucket" "bucket" { @@ -277,3 +430,257 @@ resource "google_iap_app_engine_version_iam_binding" "foo" { } `, context) } + +func testAccIapAppEngineVersionIamBinding_withConditionGenerated(context map[string]interface{}) string { + return Nprintf(` +resource "google_storage_bucket" "bucket" { + name = "appengine-static-content-%{random_suffix}" +} + +resource "google_storage_bucket_object" "object" { + name = "hello-world.zip" + bucket = "${google_storage_bucket.bucket.name}" + source = "./test-fixtures/appengine/hello-world.zip" +} + +resource "google_app_engine_standard_app_version" "version" { + version_id = "%{random_suffix}" + service = "default" + runtime = "nodejs10" + noop_on_destroy = false + entrypoint { + shell = "node ./app.js" + } + deployment { + zip { + source_url = "https://storage.googleapis.com/${google_storage_bucket.bucket.name}/hello-world.zip" + } + } + env_variables = { + port = "8080" + } +} + +resource "google_iap_app_engine_version_iam_binding" "foo" { + project = "${google_app_engine_standard_app_version.version.project}" + app_id = "${google_app_engine_standard_app_version.version.project}" + service = "${google_app_engine_standard_app_version.version.service}" + version_id = "${google_app_engine_standard_app_version.version.version_id}" + role = "%{role}" + members = ["user:admin@hashicorptest.com"] + condition { + title = "%{condition_title}" + description = "Expiring at midnight of 2019-12-31" + expression = "%{condition_expr}" + } +} +`, context) +} + +func testAccIapAppEngineVersionIamBinding_withAndWithoutConditionGenerated(context map[string]interface{}) string { + return Nprintf(` +resource "google_storage_bucket" "bucket" { + name = "appengine-static-content-%{random_suffix}" +} + +resource "google_storage_bucket_object" "object" { + name = "hello-world.zip" + bucket = "${google_storage_bucket.bucket.name}" + source = "./test-fixtures/appengine/hello-world.zip" +} + +resource "google_app_engine_standard_app_version" "version" { + version_id = "%{random_suffix}" + service = "default" + runtime = "nodejs10" + noop_on_destroy = false + entrypoint { + shell = "node ./app.js" + } + deployment { + zip { + source_url = "https://storage.googleapis.com/${google_storage_bucket.bucket.name}/hello-world.zip" + } + } + env_variables = { + port = "8080" + } +} + +resource "google_iap_app_engine_version_iam_binding" "foo" { + project = "${google_app_engine_standard_app_version.version.project}" + app_id = "${google_app_engine_standard_app_version.version.project}" + service = "${google_app_engine_standard_app_version.version.service}" + version_id = "${google_app_engine_standard_app_version.version.version_id}" + role = "%{role}" + members = ["user:admin@hashicorptest.com"] +} + +resource "google_iap_app_engine_version_iam_binding" "foo2" { + project = "${google_app_engine_standard_app_version.version.project}" + app_id = "${google_app_engine_standard_app_version.version.project}" + service = "${google_app_engine_standard_app_version.version.service}" + version_id = "${google_app_engine_standard_app_version.version.version_id}" + role = "%{role}" + members = ["user:admin@hashicorptest.com"] + condition { + title = "%{condition_title}" + description = "Expiring at midnight of 2019-12-31" + expression = "%{condition_expr}" + } +} +`, context) +} + +func testAccIapAppEngineVersionIamMember_withConditionGenerated(context map[string]interface{}) string { + return Nprintf(` +resource "google_storage_bucket" "bucket" { + name = "appengine-static-content-%{random_suffix}" +} + +resource "google_storage_bucket_object" "object" { + name = "hello-world.zip" + bucket = "${google_storage_bucket.bucket.name}" + source = "./test-fixtures/appengine/hello-world.zip" +} + +resource "google_app_engine_standard_app_version" "version" { + version_id = "%{random_suffix}" + service = "default" + runtime = "nodejs10" + noop_on_destroy = false + entrypoint { + shell = "node ./app.js" + } + deployment { + zip { + source_url = "https://storage.googleapis.com/${google_storage_bucket.bucket.name}/hello-world.zip" + } + } + env_variables = { + port = "8080" + } +} + +resource "google_iap_app_engine_version_iam_member" "foo" { + project = "${google_app_engine_standard_app_version.version.project}" + app_id = "${google_app_engine_standard_app_version.version.project}" + service = "${google_app_engine_standard_app_version.version.service}" + version_id = "${google_app_engine_standard_app_version.version.version_id}" + role = "%{role}" + member = "user:admin@hashicorptest.com" + condition { + title = "%{condition_title}" + description = "Expiring at midnight of 2019-12-31" + expression = "%{condition_expr}" + } +} +`, context) +} + +func testAccIapAppEngineVersionIamMember_withAndWithoutConditionGenerated(context map[string]interface{}) string { + return Nprintf(` +resource "google_storage_bucket" "bucket" { + name = "appengine-static-content-%{random_suffix}" +} + +resource "google_storage_bucket_object" "object" { + name = "hello-world.zip" + bucket = "${google_storage_bucket.bucket.name}" + source = "./test-fixtures/appengine/hello-world.zip" +} + +resource "google_app_engine_standard_app_version" "version" { + version_id = "%{random_suffix}" + service = "default" + runtime = "nodejs10" + noop_on_destroy = false + entrypoint { + shell = "node ./app.js" + } + deployment { + zip { + source_url = "https://storage.googleapis.com/${google_storage_bucket.bucket.name}/hello-world.zip" + } + } + env_variables = { + port = "8080" + } +} + +resource "google_iap_app_engine_version_iam_member" "foo" { + project = "${google_app_engine_standard_app_version.version.project}" + app_id = "${google_app_engine_standard_app_version.version.project}" + service = "${google_app_engine_standard_app_version.version.service}" + version_id = "${google_app_engine_standard_app_version.version.version_id}" + role = "%{role}" + member = "user:admin@hashicorptest.com" +} + +resource "google_iap_app_engine_version_iam_member" "foo2" { + project = "${google_app_engine_standard_app_version.version.project}" + app_id = "${google_app_engine_standard_app_version.version.project}" + service = "${google_app_engine_standard_app_version.version.service}" + version_id = "${google_app_engine_standard_app_version.version.version_id}" + role = "%{role}" + member = "user:admin@hashicorptest.com" + condition { + title = "%{condition_title}" + description = "Expiring at midnight of 2019-12-31" + expression = "%{condition_expr}" + } +} +`, context) +} + +func testAccIapAppEngineVersionIamPolicy_withConditionGenerated(context map[string]interface{}) string { + return Nprintf(` +resource "google_storage_bucket" "bucket" { + name = "appengine-static-content-%{random_suffix}" +} + +resource "google_storage_bucket_object" "object" { + name = "hello-world.zip" + bucket = "${google_storage_bucket.bucket.name}" + source = "./test-fixtures/appengine/hello-world.zip" +} + +resource "google_app_engine_standard_app_version" "version" { + version_id = "%{random_suffix}" + service = "default" + runtime = "nodejs10" + noop_on_destroy = false + entrypoint { + shell = "node ./app.js" + } + deployment { + zip { + source_url = "https://storage.googleapis.com/${google_storage_bucket.bucket.name}/hello-world.zip" + } + } + env_variables = { + port = "8080" + } +} + +data "google_iam_policy" "foo" { + binding { + role = "%{role}" + members = ["user:admin@hashicorptest.com"] + condition { + title = "%{condition_title}" + description = "Expiring at midnight of 2019-12-31" + expression = "%{condition_expr}" + } + } +} + +resource "google_iap_app_engine_version_iam_policy" "foo" { + project = "${google_app_engine_standard_app_version.version.project}" + app_id = "${google_app_engine_standard_app_version.version.project}" + service = "${google_app_engine_standard_app_version.version.service}" + version_id = "${google_app_engine_standard_app_version.version.version_id}" + policy_data = "${data.google_iam_policy.foo.policy_data}" +} +`, context) +} diff --git a/google-beta/iam_iap_web.go b/google-beta/iam_iap_web.go index 7f00226546..549542f3a7 100644 --- a/google-beta/iam_iap_web.go +++ b/google-beta/iam_iap_web.go @@ -64,8 +64,6 @@ func IapWebIamUpdaterProducer(d *schema.ResourceData, config *Config) (ResourceI d.Set("project", u.project) - d.SetId(u.GetResourceId()) - return u, nil } @@ -93,7 +91,7 @@ func IapWebIdParseFunc(d *schema.ResourceData, config *Config) error { Config: config, } d.Set("project", u.project) - d.SetId(u.GetResourceId()) + return nil } @@ -104,8 +102,9 @@ func (u *IapWebIamUpdater) GetResourceIamPolicy() (*cloudresourcemanager.Policy, if err != nil { return nil, err } + var obj map[string]interface{} - policy, err := sendRequest(u.Config, "POST", project, url, nil) + policy, err := sendRequest(u.Config, "POST", project, url, obj) if err != nil { return nil, errwrap.Wrapf(fmt.Sprintf("Error retrieving IAM policy for %s: {{err}}", u.DescribeResource()), err) } diff --git a/google-beta/iam_iap_web_backend_service.go b/google-beta/iam_iap_web_backend_service.go index 7199337c91..68395d9550 100644 --- a/google-beta/iam_iap_web_backend_service.go +++ b/google-beta/iam_iap_web_backend_service.go @@ -75,8 +75,6 @@ func IapWebBackendServiceIamUpdaterProducer(d *schema.ResourceData, config *Conf d.Set("project", u.project) d.Set("web_backend_service", u.GetResourceId()) - d.SetId(u.GetResourceId()) - return u, nil } @@ -105,7 +103,7 @@ func IapWebBackendServiceIdParseFunc(d *schema.ResourceData, config *Config) err Config: config, } d.Set("web_backend_service", u.GetResourceId()) - d.SetId(u.GetResourceId()) + return nil } @@ -116,8 +114,14 @@ func (u *IapWebBackendServiceIamUpdater) GetResourceIamPolicy() (*cloudresourcem if err != nil { return nil, err } + var obj map[string]interface{} + obj = map[string]interface{}{ + "options": map[string]interface{}{ + "requestedPolicyVersion": iamPolicyVersion, + }, + } - policy, err := sendRequest(u.Config, "POST", project, url, nil) + policy, err := sendRequest(u.Config, "POST", project, url, obj) if err != nil { return nil, errwrap.Wrapf(fmt.Sprintf("Error retrieving IAM policy for %s: {{err}}", u.DescribeResource()), err) } diff --git a/google-beta/iam_iap_web_backend_service_generated_test.go b/google-beta/iam_iap_web_backend_service_generated_test.go index 7e097441fb..dec2742aba 100644 --- a/google-beta/iam_iap_web_backend_service_generated_test.go +++ b/google-beta/iam_iap_web_backend_service_generated_test.go @@ -26,8 +26,10 @@ func TestAccIapWebBackendServiceIamBindingGenerated(t *testing.T) { t.Parallel() context := map[string]interface{}{ - "random_suffix": acctest.RandString(10), - "role": "roles/iap.httpsResourceAccessor", + "random_suffix": acctest.RandString(10), + "role": "roles/iap.httpsResourceAccessor", + "condition_title": "expires_after_2019_12_31", + "condition_expr": `request.time < timestamp(\"2020-01-01T00:00:00Z\")`, } resource.Test(t, resource.TestCase{ @@ -61,8 +63,10 @@ func TestAccIapWebBackendServiceIamMemberGenerated(t *testing.T) { t.Parallel() context := map[string]interface{}{ - "random_suffix": acctest.RandString(10), - "role": "roles/iap.httpsResourceAccessor", + "random_suffix": acctest.RandString(10), + "role": "roles/iap.httpsResourceAccessor", + "condition_title": "expires_after_2019_12_31", + "condition_expr": `request.time < timestamp(\"2020-01-01T00:00:00Z\")`, } resource.Test(t, resource.TestCase{ @@ -87,8 +91,10 @@ func TestAccIapWebBackendServiceIamPolicyGenerated(t *testing.T) { t.Parallel() context := map[string]interface{}{ - "random_suffix": acctest.RandString(10), - "role": "roles/iap.httpsResourceAccessor", + "random_suffix": acctest.RandString(10), + "role": "roles/iap.httpsResourceAccessor", + "condition_title": "expires_after_2019_12_31", + "condition_expr": `request.time < timestamp(\"2020-01-01T00:00:00Z\")`, } resource.Test(t, resource.TestCase{ @@ -108,6 +114,153 @@ func TestAccIapWebBackendServiceIamPolicyGenerated(t *testing.T) { }) } +func TestAccIapWebBackendServiceIamBindingGenerated_withCondition(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(10), + "role": "roles/iap.httpsResourceAccessor", + "condition_title": "expires_after_2019_12_31", + "condition_expr": `request.time < timestamp(\"2020-01-01T00:00:00Z\")`, + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccIapWebBackendServiceIamBinding_withConditionGenerated(context), + }, + { + ResourceName: "google_iap_web_backend_service_iam_binding.foo", + ImportStateId: fmt.Sprintf("projects/%s/iap_web/compute/services/%s roles/iap.httpsResourceAccessor %s", getTestProjectFromEnv(), fmt.Sprintf("backend-service%s", context["random_suffix"]), context["condition_title"]), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccIapWebBackendServiceIamBindingGenerated_withAndWithoutCondition(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(10), + "role": "roles/iap.httpsResourceAccessor", + "condition_title": "expires_after_2019_12_31", + "condition_expr": `request.time < timestamp(\"2020-01-01T00:00:00Z\")`, + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccIapWebBackendServiceIamBinding_withAndWithoutConditionGenerated(context), + }, + { + ResourceName: "google_iap_web_backend_service_iam_binding.foo", + ImportStateId: fmt.Sprintf("projects/%s/iap_web/compute/services/%s roles/iap.httpsResourceAccessor", getTestProjectFromEnv(), fmt.Sprintf("backend-service%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + { + ResourceName: "google_iap_web_backend_service_iam_binding.foo2", + ImportStateId: fmt.Sprintf("projects/%s/iap_web/compute/services/%s roles/iap.httpsResourceAccessor %s", getTestProjectFromEnv(), fmt.Sprintf("backend-service%s", context["random_suffix"]), context["condition_title"]), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccIapWebBackendServiceIamMemberGenerated_withCondition(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(10), + "role": "roles/iap.httpsResourceAccessor", + "condition_title": "expires_after_2019_12_31", + "condition_expr": `request.time < timestamp(\"2020-01-01T00:00:00Z\")`, + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccIapWebBackendServiceIamMember_withConditionGenerated(context), + }, + { + ResourceName: "google_iap_web_backend_service_iam_member.foo", + ImportStateId: fmt.Sprintf("projects/%s/iap_web/compute/services/%s roles/iap.httpsResourceAccessor user:admin@hashicorptest.com %s", getTestProjectFromEnv(), fmt.Sprintf("backend-service%s", context["random_suffix"]), context["condition_title"]), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccIapWebBackendServiceIamMemberGenerated_withAndWithoutCondition(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(10), + "role": "roles/iap.httpsResourceAccessor", + "condition_title": "expires_after_2019_12_31", + "condition_expr": `request.time < timestamp(\"2020-01-01T00:00:00Z\")`, + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccIapWebBackendServiceIamMember_withAndWithoutConditionGenerated(context), + }, + { + ResourceName: "google_iap_web_backend_service_iam_member.foo", + ImportStateId: fmt.Sprintf("projects/%s/iap_web/compute/services/%s roles/iap.httpsResourceAccessor user:admin@hashicorptest.com", getTestProjectFromEnv(), fmt.Sprintf("backend-service%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + { + ResourceName: "google_iap_web_backend_service_iam_member.foo2", + ImportStateId: fmt.Sprintf("projects/%s/iap_web/compute/services/%s roles/iap.httpsResourceAccessor user:admin@hashicorptest.com %s", getTestProjectFromEnv(), fmt.Sprintf("backend-service%s", context["random_suffix"]), context["condition_title"]), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccIapWebBackendServiceIamPolicyGenerated_withCondition(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(10), + "role": "roles/iap.httpsResourceAccessor", + "condition_title": "expires_after_2019_12_31", + "condition_expr": `request.time < timestamp(\"2020-01-01T00:00:00Z\")`, + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccIapWebBackendServiceIamPolicy_withConditionGenerated(context), + }, + { + ResourceName: "google_iap_web_backend_service_iam_policy.foo", + ImportStateId: fmt.Sprintf("projects/%s/iap_web/compute/services/%s", getTestProjectFromEnv(), fmt.Sprintf("backend-service%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccIapWebBackendServiceIamMember_basicGenerated(context map[string]interface{}) string { return Nprintf(` resource "google_compute_backend_service" "default" { @@ -205,3 +358,163 @@ resource "google_iap_web_backend_service_iam_binding" "foo" { } `, context) } + +func testAccIapWebBackendServiceIamBinding_withConditionGenerated(context map[string]interface{}) string { + return Nprintf(` +resource "google_compute_backend_service" "default" { + name = "backend-service%{random_suffix}" + health_checks = ["${google_compute_http_health_check.default.self_link}"] +} + +resource "google_compute_http_health_check" "default" { + name = "health-check%{random_suffix}" + request_path = "/" + check_interval_sec = 1 + timeout_sec = 1 +} + +resource "google_iap_web_backend_service_iam_binding" "foo" { + project = "${google_compute_backend_service.default.project}" + web_backend_service = "${google_compute_backend_service.default.name}" + role = "%{role}" + members = ["user:admin@hashicorptest.com"] + condition { + title = "%{condition_title}" + description = "Expiring at midnight of 2019-12-31" + expression = "%{condition_expr}" + } +} +`, context) +} + +func testAccIapWebBackendServiceIamBinding_withAndWithoutConditionGenerated(context map[string]interface{}) string { + return Nprintf(` +resource "google_compute_backend_service" "default" { + name = "backend-service%{random_suffix}" + health_checks = ["${google_compute_http_health_check.default.self_link}"] +} + +resource "google_compute_http_health_check" "default" { + name = "health-check%{random_suffix}" + request_path = "/" + check_interval_sec = 1 + timeout_sec = 1 +} + +resource "google_iap_web_backend_service_iam_binding" "foo" { + project = "${google_compute_backend_service.default.project}" + web_backend_service = "${google_compute_backend_service.default.name}" + role = "%{role}" + members = ["user:admin@hashicorptest.com"] +} + +resource "google_iap_web_backend_service_iam_binding" "foo2" { + project = "${google_compute_backend_service.default.project}" + web_backend_service = "${google_compute_backend_service.default.name}" + role = "%{role}" + members = ["user:admin@hashicorptest.com"] + condition { + title = "%{condition_title}" + description = "Expiring at midnight of 2019-12-31" + expression = "%{condition_expr}" + } +} +`, context) +} + +func testAccIapWebBackendServiceIamMember_withConditionGenerated(context map[string]interface{}) string { + return Nprintf(` +resource "google_compute_backend_service" "default" { + name = "backend-service%{random_suffix}" + health_checks = ["${google_compute_http_health_check.default.self_link}"] +} + +resource "google_compute_http_health_check" "default" { + name = "health-check%{random_suffix}" + request_path = "/" + check_interval_sec = 1 + timeout_sec = 1 +} + +resource "google_iap_web_backend_service_iam_member" "foo" { + project = "${google_compute_backend_service.default.project}" + web_backend_service = "${google_compute_backend_service.default.name}" + role = "%{role}" + member = "user:admin@hashicorptest.com" + condition { + title = "%{condition_title}" + description = "Expiring at midnight of 2019-12-31" + expression = "%{condition_expr}" + } +} +`, context) +} + +func testAccIapWebBackendServiceIamMember_withAndWithoutConditionGenerated(context map[string]interface{}) string { + return Nprintf(` +resource "google_compute_backend_service" "default" { + name = "backend-service%{random_suffix}" + health_checks = ["${google_compute_http_health_check.default.self_link}"] +} + +resource "google_compute_http_health_check" "default" { + name = "health-check%{random_suffix}" + request_path = "/" + check_interval_sec = 1 + timeout_sec = 1 +} + +resource "google_iap_web_backend_service_iam_member" "foo" { + project = "${google_compute_backend_service.default.project}" + web_backend_service = "${google_compute_backend_service.default.name}" + role = "%{role}" + member = "user:admin@hashicorptest.com" +} + +resource "google_iap_web_backend_service_iam_member" "foo2" { + project = "${google_compute_backend_service.default.project}" + web_backend_service = "${google_compute_backend_service.default.name}" + role = "%{role}" + member = "user:admin@hashicorptest.com" + condition { + title = "%{condition_title}" + description = "Expiring at midnight of 2019-12-31" + expression = "%{condition_expr}" + } +} +`, context) +} + +func testAccIapWebBackendServiceIamPolicy_withConditionGenerated(context map[string]interface{}) string { + return Nprintf(` +resource "google_compute_backend_service" "default" { + name = "backend-service%{random_suffix}" + health_checks = ["${google_compute_http_health_check.default.self_link}"] +} + +resource "google_compute_http_health_check" "default" { + name = "health-check%{random_suffix}" + request_path = "/" + check_interval_sec = 1 + timeout_sec = 1 +} + +data "google_iam_policy" "foo" { + binding { + role = "%{role}" + members = ["user:admin@hashicorptest.com"] + condition { + title = "%{condition_title}" + description = "Expiring at midnight of 2019-12-31" + expression = "%{condition_expr}" + } + } +} + +resource "google_iap_web_backend_service_iam_policy" "foo" { + project = "${google_compute_backend_service.default.project}" + web_backend_service = "${google_compute_backend_service.default.name}" + policy_data = "${data.google_iam_policy.foo.policy_data}" +} +`, context) +} diff --git a/google-beta/iam_iap_web_type_app_engine.go b/google-beta/iam_iap_web_type_app_engine.go index 648c819fd7..cba746b8cd 100644 --- a/google-beta/iam_iap_web_type_app_engine.go +++ b/google-beta/iam_iap_web_type_app_engine.go @@ -89,8 +89,6 @@ func IapWebTypeAppEngineIamUpdaterProducer(d *schema.ResourceData, config *Confi d.Set("project", u.project) d.Set("app_id", u.GetResourceId()) - d.SetId(u.GetResourceId()) - return u, nil } @@ -119,7 +117,7 @@ func IapWebTypeAppEngineIdParseFunc(d *schema.ResourceData, config *Config) erro Config: config, } d.Set("app_id", u.GetResourceId()) - d.SetId(u.GetResourceId()) + return nil } @@ -130,8 +128,9 @@ func (u *IapWebTypeAppEngineIamUpdater) GetResourceIamPolicy() (*cloudresourcema if err != nil { return nil, err } + var obj map[string]interface{} - policy, err := sendRequest(u.Config, "POST", project, url, nil) + policy, err := sendRequest(u.Config, "POST", project, url, obj) if err != nil { return nil, errwrap.Wrapf(fmt.Sprintf("Error retrieving IAM policy for %s: {{err}}", u.DescribeResource()), err) } diff --git a/google-beta/iam_iap_web_type_compute.go b/google-beta/iam_iap_web_type_compute.go index 4f67a9c5b5..ec093a3fd6 100644 --- a/google-beta/iam_iap_web_type_compute.go +++ b/google-beta/iam_iap_web_type_compute.go @@ -64,8 +64,6 @@ func IapWebTypeComputeIamUpdaterProducer(d *schema.ResourceData, config *Config) d.Set("project", u.project) - d.SetId(u.GetResourceId()) - return u, nil } @@ -93,7 +91,7 @@ func IapWebTypeComputeIdParseFunc(d *schema.ResourceData, config *Config) error Config: config, } d.Set("project", u.project) - d.SetId(u.GetResourceId()) + return nil } @@ -104,8 +102,9 @@ func (u *IapWebTypeComputeIamUpdater) GetResourceIamPolicy() (*cloudresourcemana if err != nil { return nil, err } + var obj map[string]interface{} - policy, err := sendRequest(u.Config, "POST", project, url, nil) + policy, err := sendRequest(u.Config, "POST", project, url, obj) if err != nil { return nil, errwrap.Wrapf(fmt.Sprintf("Error retrieving IAM policy for %s: {{err}}", u.DescribeResource()), err) } diff --git a/google-beta/iam_pubsub_topic.go b/google-beta/iam_pubsub_topic.go index 81a4328f76..54fe2bab29 100644 --- a/google-beta/iam_pubsub_topic.go +++ b/google-beta/iam_pubsub_topic.go @@ -75,8 +75,6 @@ func PubsubTopicIamUpdaterProducer(d *schema.ResourceData, config *Config) (Reso d.Set("project", u.project) d.Set("topic", u.GetResourceId()) - d.SetId(u.GetResourceId()) - return u, nil } @@ -105,7 +103,7 @@ func PubsubTopicIdParseFunc(d *schema.ResourceData, config *Config) error { Config: config, } d.Set("topic", u.GetResourceId()) - d.SetId(u.GetResourceId()) + return nil } @@ -116,8 +114,9 @@ func (u *PubsubTopicIamUpdater) GetResourceIamPolicy() (*cloudresourcemanager.Po if err != nil { return nil, err } + var obj map[string]interface{} - policy, err := sendRequest(u.Config, "GET", project, url, nil) + policy, err := sendRequest(u.Config, "GET", project, url, obj) if err != nil { return nil, errwrap.Wrapf(fmt.Sprintf("Error retrieving IAM policy for %s: {{err}}", u.DescribeResource()), err) } diff --git a/google-beta/iam_runtime_config_config.go b/google-beta/iam_runtime_config_config.go index ff39e683f5..6308cfed40 100644 --- a/google-beta/iam_runtime_config_config.go +++ b/google-beta/iam_runtime_config_config.go @@ -75,8 +75,6 @@ func RuntimeConfigConfigIamUpdaterProducer(d *schema.ResourceData, config *Confi d.Set("project", u.project) d.Set("config", u.GetResourceId()) - d.SetId(u.GetResourceId()) - return u, nil } @@ -105,7 +103,7 @@ func RuntimeConfigConfigIdParseFunc(d *schema.ResourceData, config *Config) erro Config: config, } d.Set("config", u.GetResourceId()) - d.SetId(u.GetResourceId()) + return nil } @@ -116,8 +114,9 @@ func (u *RuntimeConfigConfigIamUpdater) GetResourceIamPolicy() (*cloudresourcema if err != nil { return nil, err } + var obj map[string]interface{} - policy, err := sendRequest(u.Config, "GET", project, url, nil) + policy, err := sendRequest(u.Config, "GET", project, url, obj) if err != nil { return nil, errwrap.Wrapf(fmt.Sprintf("Error retrieving IAM policy for %s: {{err}}", u.DescribeResource()), err) } diff --git a/google-beta/iam_source_repo_repository.go b/google-beta/iam_source_repo_repository.go index d6d0dc4cfe..f51e99ccc9 100644 --- a/google-beta/iam_source_repo_repository.go +++ b/google-beta/iam_source_repo_repository.go @@ -75,8 +75,6 @@ func SourceRepoRepositoryIamUpdaterProducer(d *schema.ResourceData, config *Conf d.Set("project", u.project) d.Set("repository", u.GetResourceId()) - d.SetId(u.GetResourceId()) - return u, nil } @@ -105,7 +103,7 @@ func SourceRepoRepositoryIdParseFunc(d *schema.ResourceData, config *Config) err Config: config, } d.Set("repository", u.GetResourceId()) - d.SetId(u.GetResourceId()) + return nil } @@ -116,8 +114,9 @@ func (u *SourceRepoRepositoryIamUpdater) GetResourceIamPolicy() (*cloudresourcem if err != nil { return nil, err } + var obj map[string]interface{} - policy, err := sendRequest(u.Config, "GET", project, url, nil) + policy, err := sendRequest(u.Config, "GET", project, url, obj) if err != nil { return nil, errwrap.Wrapf(fmt.Sprintf("Error retrieving IAM policy for %s: {{err}}", u.DescribeResource()), err) } diff --git a/website/docs/r/iap_app_engine_version_iam.html.markdown b/website/docs/r/iap_app_engine_version_iam.html.markdown index 5c35fd96f8..a786fed772 100644 --- a/website/docs/r/iap_app_engine_version_iam.html.markdown +++ b/website/docs/r/iap_app_engine_version_iam.html.markdown @@ -54,6 +54,32 @@ resource "google_iap_app_engine_version_iam_policy" "editor" { } ``` +With IAM Conditions ([beta](https://terraform.io/docs/providers/google/provider_versions.html), Whitelist-only): + +```hcl +data "google_iam_policy" "admin" { + binding { + role = "roles/iap.httpsResourceAccessor" + members = [ + "user:jane@example.com", + ] + + condition { + title = "expires_after_2019_12_31" + description = "Expiring at midnight of 2019-12-31" + expression = "request.time < timestamp(\"2020-01-01T00:00:00Z\")" + } + } +} + +resource "google_iap_app_engine_version_iam_policy" "editor" { + project = "${google_app_engine_standard_app_version.version.project}" + app_id = "${google_app_engine_standard_app_version.version.project}" + service = "${google_app_engine_standard_app_version.version.service}" + version_id = "${google_app_engine_standard_app_version.version.version_id}" + policy_data = "${data.google_iam_policy.admin.policy_data}" +} +``` ## google\_iap\_app\_engine\_version\_iam\_binding ```hcl @@ -69,6 +95,26 @@ resource "google_iap_app_engine_version_iam_binding" "editor" { } ``` +With IAM Conditions ([beta](https://terraform.io/docs/providers/google/provider_versions.html), Whitelist-only): + +```hcl +resource "google_iap_app_engine_version_iam_binding" "editor" { + project = "${google_app_engine_standard_app_version.version.project}" + app_id = "${google_app_engine_standard_app_version.version.project}" + service = "${google_app_engine_standard_app_version.version.service}" + version_id = "${google_app_engine_standard_app_version.version.version_id}" + role = "roles/iap.httpsResourceAccessor" + members = [ + "user:jane@example.com", + ] + + condition { + title = "expires_after_2019_12_31" + description = "Expiring at midnight of 2019-12-31" + expression = "request.time < timestamp(\"2020-01-01T00:00:00Z\")" + } +} +``` ## google\_iap\_app\_engine\_version\_iam\_member ```hcl @@ -82,6 +128,24 @@ resource "google_iap_app_engine_version_iam_member" "editor" { } ``` +With IAM Conditions ([beta](https://terraform.io/docs/providers/google/provider_versions.html), Whitelist-only): + +```hcl +resource "google_iap_app_engine_version_iam_member" "editor" { + project = "${google_app_engine_standard_app_version.version.project}" + app_id = "${google_app_engine_standard_app_version.version.project}" + service = "${google_app_engine_standard_app_version.version.service}" + version_id = "${google_app_engine_standard_app_version.version.version_id}" + role = "roles/iap.httpsResourceAccessor" + member = "user:jane@example.com" + + condition { + title = "expires_after_2019_12_31" + description = "Expiring at midnight of 2019-12-31" + expression = "request.time < timestamp(\"2020-01-01T00:00:00Z\")" + } +} +``` ## Argument Reference The following arguments are supported: @@ -109,6 +173,22 @@ The following arguments are supported: * `policy_data` - (Required only by `google_iap_app_engine_version_iam_policy`) The policy data generated by a `google_iam_policy` data source. +* `condition` - (Optional, [Beta](https://terraform.io/docs/providers/google/provider_versions.html)) An [IAM Condition](https://cloud.google.com/iam/docs/conditions-overview) for a given binding. You must be whitelisted for the IAM Conditions private beta in order to use them in Terraform. + Structure is documented below. + +--- + +The `condition` block supports: + +* `expression` - (Required) Textual representation of an expression in Common Expression Language syntax. + +* `title` - (Required) A title for the expression, i.e. a short string describing its purpose. + +* `description` - (Optional) An optional description of the expression. This is a longer text which describes the expression, e.g. when hovered over it in a UI. + +~> **Warning:** Terraform considers the `role` and condition contents (`title`+`description`+`expression`) as the + identifier for the binding. This means that if any part of the condition is changed out-of-band, Terraform will + consider it to be an entirely different resource and will treat it as such. ## Attributes Reference In addition to the arguments listed above, the following computed attributes are diff --git a/website/docs/r/iap_web_backend_service_iam.html.markdown b/website/docs/r/iap_web_backend_service_iam.html.markdown index d2a16640ac..6067b31ad3 100644 --- a/website/docs/r/iap_web_backend_service_iam.html.markdown +++ b/website/docs/r/iap_web_backend_service_iam.html.markdown @@ -52,6 +52,30 @@ resource "google_iap_web_backend_service_iam_policy" "editor" { } ``` +With IAM Conditions ([beta](https://terraform.io/docs/providers/google/provider_versions.html), Whitelist-only): + +```hcl +data "google_iam_policy" "admin" { + binding { + role = "roles/iap.httpsResourceAccessor" + members = [ + "user:jane@example.com", + ] + + condition { + title = "expires_after_2019_12_31" + description = "Expiring at midnight of 2019-12-31" + expression = "request.time < timestamp(\"2020-01-01T00:00:00Z\")" + } + } +} + +resource "google_iap_web_backend_service_iam_policy" "editor" { + project = "${google_compute_backend_service.default.project}" + web_backend_service = "${google_compute_backend_service.default.name}" + policy_data = "${data.google_iam_policy.admin.policy_data}" +} +``` ## google\_iap\_web\_backend\_service\_iam\_binding ```hcl @@ -65,6 +89,24 @@ resource "google_iap_web_backend_service_iam_binding" "editor" { } ``` +With IAM Conditions ([beta](https://terraform.io/docs/providers/google/provider_versions.html), Whitelist-only): + +```hcl +resource "google_iap_web_backend_service_iam_binding" "editor" { + project = "${google_compute_backend_service.default.project}" + web_backend_service = "${google_compute_backend_service.default.name}" + role = "roles/iap.httpsResourceAccessor" + members = [ + "user:jane@example.com", + ] + + condition { + title = "expires_after_2019_12_31" + description = "Expiring at midnight of 2019-12-31" + expression = "request.time < timestamp(\"2020-01-01T00:00:00Z\")" + } +} +``` ## google\_iap\_web\_backend\_service\_iam\_member ```hcl @@ -76,6 +118,22 @@ resource "google_iap_web_backend_service_iam_member" "editor" { } ``` +With IAM Conditions ([beta](https://terraform.io/docs/providers/google/provider_versions.html), Whitelist-only): + +```hcl +resource "google_iap_web_backend_service_iam_member" "editor" { + project = "${google_compute_backend_service.default.project}" + web_backend_service = "${google_compute_backend_service.default.name}" + role = "roles/iap.httpsResourceAccessor" + member = "user:jane@example.com" + + condition { + title = "expires_after_2019_12_31" + description = "Expiring at midnight of 2019-12-31" + expression = "request.time < timestamp(\"2020-01-01T00:00:00Z\")" + } +} +``` ## Argument Reference The following arguments are supported: @@ -101,6 +159,22 @@ The following arguments are supported: * `policy_data` - (Required only by `google_iap_web_backend_service_iam_policy`) The policy data generated by a `google_iam_policy` data source. +* `condition` - (Optional, [Beta](https://terraform.io/docs/providers/google/provider_versions.html)) An [IAM Condition](https://cloud.google.com/iam/docs/conditions-overview) for a given binding. You must be whitelisted for the IAM Conditions private beta in order to use them in Terraform. + Structure is documented below. + +--- + +The `condition` block supports: + +* `expression` - (Required) Textual representation of an expression in Common Expression Language syntax. + +* `title` - (Required) A title for the expression, i.e. a short string describing its purpose. + +* `description` - (Optional) An optional description of the expression. This is a longer text which describes the expression, e.g. when hovered over it in a UI. + +~> **Warning:** Terraform considers the `role` and condition contents (`title`+`description`+`expression`) as the + identifier for the binding. This means that if any part of the condition is changed out-of-band, Terraform will + consider it to be an entirely different resource and will treat it as such. ## Attributes Reference In addition to the arguments listed above, the following computed attributes are