From 9f3a6b296e4a6b1237eedae39fa8f6e62a1c077a Mon Sep 17 00:00:00 2001 From: Roberto Jung Drebes Date: Tue, 6 Aug 2019 16:53:20 +0000 Subject: [PATCH] Binary Authorization: globalPolicyEvaluationMode Signed-off-by: Modular Magician --- .../resource_binary_authorization_policy.go | 29 +++ ...esource_binaryauthorization_policy_test.go | 245 +++++++++++++++++- .../binary_authorization_policy.html.markdown | 38 +++ 3 files changed, 310 insertions(+), 2 deletions(-) diff --git a/google/resource_binary_authorization_policy.go b/google/resource_binary_authorization_policy.go index 4f036384b7e..c38f0916cec 100644 --- a/google/resource_binary_authorization_policy.go +++ b/google/resource_binary_authorization_policy.go @@ -158,6 +158,12 @@ func resourceBinaryAuthorizationPolicy() *schema.Resource { Type: schema.TypeString, Optional: true, }, + "global_policy_evaluation_mode": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{"ENABLE", "DISABLE", ""}, false), + }, "project": { Type: schema.TypeString, Optional: true, @@ -178,6 +184,12 @@ func resourceBinaryAuthorizationPolicyCreate(d *schema.ResourceData, meta interf } else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(descriptionProp)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { obj["description"] = descriptionProp } + globalPolicyEvaluationModeProp, err := expandBinaryAuthorizationPolicyGlobalPolicyEvaluationMode(d.Get("global_policy_evaluation_mode"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("global_policy_evaluation_mode"); !isEmptyValue(reflect.ValueOf(globalPolicyEvaluationModeProp)) && (ok || !reflect.DeepEqual(v, globalPolicyEvaluationModeProp)) { + obj["globalPolicyEvaluationMode"] = globalPolicyEvaluationModeProp + } admissionWhitelistPatternsProp, err := expandBinaryAuthorizationPolicyAdmissionWhitelistPatterns(d.Get("admission_whitelist_patterns"), d, config) if err != nil { return err @@ -244,6 +256,9 @@ func resourceBinaryAuthorizationPolicyRead(d *schema.ResourceData, meta interfac if err := d.Set("description", flattenBinaryAuthorizationPolicyDescription(res["description"], d)); err != nil { return fmt.Errorf("Error reading Policy: %s", err) } + if err := d.Set("global_policy_evaluation_mode", flattenBinaryAuthorizationPolicyGlobalPolicyEvaluationMode(res["globalPolicyEvaluationMode"], d)); err != nil { + return fmt.Errorf("Error reading Policy: %s", err) + } if err := d.Set("admission_whitelist_patterns", flattenBinaryAuthorizationPolicyAdmissionWhitelistPatterns(res["admissionWhitelistPatterns"], d)); err != nil { return fmt.Errorf("Error reading Policy: %s", err) } @@ -267,6 +282,12 @@ func resourceBinaryAuthorizationPolicyUpdate(d *schema.ResourceData, meta interf } else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { obj["description"] = descriptionProp } + globalPolicyEvaluationModeProp, err := expandBinaryAuthorizationPolicyGlobalPolicyEvaluationMode(d.Get("global_policy_evaluation_mode"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("global_policy_evaluation_mode"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, globalPolicyEvaluationModeProp)) { + obj["globalPolicyEvaluationMode"] = globalPolicyEvaluationModeProp + } admissionWhitelistPatternsProp, err := expandBinaryAuthorizationPolicyAdmissionWhitelistPatterns(d.Get("admission_whitelist_patterns"), d, config) if err != nil { return err @@ -344,6 +365,10 @@ func flattenBinaryAuthorizationPolicyDescription(v interface{}, d *schema.Resour return v } +func flattenBinaryAuthorizationPolicyGlobalPolicyEvaluationMode(v interface{}, d *schema.ResourceData) interface{} { + return v +} + func flattenBinaryAuthorizationPolicyAdmissionWhitelistPatterns(v interface{}, d *schema.ResourceData) interface{} { if v == nil { return v @@ -434,6 +459,10 @@ func expandBinaryAuthorizationPolicyDescription(v interface{}, d TerraformResour return v, nil } +func expandBinaryAuthorizationPolicyGlobalPolicyEvaluationMode(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + func expandBinaryAuthorizationPolicyAdmissionWhitelistPatterns(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { l := v.([]interface{}) req := make([]interface{}, 0, len(l)) diff --git a/google/resource_binaryauthorization_policy_test.go b/google/resource_binaryauthorization_policy_test.go index 23524e1a667..eadf2eaa71e 100644 --- a/google/resource_binaryauthorization_policy_test.go +++ b/google/resource_binaryauthorization_policy_test.go @@ -38,8 +38,123 @@ func TestAccBinaryAuthorizationPolicy_basic(t *testing.T) { }) } -// Because Container Analysis is still in beta, we can't run any of the tests that call that -// resource without vendoring in the full beta provider. +func TestAccBinaryAuthorizationPolicy_full(t *testing.T) { + t.Parallel() + + org := getTestOrgFromEnv(t) + pid := "tf-test-" + acctest.RandString(10) + billingId := getTestBillingAccountFromEnv(t) + note := acctest.RandString(10) + attestor := acctest.RandString(10) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccBinaryAuthorizationPolicyFull(pid, pname, org, billingId, note, attestor, "DISABLE"), + }, + { + ResourceName: "google_binary_authorization_policy.policy", + ImportState: true, + ImportStateVerify: true, + }, + // Destroy the policy without destroying the project so we can check + // that it was restored to the default. + { + Config: testAccBinaryAuthorizationPolicyDefault(pid, pname, org, billingId), + Check: testAccCheckBinaryAuthorizationPolicyDefault(pid), + }, + }, + }) +} + +// Use an attestor created in the default CI project +func TestAccBinaryAuthorizationPolicy_separateProject(t *testing.T) { + t.Parallel() + + org := getTestOrgFromEnv(t) + pid := "tf-test-" + acctest.RandString(10) + billingId := getTestBillingAccountFromEnv(t) + note := acctest.RandString(10) + attestor := acctest.RandString(10) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccBinaryAuthorizationPolicy_separateProject(pid, pname, org, billingId, note, attestor), + }, + { + ResourceName: "google_binary_authorization_policy.policy", + ImportState: true, + ImportStateVerify: true, + }, + // Destroy the policy without destroying the project so we can check + // that it was restored to the default. + { + Config: testAccBinaryAuthorizationPolicyDefault(pid, pname, org, billingId), + Check: testAccCheckBinaryAuthorizationPolicyDefault(pid), + }, + }, + }) +} + +func TestAccBinaryAuthorizationPolicy_update(t *testing.T) { + t.Parallel() + + org := getTestOrgFromEnv(t) + pid := "tf-test-" + acctest.RandString(10) + billingId := getTestBillingAccountFromEnv(t) + note := acctest.RandString(10) + attestor := acctest.RandString(10) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccBinaryAuthorizationPolicyBasic(pid, pname, org, billingId), + }, + { + ResourceName: "google_binary_authorization_policy.policy", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccBinaryAuthorizationPolicyFull(pid, pname, org, billingId, note, attestor, "DISABLE"), + }, + { + ResourceName: "google_binary_authorization_policy.policy", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccBinaryAuthorizationPolicyFull(pid, pname, org, billingId, note, attestor, "ENABLE"), + }, + { + ResourceName: "google_binary_authorization_policy.policy", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccBinaryAuthorizationPolicyBasic(pid, pname, org, billingId), + }, + { + ResourceName: "google_binary_authorization_policy.policy", + ImportState: true, + ImportStateVerify: true, + }, + // Destroy the policy without destroying the project so we can check + // that it was restored to the default. + { + Config: testAccBinaryAuthorizationPolicyDefault(pid, pname, org, billingId), + Check: testAccCheckBinaryAuthorizationPolicyDefault(pid), + }, + }, + }) +} func testAccCheckBinaryAuthorizationPolicyDefault(pid string) resource.TestCheckFunc { return func(s *terraform.State) error { @@ -95,3 +210,129 @@ resource "google_binary_authorization_policy" "policy" { } `, pid, pname, org, billing) } + +func testAccBinaryAuthorizationPolicyFull(pid, pname, org, billing, note, attestor, gpmode string) string { + return fmt.Sprintf(` +// Use a separate project since each project can only have one policy +resource "google_project" "project" { + project_id = "%s" + name = "%s" + org_id = "%s" + billing_account = "%s" +} + +resource "google_project_service" "binauthz" { + project = "${google_project.project.project_id}" + service = "binaryauthorization.googleapis.com" +} + +resource "google_container_analysis_note" "note" { + project = "${google_project.project.project_id}" + + name = "tf-test-%s" + attestation_authority { + hint { + human_readable_name = "My attestor" + } + } + + depends_on = ["google_project_service.binauthz"] +} + +resource "google_binary_authorization_attestor" "attestor" { + project = "${google_project.project.project_id}" + + name = "tf-test-%s" + description = "my description" + attestation_authority_note { + note_reference = "${google_container_analysis_note.note.name}" + } + + depends_on = ["google_project_service.binauthz"] +} + +resource "google_binary_authorization_policy" "policy" { + project = "${google_project.project.project_id}" + + admission_whitelist_patterns { + name_pattern= "gcr.io/google_containers/*" + } + + default_admission_rule { + evaluation_mode = "ALWAYS_ALLOW" + enforcement_mode = "ENFORCED_BLOCK_AND_AUDIT_LOG" + } + + cluster_admission_rules { + cluster = "us-central1-a.prod-cluster" + evaluation_mode = "REQUIRE_ATTESTATION" + enforcement_mode = "ENFORCED_BLOCK_AND_AUDIT_LOG" + require_attestations_by = ["${google_binary_authorization_attestor.attestor.name}"] + } + + global_policy_evaluation mode = "%s" +} +`, pid, pname, org, billing, note, attestor, gpmode) +} + +func testAccBinaryAuthorizationPolicy_separateProject(pid, pname, org, billing, note, attestor string) string { + return fmt.Sprintf(` +// Use a separate project since each project can only have one policy +resource "google_project" "project" { + project_id = "%s" + name = "%s" + org_id = "%s" + billing_account = "%s" +} + +data "google_client_config" "current" {} + +resource "google_project_service" "binauthz" { + project = "${google_project.project.project_id}" + service = "binaryauthorization.googleapis.com" +} + +resource "google_container_analysis_note" "note" { + project = "${google_project.project.project_id}" + + name = "tf-test-%s" + attestation_authority { + hint { + human_readable_name = "My attestor" + } + } + + depends_on = ["google_project_service.binauthz"] +} + +resource "google_binary_authorization_attestor" "attestor" { + name = "tf-test-%s" + description = "my description" + attestation_authority_note { + note_reference = "${google_container_analysis_note.note.name}" + } + + depends_on = ["google_project_service.binauthz"] +} + +resource "google_binary_authorization_policy" "policy" { + project = "${google_project.project.project_id}" + + admission_whitelist_patterns { + name_pattern= "gcr.io/google_containers/*" + } + + default_admission_rule { + evaluation_mode = "ALWAYS_ALLOW" + enforcement_mode = "ENFORCED_BLOCK_AND_AUDIT_LOG" + } + + cluster_admission_rules { + cluster = "us-central1-a.prod-cluster" + evaluation_mode = "REQUIRE_ATTESTATION" + enforcement_mode = "ENFORCED_BLOCK_AND_AUDIT_LOG" + require_attestations_by = ["projects/${data.google_client_config.current.project}/attestors/${google_binary_authorization_attestor.attestor.name}"] + } +} +`, pid, pname, org, billing, note, attestor) +} diff --git a/website/docs/r/binary_authorization_policy.html.markdown b/website/docs/r/binary_authorization_policy.html.markdown index 897216ce197..c265861a047 100644 --- a/website/docs/r/binary_authorization_policy.html.markdown +++ b/website/docs/r/binary_authorization_policy.html.markdown @@ -61,6 +61,38 @@ resource "google_container_analysis_note" "note" { } } +resource "google_binary_authorization_attestor" "attestor" { + name = "test-attestor" + attestation_authority_note { + note_reference = "${google_container_analysis_note.note.name}" + } +} +``` +## Example Usage - Binary Authorization Policy Global Evaluation + + +```hcl +resource "google_binary_authorization_policy" "policy" { + + default_admission_rule { + evaluation_mode = "REQUIRE_ATTESTATION" + enforcement_mode = "ENFORCED_BLOCK_AND_AUDIT_LOG" + require_attestations_by = ["${google_binary_authorization_attestor.attestor.name}"] + } + + global_policy_evaluation_mode = "ENABLE" + +} + +resource "google_container_analysis_note" "note" { + name = "test-attestor-note" + attestation_authority { + hint { + human_readable_name = "My attestor" + } + } +} + resource "google_binary_authorization_attestor" "attestor" { name = "test-attestor" attestation_authority_note { @@ -108,6 +140,12 @@ The `default_admission_rule` block supports: (Optional) A descriptive comment. +* `global_policy_evaluation_mode` - + (Optional) + Controls the evaluation of a Google-maintained global admission policy + for common system-level images. Images not covered by the global + policy will be subject to the project admission policy. + * `admission_whitelist_patterns` - (Optional) A whitelist of image patterns to exclude from admission rules. If an