Skip to content

Commit

Permalink
add support for Cloud Armor Edge Policies (#5794) (#4154)
Browse files Browse the repository at this point in the history
Signed-off-by: Modular Magician <magic-modules@google.com>
  • Loading branch information
modular-magician authored Mar 24, 2022
1 parent 75e1741 commit caccf10
Show file tree
Hide file tree
Showing 8 changed files with 246 additions and 6 deletions.
6 changes: 6 additions & 0 deletions .changelog/5794.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
```release-note:enhancement
compute: added support for field `type` to `google_compute_security_policy`
```
```release-note:enhancement
compute: added support for attaching a `edge_security_policy` to `google_compute_backend_bucket`
```
69 changes: 69 additions & 0 deletions google-beta/resource_compute_backend_bucket.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"reflect"
"time"

"github.com/hashicorp/errwrap"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

Expand Down Expand Up @@ -157,6 +158,12 @@ header. The actual headers served in responses will not be altered.`,
Description: `An optional textual description of the resource; provided by the
client when the resource is created.`,
},
"edge_security_policy": {
Type: schema.TypeString,
Optional: true,
DiffSuppressFunc: compareSelfLinkOrResourceName,
Description: `The security policy associated with this backend bucket.`,
},
"enable_cdn": {
Type: schema.TypeBool,
Optional: true,
Expand Down Expand Up @@ -202,6 +209,12 @@ func resourceComputeBackendBucketCreate(d *schema.ResourceData, meta interface{}
} else if v, ok := d.GetOkExists("cdn_policy"); !isEmptyValue(reflect.ValueOf(cdnPolicyProp)) && (ok || !reflect.DeepEqual(v, cdnPolicyProp)) {
obj["cdnPolicy"] = cdnPolicyProp
}
edgeSecurityPolicyProp, err := expandComputeBackendBucketEdgeSecurityPolicy(d.Get("edge_security_policy"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("edge_security_policy"); !isEmptyValue(reflect.ValueOf(edgeSecurityPolicyProp)) && (ok || !reflect.DeepEqual(v, edgeSecurityPolicyProp)) {
obj["edgeSecurityPolicy"] = edgeSecurityPolicyProp
}
customResponseHeadersProp, err := expandComputeBackendBucketCustomResponseHeaders(d.Get("custom_response_headers"), d, config)
if err != nil {
return err
Expand Down Expand Up @@ -268,6 +281,26 @@ func resourceComputeBackendBucketCreate(d *schema.ResourceData, meta interface{}
return fmt.Errorf("Error waiting to create BackendBucket: %s", err)
}

// security_policy isn't set by Create / Update
if o, n := d.GetChange("edge_security_policy"); o.(string) != n.(string) {
pol, err := ParseSecurityPolicyFieldValue(n.(string), d, config)
if err != nil {
return errwrap.Wrapf("Error parsing Backend Service security policy: {{err}}", err)
}

spr := emptySecurityPolicyReference()
spr.SecurityPolicy = pol.RelativeLink()
op, err := config.NewComputeClient(userAgent).BackendBuckets.SetEdgeSecurityPolicy(project, obj["name"].(string), spr).Do()
if err != nil {
return errwrap.Wrapf("Error setting Backend Service security policy: {{err}}", err)
}
// This uses the create timeout for simplicity, though technically this code appears in both create and update
waitErr := computeOperationWaitTime(config, op, project, "Setting Backend Service Security Policy", userAgent, d.Timeout(schema.TimeoutCreate))
if waitErr != nil {
return waitErr
}
}

log.Printf("[DEBUG] Finished creating BackendBucket %q: %#v", d.Id(), res)

return resourceComputeBackendBucketRead(d, meta)
Expand Down Expand Up @@ -313,6 +346,9 @@ func resourceComputeBackendBucketRead(d *schema.ResourceData, meta interface{})
if err := d.Set("cdn_policy", flattenComputeBackendBucketCdnPolicy(res["cdnPolicy"], d, config)); err != nil {
return fmt.Errorf("Error reading BackendBucket: %s", err)
}
if err := d.Set("edge_security_policy", flattenComputeBackendBucketEdgeSecurityPolicy(res["edgeSecurityPolicy"], d, config)); err != nil {
return fmt.Errorf("Error reading BackendBucket: %s", err)
}
if err := d.Set("custom_response_headers", flattenComputeBackendBucketCustomResponseHeaders(res["customResponseHeaders"], d, config)); err != nil {
return fmt.Errorf("Error reading BackendBucket: %s", err)
}
Expand Down Expand Up @@ -363,6 +399,12 @@ func resourceComputeBackendBucketUpdate(d *schema.ResourceData, meta interface{}
} else if v, ok := d.GetOkExists("cdn_policy"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, cdnPolicyProp)) {
obj["cdnPolicy"] = cdnPolicyProp
}
edgeSecurityPolicyProp, err := expandComputeBackendBucketEdgeSecurityPolicy(d.Get("edge_security_policy"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("edge_security_policy"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, edgeSecurityPolicyProp)) {
obj["edgeSecurityPolicy"] = edgeSecurityPolicyProp
}
customResponseHeadersProp, err := expandComputeBackendBucketCustomResponseHeaders(d.Get("custom_response_headers"), d, config)
if err != nil {
return err
Expand Down Expand Up @@ -416,6 +458,25 @@ func resourceComputeBackendBucketUpdate(d *schema.ResourceData, meta interface{}
return err
}

// security_policy isn't set by Create / Update
if o, n := d.GetChange("edge_security_policy"); o.(string) != n.(string) {
pol, err := ParseSecurityPolicyFieldValue(n.(string), d, config)
if err != nil {
return errwrap.Wrapf("Error parsing Backend Service security policy: {{err}}", err)
}

spr := emptySecurityPolicyReference()
spr.SecurityPolicy = pol.RelativeLink()
op, err := config.NewComputeClient(userAgent).BackendBuckets.SetEdgeSecurityPolicy(project, obj["name"].(string), spr).Do()
if err != nil {
return errwrap.Wrapf("Error setting Backend Service security policy: {{err}}", err)
}
// This uses the create timeout for simplicity, though technically this code appears in both create and update
waitErr := computeOperationWaitTime(config, op, project, "Setting Backend Service Security Policy", userAgent, d.Timeout(schema.TimeoutCreate))
if waitErr != nil {
return waitErr
}
}
return resourceComputeBackendBucketRead(d, meta)
}

Expand Down Expand Up @@ -661,6 +722,10 @@ func flattenComputeBackendBucketCdnPolicyServeWhileStale(v interface{}, d *schem
return v // let terraform core handle it otherwise
}

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

func flattenComputeBackendBucketCustomResponseHeaders(v interface{}, d *schema.ResourceData, config *Config) interface{} {
return v
}
Expand Down Expand Up @@ -818,6 +883,10 @@ func expandComputeBackendBucketCdnPolicyServeWhileStale(v interface{}, d Terrafo
return v, nil
}

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

func expandComputeBackendBucketCustomResponseHeaders(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
return v, nil
}
Expand Down
47 changes: 47 additions & 0 deletions google-beta/resource_compute_backend_bucket_generated_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,53 @@ resource "google_storage_bucket" "image_backend_full" {
`, context)
}

