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

Add IAP support to compute_region_backend_service #3605

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions .changelog/5134.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
compute: added `iap` fields to `google_compute_region_backend_service`
```
148 changes: 148 additions & 0 deletions google-beta/resource_compute_region_backend_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,33 @@ or serverless NEG as a backend.`,
},
Set: selfLinkRelativePathHash,
},
"iap": {
Type: schema.TypeList,
Optional: true,
Description: `Settings for enabling Cloud Identity Aware Proxy`,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"oauth2_client_id": {
Type: schema.TypeString,
Required: true,
Description: `OAuth2 Client ID for IAP`,
},
"oauth2_client_secret": {
Type: schema.TypeString,
Required: true,
Description: `OAuth2 Client Secret for IAP`,
Sensitive: true,
},
"oauth2_client_secret_sha256": {
Type: schema.TypeString,
Computed: true,
Description: `OAuth2 Client Secret SHA-256 for IAP`,
Sensitive: true,
},
},
},
},
"load_balancing_scheme": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -1072,6 +1099,12 @@ func resourceComputeRegionBackendServiceCreate(d *schema.ResourceData, meta inte
} else if v, ok := d.GetOkExists("health_checks"); !isEmptyValue(reflect.ValueOf(healthChecksProp)) && (ok || !reflect.DeepEqual(v, healthChecksProp)) {
obj["healthChecks"] = healthChecksProp
}
iapProp, err := expandComputeRegionBackendServiceIap(d.Get("iap"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("iap"); ok || !reflect.DeepEqual(v, iapProp) {
obj["iap"] = iapProp
}
loadBalancingSchemeProp, err := expandComputeRegionBackendServiceLoadBalancingScheme(d.Get("load_balancing_scheme"), d, config)
if err != nil {
return err
Expand Down Expand Up @@ -1284,6 +1317,9 @@ func resourceComputeRegionBackendServiceRead(d *schema.ResourceData, meta interf
if err := d.Set("health_checks", flattenComputeRegionBackendServiceHealthChecks(res["healthChecks"], d, config)); err != nil {
return fmt.Errorf("Error reading RegionBackendService: %s", err)
}
if err := d.Set("iap", flattenComputeRegionBackendServiceIap(res["iap"], d, config)); err != nil {
return fmt.Errorf("Error reading RegionBackendService: %s", err)
}
if err := d.Set("load_balancing_scheme", flattenComputeRegionBackendServiceLoadBalancingScheme(res["loadBalancingScheme"], d, config)); err != nil {
return fmt.Errorf("Error reading RegionBackendService: %s", err)
}
Expand Down Expand Up @@ -1406,6 +1442,12 @@ func resourceComputeRegionBackendServiceUpdate(d *schema.ResourceData, meta inte
} else if v, ok := d.GetOkExists("health_checks"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, healthChecksProp)) {
obj["healthChecks"] = healthChecksProp
}
iapProp, err := expandComputeRegionBackendServiceIap(d.Get("iap"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("iap"); ok || !reflect.DeepEqual(v, iapProp) {
obj["iap"] = iapProp
}
loadBalancingSchemeProp, err := expandComputeRegionBackendServiceLoadBalancingScheme(d.Get("load_balancing_scheme"), d, config)
if err != nil {
return err
Expand Down Expand Up @@ -2297,6 +2339,35 @@ func flattenComputeRegionBackendServiceHealthChecks(v interface{}, d *schema.Res
return convertAndMapStringArr(v.([]interface{}), ConvertSelfLinkToV1)
}

func flattenComputeRegionBackendServiceIap(v interface{}, d *schema.ResourceData, config *Config) interface{} {
if v == nil {
return nil
}
original := v.(map[string]interface{})
if len(original) == 0 {
return nil
}
transformed := make(map[string]interface{})
transformed["oauth2_client_id"] =
flattenComputeRegionBackendServiceIapOauth2ClientId(original["oauth2ClientId"], d, config)
transformed["oauth2_client_secret"] =
flattenComputeRegionBackendServiceIapOauth2ClientSecret(original["oauth2ClientSecret"], d, config)
transformed["oauth2_client_secret_sha256"] =
flattenComputeRegionBackendServiceIapOauth2ClientSecretSha256(original["oauth2ClientSecretSha256"], d, config)
return []interface{}{transformed}
}
func flattenComputeRegionBackendServiceIapOauth2ClientId(v interface{}, d *schema.ResourceData, config *Config) interface{} {
return v
}

func flattenComputeRegionBackendServiceIapOauth2ClientSecret(v interface{}, d *schema.ResourceData, config *Config) interface{} {
return d.Get("iap.0.oauth2_client_secret")
}

func flattenComputeRegionBackendServiceIapOauth2ClientSecretSha256(v interface{}, d *schema.ResourceData, config *Config) interface{} {
return v
}

func flattenComputeRegionBackendServiceLoadBalancingScheme(v interface{}, d *schema.ResourceData, config *Config) interface{} {
return v
}
Expand Down Expand Up @@ -3322,6 +3393,51 @@ func expandComputeRegionBackendServiceHealthChecks(v interface{}, d TerraformRes
return v, nil
}

func expandComputeRegionBackendServiceIap(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
l := v.([]interface{})
if len(l) == 0 || l[0] == nil {
return nil, nil
}
raw := l[0]
original := raw.(map[string]interface{})
transformed := make(map[string]interface{})

transformedOauth2ClientId, err := expandComputeRegionBackendServiceIapOauth2ClientId(original["oauth2_client_id"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedOauth2ClientId); val.IsValid() && !isEmptyValue(val) {
transformed["oauth2ClientId"] = transformedOauth2ClientId
}

transformedOauth2ClientSecret, err := expandComputeRegionBackendServiceIapOauth2ClientSecret(original["oauth2_client_secret"], d, config)
if err != nil {
return nil, err
} else {
transformed["oauth2ClientSecret"] = transformedOauth2ClientSecret
}

transformedOauth2ClientSecretSha256, err := expandComputeRegionBackendServiceIapOauth2ClientSecretSha256(original["oauth2_client_secret_sha256"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedOauth2ClientSecretSha256); val.IsValid() && !isEmptyValue(val) {
transformed["oauth2ClientSecretSha256"] = transformedOauth2ClientSecretSha256
}

return transformed, nil
}

func expandComputeRegionBackendServiceIapOauth2ClientId(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
return v, nil
}

func expandComputeRegionBackendServiceIapOauth2ClientSecret(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
return v, nil
}

func expandComputeRegionBackendServiceIapOauth2ClientSecretSha256(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
return v, nil
}

func expandComputeRegionBackendServiceLoadBalancingScheme(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
return v, nil
}
Expand Down Expand Up @@ -3594,6 +3710,26 @@ func expandComputeRegionBackendServiceRegion(v interface{}, d TerraformResourceD
}

func resourceComputeRegionBackendServiceEncoder(d *schema.ResourceData, meta interface{}, obj map[string]interface{}) (map[string]interface{}, error) {
// The RegionBackendService API's Update / PUT API is badly formed and behaves like
// a PATCH field for at least IAP. When sent a `null` `iap` field, the API
// doesn't disable an existing field. To work around this, we need to emulate
// the old Terraform behaviour of always sending the block (at both update and
// create), and force sending each subfield as empty when the block isn't
// present in config.

iapVal := obj["iap"]
if iapVal == nil {
data := map[string]interface{}{}
data["enabled"] = false
data["oauth2ClientId"] = ""
data["oauth2ClientSecret"] = ""
obj["iap"] = data
} else {
iap := iapVal.(map[string]interface{})
iap["enabled"] = true
obj["iap"] = iap
}

if d.Get("load_balancing_scheme").(string) == "INTERNAL_MANAGED" {
return obj, nil
}
Expand Down Expand Up @@ -3632,6 +3768,18 @@ func resourceComputeRegionBackendServiceEncoder(d *schema.ResourceData, meta int
}

func resourceComputeRegionBackendServiceDecoder(d *schema.ResourceData, meta interface{}, res map[string]interface{}) (map[string]interface{}, error) {
// We need to pretend IAP isn't there if it's disabled for Terraform to maintain
// BC behaviour with the handwritten resource.
v, ok := res["iap"]
if !ok || v == nil {
delete(res, "iap")
return res, nil
}
m := v.(map[string]interface{})
if ok && m["enabled"] == false {
delete(res, "iap")
}

// Requests with consistentHash will error for specific values of
// localityLbPolicy. However, the API will not remove it if the backend
// service is updated to from supporting to non-supporting localityLbPolicy
Expand Down
70 changes: 70 additions & 0 deletions google-beta/resource_compute_region_backend_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,36 @@ func TestAccComputeRegionBackendService_ilbUpdateFull(t *testing.T) {
})
}

func TestAccComputeRegionBackendService_withBackendAndIAP(t *testing.T) {
backendName := fmt.Sprintf("foo-%s", randString(t, 10))
checkName := fmt.Sprintf("bar-%s", randString(t, 10))

vcrTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeRegionBackendServiceDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccComputeRegionBackendService_ilbBasicwithIAP(backendName, checkName),
},
{
ResourceName: "google_compute_region_backend_service.foobar",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"iap.0.oauth2_client_secret"},
},
{
Config: testAccComputeRegionBackendService_ilbBasic(backendName, checkName),
},
{
ResourceName: "google_compute_region_backend_service.foobar",
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func testAccComputeRegionBackendService_ilbBasic(serviceName, checkName string) string {
return fmt.Sprintf(`
resource "google_compute_region_backend_service" "foobar" {
Expand Down Expand Up @@ -953,3 +983,43 @@ resource "google_compute_health_check" "zero" {
}
`, serviceName, drainingTimeout, checkName)
}

func testAccComputeRegionBackendService_ilbBasicwithIAP(serviceName, checkName string) string {
return fmt.Sprintf(`
resource "google_compute_region_backend_service" "foobar" {
name = "%s"
health_checks = [google_compute_health_check.health_check.self_link]
port_name = "http"
protocol = "HTTP"
load_balancing_scheme = "INTERNAL_MANAGED"
locality_lb_policy = "RING_HASH"
circuit_breakers {
max_connections = 10
}
consistent_hash {
http_cookie {
ttl {
seconds = 11
nanos = 1234
}
name = "mycookie"
}
}
outlier_detection {
consecutive_errors = 2
}

iap {
oauth2_client_id = "test"
oauth2_client_secret = "test"
}
}

resource "google_compute_health_check" "health_check" {
name = "%s"
http_health_check {
port = 80
}
}
`, serviceName, checkName)
}
23 changes: 23 additions & 0 deletions website/docs/r/compute_region_backend_service.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ To get more information about RegionBackendService, see:
* How-to Guides
* [Internal TCP/UDP Load Balancing](https://cloud.google.com/compute/docs/load-balancing/internal/)

~> **Warning:** All arguments including `iap.oauth2_client_secret` and `iap.oauth2_client_secret_sha256` will be stored in the raw
state as plain-text. [Read more about sensitive data in state](/docs/state/sensitive-data.html).

<div class = "oics-button" style="float: right; margin: 0 0 -15px">
<a href="https://console.cloud.google.com/cloudshell/open?cloudshell_git_repo=https%3A%2F%2Fgit.luolix.top%2Fterraform-google-modules%2Fdocs-examples.git&cloudshell_working_dir=region_backend_service_basic&cloudshell_image=gcr.io%2Fgraphite-cloud-shell-images%2Fterraform%3Alatest&open_in_editor=main.tf&cloudshell_print=.%2Fmotd&cloudshell_tutorial=.%2Ftutorial.md" target="_blank">
<img alt="Open in Cloud Shell" src="//gstatic.com/cloudssh/images/open-btn.svg" style="max-height: 44px; margin: 32px auto; max-width: 100%;">
Expand Down Expand Up @@ -361,6 +364,11 @@ The following arguments are supported:
A health check must be specified unless the backend service uses an internet
or serverless NEG as a backend.

* `iap` -
(Optional)
Settings for enabling Cloud Identity Aware Proxy
Structure is documented below.

* `load_balancing_scheme` -
(Optional)
Indicates what kind of load balancing this regional backend service
Expand Down Expand Up @@ -793,6 +801,21 @@ The `failover_policy` block supports:
VMs with the best effort, or to all VMs when no VM is healthy.
This field is only used with l4 load balancing.

The `iap` block supports:

* `oauth2_client_id` -
(Required)
OAuth2 Client ID for IAP

* `oauth2_client_secret` -
(Required)
OAuth2 Client Secret for IAP
**Note**: This property is sensitive and will not be displayed in the plan.

* `oauth2_client_secret_sha256` -
OAuth2 Client Secret SHA-256 for IAP
**Note**: This property is sensitive and will not be displayed in the plan.

The `outlier_detection` block supports:

* `base_ejection_time` -
Expand Down