func TestAccComputeBackendBucket_backendBucketSecurityPolicyExample(t *testing.T) {
t.Parallel()

context := map[string]interface{}{
"random_suffix": randString(t, 10),
}

vcrTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeBackendBucketDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccComputeBackendBucket_backendBucketSecurityPolicyExample(context),
},
{
ResourceName: "google_compute_backend_bucket.image_backend",
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func testAccComputeBackendBucket_backendBucketSecurityPolicyExample(context map[string]interface{}) string {
return Nprintf(`
resource "google_compute_backend_bucket" "image_backend" {
name = "tf-test-image-backend-bucket%{random_suffix}"
description = "Contains beautiful images"
bucket_name = google_storage_bucket.image_backend.name
enable_cdn = true
edge_security_policy = google_compute_security_policy.policy.id
}
resource "google_storage_bucket" "image_backend" {
name = "tf-test-image-store-bucket%{random_suffix}"
location = "EU"
}
resource "google_compute_security_policy" "policy" {
name = "tf-test-image-store-bucket%{random_suffix}"
description = "basic security policy"
type = "CLOUD_ARMOR_EDGE"
}
`, context)
}

func testAccCheckComputeBackendBucketDestroyProducer(t *testing.T) func(s *terraform.State) error {
return func(s *terraform.State) error {
for name, rs := range s.RootModule().Resources {
Expand Down
55 changes: 55 additions & 0 deletions google-beta/resource_compute_backend_bucket_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,37 @@ func TestAccComputeBackendBucket_withCdnPolicy(t *testing.T) {
})
}

func TestAccComputeBackendBucket_withSecurityPolicy(t *testing.T) {
t.Parallel()

bucketName := fmt.Sprintf("tf-test-%s", randString(t, 10))
polName := fmt.Sprintf("tf-test-%s", randString(t, 10))

vcrTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeBackendServiceDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccComputeBackendBucket_withSecurityPolicy(bucketName, polName, "google_compute_security_policy.policy.self_link"),
},
{
ResourceName: "google_compute_backend_bucket.image_backend",
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccComputeBackendBucket_withSecurityPolicy(bucketName, polName, "\"\""),
},
{
ResourceName: "google_compute_backend_bucket.image_backend",
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func testAccComputeBackendBucket_basic(backendName, storageName string) string {
return fmt.Sprintf(`
resource "google_compute_backend_bucket" "foobar" {
Expand Down Expand Up @@ -201,3 +232,27 @@ resource "google_storage_bucket" "bucket" {
}
`, backendName, age, max_ttl, ttl, ttl, ttl, code, ttl, storageName)
}

func testAccComputeBackendBucket_withSecurityPolicy(bucketName, polName, polLink string) string {
return fmt.Sprintf(`
resource "google_compute_backend_bucket" "image_backend" {
name = "%s"
description = "Contains beautiful images"
bucket_name = google_storage_bucket.image_bucket.name
enable_cdn = true
edge_security_policy = %s
}
resource "google_storage_bucket" "image_bucket" {
name = "%s"
location = "EU"
}
resource "google_compute_security_policy" "policy" {
name = "%s"
description = "basic security policy"
type = "CLOUD_ARMOR_EDGE"
}
`, bucketName, polLink, bucketName, polName)
}
33 changes: 28 additions & 5 deletions google-beta/resource_compute_security_policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ func resourceComputeSecurityPolicy() *schema.Resource {
Description: `The project in which the resource belongs. If it is not provided, the provider project is used.`,
},

"type": {
Type: schema.TypeString,
Optional: true,
Computed: true,
Description: `The type indicates the intended use of the security policy. CLOUD_ARMOR - Cloud Armor backend security policies can be configured to filter incoming HTTP requests targeting backend services. They filter requests before they hit the origin servers. CLOUD_ARMOR_EDGE - Cloud Armor edge security policies can be configured to filter incoming HTTP requests targeting backend services (including Cloud CDN-enabled) as well as backend buckets (Cloud Storage). They filter requests before the request is served from Google's cache.`,
},

"rule": {
Type: schema.TypeSet,
Optional: true,
Expand Down Expand Up @@ -346,6 +353,11 @@ func resourceComputeSecurityPolicyCreate(d *schema.ResourceData, meta interface{
Name: sp,
Description: d.Get("description").(string),
}

if v, ok := d.GetOk("type"); ok {
securityPolicy.Type = v.(string)
}

if v, ok := d.GetOk("rule"); ok {
securityPolicy.Rules = expandSecurityPolicyRules(v.(*schema.Set).List())
}
Expand Down Expand Up @@ -405,6 +417,9 @@ func resourceComputeSecurityPolicyRead(d *schema.ResourceData, meta interface{})
if err := d.Set("description", securityPolicy.Description); err != nil {
return fmt.Errorf("Error setting description: %s", err)
}
if err := d.Set("type", securityPolicy.Type); err != nil {
return fmt.Errorf("Error setting type: %s", err)
}
if err := d.Set("rule", flattenSecurityPolicyRules(securityPolicy.Rules)); err != nil {
return err
}
Expand Down Expand Up @@ -438,13 +453,21 @@ func resourceComputeSecurityPolicyUpdate(d *schema.ResourceData, meta interface{

sp := d.Get("name").(string)

securityPolicy := &compute.SecurityPolicy{
Fingerprint: d.Get("fingerprint").(string),
}

if d.HasChange("type") {
securityPolicy.Type = d.Get("type").(string)
securityPolicy.ForceSendFields = append(securityPolicy.ForceSendFields, "Type")
}

if d.HasChange("description") {
securityPolicy := &compute.SecurityPolicy{
Description: d.Get("description").(string),
Fingerprint: d.Get("fingerprint").(string),
ForceSendFields: []string{"Description"},
}
securityPolicy.Description = d.Get("description").(string)
securityPolicy.ForceSendFields = append(securityPolicy.ForceSendFields, "Description")
}

if len(securityPolicy.ForceSendFields) > 0 {
client := config.NewComputeClient(userAgent)

op, err := client.SecurityPolicies.Patch(project, sp, securityPolicy).Do()
Expand Down
3 changes: 2 additions & 1 deletion google-beta/resource_compute_security_policy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ func testAccComputeSecurityPolicy_basic(spName string) string {
resource "google_compute_security_policy" "policy" {
name = "%s"
description = "basic security policy"
type = "CLOUD_ARMOR_EDGE"
}
`, spName)
}
Expand Down Expand Up @@ -390,7 +391,7 @@ resource "google_compute_security_policy" "policy" {
rule {
action = "throttle"
priority = 100
priority = 100
match {
versioned_expr = "SRC_IPS_V1"
config {
Expand Down
32 changes: 32 additions & 0 deletions website/docs/r/compute_backend_bucket.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,34 @@ resource "google_storage_bucket" "image_bucket" {
location = "EU"
}
```
<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=backend_bucket_security_policy&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%;">
</a>
</div>
## Example Usage - Backend Bucket Security Policy


```hcl
resource "google_compute_backend_bucket" "image_backend" {
name = "image-backend-bucket"
description = "Contains beautiful images"
bucket_name = google_storage_bucket.image_backend.name
enable_cdn = true
edge_security_policy = google_compute_security_policy.policy.id
}
resource "google_storage_bucket" "image_backend" {
name = "image-store-bucket"
location = "EU"
}
resource "google_compute_security_policy" "policy" {
name = "image-store-bucket"
description = "basic security policy"
type = "CLOUD_ARMOR_EDGE"
}
```

## Argument Reference

Expand Down Expand Up @@ -88,6 +116,10 @@ The following arguments are supported:
Cloud CDN configuration for this Backend Bucket.
Structure is [documented below](#nested_cdn_policy).

* `edge_security_policy` -
(Optional)
The security policy associated with this backend bucket.

* `custom_response_headers` -
(Optional)
Headers that the HTTP/S load balancer should add to proxied responses.
Expand Down
7 changes: 7 additions & 0 deletions website/docs/r/compute_security_policy.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,13 @@ The following arguments are supported:

* `adaptive_protection_config` - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) Configuration for [Google Cloud Armor Adaptive Protection](https://cloud.google.com/armor/docs/adaptive-protection-overview?hl=en). Structure is [documented below](#nested_adaptive_protection_config).

* `type` - The type indicates the intended use of the security policy.
* CLOUD_ARMOR - Cloud Armor backend security policies can be configured to filter incoming HTTP requests targeting backend services.
They filter requests before they hit the origin servers.
* CLOUD_ARMOR_EDGE - Cloud Armor edge security policies can be configured to filter incoming HTTP requests targeting backend services
(including Cloud CDN-enabled) as well as backend buckets (Cloud Storage).
They filter requests before the request is served from Google's cache.

<a name="nested_rule"></a>The `rule` block supports:

* `action` - (Required) Action to take when `match` matches the request. Valid values:
Expand Down

0 comments on commit caccf10

Please sign in to comment.