diff --git a/google/config.go b/google/config.go index 0b215f253f6..5005af1b50a 100644 --- a/google/config.go +++ b/google/config.go @@ -69,6 +69,7 @@ type Config struct { tokenSource oauth2.TokenSource AccessContextManagerBasePath string + BinaryAuthorizationBasePath string CloudSchedulerBasePath string FirestoreBasePath string MonitoringBasePath string diff --git a/google/provider.go b/google/provider.go index b499328725b..71a5d403e85 100644 --- a/google/provider.go +++ b/google/provider.go @@ -100,6 +100,7 @@ func Provider() terraform.ResourceProvider { // Generated Products AccessContextManagerCustomEndpointEntryKey: AccessContextManagerCustomEndpointEntry, AppEngineCustomEndpointEntryKey: AppEngineCustomEndpointEntry, + BinaryAuthorizationCustomEndpointEntryKey: BinaryAuthorizationCustomEndpointEntry, ComputeCustomEndpointEntryKey: ComputeCustomEndpointEntry, CloudBuildCustomEndpointEntryKey: CloudBuildCustomEndpointEntry, CloudSchedulerCustomEndpointEntryKey: CloudSchedulerCustomEndpointEntry, @@ -210,6 +211,7 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) { return mergeResourceMaps( GeneratedAccessContextManagerResourcesMap, GeneratedAppEngineResourcesMap, + GeneratedBinaryAuthorizationResourcesMap, GeneratedComputeResourcesMap, GeneratedCloudBuildResourcesMap, GeneratedCloudSchedulerResourcesMap, @@ -382,6 +384,7 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) { config.FirestoreBasePath = d.Get(FirestoreCustomEndpointEntryKey).(string) config.AppEngineBasePath = d.Get(AppEngineCustomEndpointEntryKey).(string) + config.BinaryAuthorizationBasePath = d.Get(BinaryAuthorizationCustomEndpointEntryKey).(string) config.ComputeBasePath = d.Get(ComputeCustomEndpointEntryKey).(string) config.CloudBuildBasePath = d.Get(CloudBuildCustomEndpointEntryKey).(string) config.DnsBasePath = d.Get(DnsCustomEndpointEntryKey).(string) @@ -434,6 +437,7 @@ func ConfigureBasePaths(c *Config) { // Generated Products c.AccessContextManagerBasePath = AccessContextManagerDefaultBasePath c.AppEngineBasePath = AppEngineDefaultBasePath + c.BinaryAuthorizationBasePath = BinaryAuthorizationDefaultBasePath c.ComputeBasePath = ComputeDefaultBasePath c.CloudBuildBasePath = CloudBuildDefaultBasePath c.CloudSchedulerBasePath = CloudSchedulerDefaultBasePath diff --git a/google/provider_binary_authorization_gen.go b/google/provider_binary_authorization_gen.go new file mode 100644 index 00000000000..6485ff29d81 --- /dev/null +++ b/google/provider_binary_authorization_gen.go @@ -0,0 +1,35 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package google + +import "github.com/hashicorp/terraform/helper/schema" + +// If the base path has changed as a result of your PR, make sure to update +// the provider_reference page! +var BinaryAuthorizationDefaultBasePath = "https://binaryauthorization.googleapis.com/v1/" +var BinaryAuthorizationCustomEndpointEntryKey = "binary_authorization_custom_endpoint" +var BinaryAuthorizationCustomEndpointEntry = &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateCustomEndpoint, + DefaultFunc: schema.MultiEnvDefaultFunc([]string{ + "GOOGLE_BINARY_AUTHORIZATION_CUSTOM_ENDPOINT", + }, BinaryAuthorizationDefaultBasePath), +} + +var GeneratedBinaryAuthorizationResourcesMap = map[string]*schema.Resource{ + "google_binary_authorization_attestor": resourceBinaryAuthorizationAttestor(), + "google_binary_authorization_policy": resourceBinaryAuthorizationPolicy(), +} diff --git a/google/resource_binary_authorization_attestor.go b/google/resource_binary_authorization_attestor.go new file mode 100644 index 00000000000..cccb8e9b67f --- /dev/null +++ b/google/resource_binary_authorization_attestor.go @@ -0,0 +1,463 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package google + +import ( + "fmt" + "log" + "reflect" + "regexp" + "time" + + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceBinaryAuthorizationAttestor() *schema.Resource { + return &schema.Resource{ + Create: resourceBinaryAuthorizationAttestorCreate, + Read: resourceBinaryAuthorizationAttestorRead, + Update: resourceBinaryAuthorizationAttestorUpdate, + Delete: resourceBinaryAuthorizationAttestorDelete, + + Importer: &schema.ResourceImporter{ + State: resourceBinaryAuthorizationAttestorImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(4 * time.Minute), + Update: schema.DefaultTimeout(4 * time.Minute), + Delete: schema.DefaultTimeout(4 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "attestation_authority_note": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "note_reference": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + }, + "public_keys": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ascii_armored_pgp_public_key": { + Type: schema.TypeString, + Required: true, + }, + "comment": { + Type: schema.TypeString, + Optional: true, + }, + "id": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "delegation_service_account_email": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "description": { + Type: schema.TypeString, + Optional: true, + }, + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + }, + } +} + +func resourceBinaryAuthorizationAttestorCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + obj := make(map[string]interface{}) + nameProp, err := expandBinaryAuthorizationAttestorName(d.Get("name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("name"); !isEmptyValue(reflect.ValueOf(nameProp)) && (ok || !reflect.DeepEqual(v, nameProp)) { + obj["name"] = nameProp + } + descriptionProp, err := expandBinaryAuthorizationAttestorDescription(d.Get("description"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(descriptionProp)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { + obj["description"] = descriptionProp + } + userOwnedDrydockNoteProp, err := expandBinaryAuthorizationAttestorAttestationAuthorityNote(d.Get("attestation_authority_note"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("attestation_authority_note"); !isEmptyValue(reflect.ValueOf(userOwnedDrydockNoteProp)) && (ok || !reflect.DeepEqual(v, userOwnedDrydockNoteProp)) { + obj["userOwnedDrydockNote"] = userOwnedDrydockNoteProp + } + + obj, err = resourceBinaryAuthorizationAttestorEncoder(d, meta, obj) + if err != nil { + return err + } + + url, err := replaceVars(d, config, "{{BinaryAuthorizationBasePath}}projects/{{project}}/attestors?attestorId={{name}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new Attestor: %#v", obj) + res, err := sendRequestWithTimeout(config, "POST", url, obj, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return fmt.Errorf("Error creating Attestor: %s", err) + } + + // Store the ID now + id, err := replaceVars(d, config, "{{name}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + log.Printf("[DEBUG] Finished creating Attestor %q: %#v", d.Id(), res) + + return resourceBinaryAuthorizationAttestorRead(d, meta) +} + +func resourceBinaryAuthorizationAttestorRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + url, err := replaceVars(d, config, "{{BinaryAuthorizationBasePath}}projects/{{project}}/attestors/{{name}}") + if err != nil { + return err + } + + res, err := sendRequest(config, "GET", url, nil) + if err != nil { + return handleNotFoundError(err, d, fmt.Sprintf("BinaryAuthorizationAttestor %q", d.Id())) + } + + res, err = resourceBinaryAuthorizationAttestorDecoder(d, meta, res) + if err != nil { + return err + } + + project, err := getProject(d, config) + if err != nil { + return err + } + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading Attestor: %s", err) + } + + if err := d.Set("name", flattenBinaryAuthorizationAttestorName(res["name"], d)); err != nil { + return fmt.Errorf("Error reading Attestor: %s", err) + } + if err := d.Set("description", flattenBinaryAuthorizationAttestorDescription(res["description"], d)); err != nil { + return fmt.Errorf("Error reading Attestor: %s", err) + } + if err := d.Set("attestation_authority_note", flattenBinaryAuthorizationAttestorAttestationAuthorityNote(res["userOwnedDrydockNote"], d)); err != nil { + return fmt.Errorf("Error reading Attestor: %s", err) + } + + return nil +} + +func resourceBinaryAuthorizationAttestorUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + obj := make(map[string]interface{}) + nameProp, err := expandBinaryAuthorizationAttestorName(d.Get("name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("name"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, nameProp)) { + obj["name"] = nameProp + } + descriptionProp, err := expandBinaryAuthorizationAttestorDescription(d.Get("description"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { + obj["description"] = descriptionProp + } + userOwnedDrydockNoteProp, err := expandBinaryAuthorizationAttestorAttestationAuthorityNote(d.Get("attestation_authority_note"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("attestation_authority_note"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, userOwnedDrydockNoteProp)) { + obj["userOwnedDrydockNote"] = userOwnedDrydockNoteProp + } + + obj, err = resourceBinaryAuthorizationAttestorEncoder(d, meta, obj) + if err != nil { + return err + } + + url, err := replaceVars(d, config, "{{BinaryAuthorizationBasePath}}projects/{{project}}/attestors/{{name}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Updating Attestor %q: %#v", d.Id(), obj) + _, err = sendRequestWithTimeout(config, "PUT", url, obj, d.Timeout(schema.TimeoutUpdate)) + + if err != nil { + return fmt.Errorf("Error updating Attestor %q: %s", d.Id(), err) + } + + return resourceBinaryAuthorizationAttestorRead(d, meta) +} + +func resourceBinaryAuthorizationAttestorDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + url, err := replaceVars(d, config, "{{BinaryAuthorizationBasePath}}projects/{{project}}/attestors/{{name}}") + if err != nil { + return err + } + + var obj map[string]interface{} + log.Printf("[DEBUG] Deleting Attestor %q", d.Id()) + res, err := sendRequestWithTimeout(config, "DELETE", url, obj, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return handleNotFoundError(err, d, "Attestor") + } + + log.Printf("[DEBUG] Finished deleting Attestor %q: %#v", d.Id(), res) + return nil +} + +func resourceBinaryAuthorizationAttestorImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*Config) + if err := parseImportId([]string{ + "projects/(?P[^/]+)/attestors/(?P[^/]+)", + "(?P[^/]+)/(?P[^/]+)", + "(?P[^/]+)", + }, d, config); err != nil { + return nil, err + } + + // Replace import id for the resource id + id, err := replaceVars(d, config, "{{name}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenBinaryAuthorizationAttestorName(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return v + } + return NameFromSelfLinkStateFunc(v) +} + +func flattenBinaryAuthorizationAttestorDescription(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenBinaryAuthorizationAttestorAttestationAuthorityNote(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["note_reference"] = + flattenBinaryAuthorizationAttestorAttestationAuthorityNoteNoteReference(original["noteReference"], d) + transformed["public_keys"] = + flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeys(original["publicKeys"], d) + transformed["delegation_service_account_email"] = + flattenBinaryAuthorizationAttestorAttestationAuthorityNoteDelegationServiceAccountEmail(original["delegationServiceAccountEmail"], d) + return []interface{}{transformed} +} +func flattenBinaryAuthorizationAttestorAttestationAuthorityNoteNoteReference(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeys(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return v + } + l := v.([]interface{}) + transformed := make([]interface{}, 0, len(l)) + for _, raw := range l { + original := raw.(map[string]interface{}) + if len(original) < 1 { + // Do not include empty json objects coming back from the api + continue + } + transformed = append(transformed, map[string]interface{}{ + "comment": flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysComment(original["comment"], d), + "id": flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysId(original["id"], d), + "ascii_armored_pgp_public_key": flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysAsciiArmoredPgpPublicKey(original["asciiArmoredPgpPublicKey"], d), + }) + } + return transformed +} +func flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysComment(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysId(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysAsciiArmoredPgpPublicKey(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenBinaryAuthorizationAttestorAttestationAuthorityNoteDelegationServiceAccountEmail(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func expandBinaryAuthorizationAttestorName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandBinaryAuthorizationAttestorDescription(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandBinaryAuthorizationAttestorAttestationAuthorityNote(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{}) + + transformedNoteReference, err := expandBinaryAuthorizationAttestorAttestationAuthorityNoteNoteReference(original["note_reference"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedNoteReference); val.IsValid() && !isEmptyValue(val) { + transformed["noteReference"] = transformedNoteReference + } + + transformedPublicKeys, err := expandBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeys(original["public_keys"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedPublicKeys); val.IsValid() && !isEmptyValue(val) { + transformed["publicKeys"] = transformedPublicKeys + } + + transformedDelegationServiceAccountEmail, err := expandBinaryAuthorizationAttestorAttestationAuthorityNoteDelegationServiceAccountEmail(original["delegation_service_account_email"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedDelegationServiceAccountEmail); val.IsValid() && !isEmptyValue(val) { + transformed["delegationServiceAccountEmail"] = transformedDelegationServiceAccountEmail + } + + return transformed, nil +} + +func expandBinaryAuthorizationAttestorAttestationAuthorityNoteNoteReference(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + r := regexp.MustCompile("projects/(.+)/notes/(.+)") + if r.MatchString(v.(string)) { + return v.(string), nil + } + + project, err := getProject(d, config) + if err != nil { + return nil, err + } + + return fmt.Sprintf("projects/%s/notes/%s", project, v.(string)), nil +} + +func expandBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeys(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + req := make([]interface{}, 0, len(l)) + for _, raw := range l { + if raw == nil { + continue + } + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedComment, err := expandBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysComment(original["comment"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedComment); val.IsValid() && !isEmptyValue(val) { + transformed["comment"] = transformedComment + } + + transformedId, err := expandBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysId(original["id"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedId); val.IsValid() && !isEmptyValue(val) { + transformed["id"] = transformedId + } + + transformedAsciiArmoredPgpPublicKey, err := expandBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysAsciiArmoredPgpPublicKey(original["ascii_armored_pgp_public_key"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedAsciiArmoredPgpPublicKey); val.IsValid() && !isEmptyValue(val) { + transformed["asciiArmoredPgpPublicKey"] = transformedAsciiArmoredPgpPublicKey + } + + req = append(req, transformed) + } + return req, nil +} + +func expandBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysComment(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysId(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysAsciiArmoredPgpPublicKey(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandBinaryAuthorizationAttestorAttestationAuthorityNoteDelegationServiceAccountEmail(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func resourceBinaryAuthorizationAttestorEncoder(d *schema.ResourceData, meta interface{}, obj map[string]interface{}) (map[string]interface{}, error) { + // Field was renamed in GA API + obj["userOwnedGrafeasNote"] = obj["userOwnedDrydockNote"] + delete(obj, "userOwnedDrydockNote") + + return obj, nil +} + +func resourceBinaryAuthorizationAttestorDecoder(d *schema.ResourceData, meta interface{}, res map[string]interface{}) (map[string]interface{}, error) { + res["userOwnedDrydockNote"] = res["userOwnedGrafeasNote"] + delete(res, "userOwnedGrafeasNote") + + return res, nil +} diff --git a/google/resource_binary_authorization_policy.go b/google/resource_binary_authorization_policy.go new file mode 100644 index 00000000000..4f036384b7e --- /dev/null +++ b/google/resource_binary_authorization_policy.go @@ -0,0 +1,594 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package google + +import ( + "bytes" + "fmt" + "log" + "reflect" + "regexp" + "time" + + "github.com/hashicorp/terraform/helper/hashcode" + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/validation" +) + +func defaultBinaryAuthorizationPolicy(project string) map[string]interface{} { + return map[string]interface{}{ + "name": fmt.Sprintf("projects/%s/policy", project), + "admissionWhitelistPatterns": []interface{}{ + map[string]interface{}{ + "namePattern": "gcr.io/google_containers/*", + }, + }, + "defaultAdmissionRule": map[string]interface{}{ + "evaluationMode": "ALWAYS_ALLOW", + "enforcementMode": "ENFORCED_BLOCK_AND_AUDIT_LOG", + }, + } +} + +func resourceBinaryAuthorizationPolicy() *schema.Resource { + return &schema.Resource{ + Create: resourceBinaryAuthorizationPolicyCreate, + Read: resourceBinaryAuthorizationPolicyRead, + Update: resourceBinaryAuthorizationPolicyUpdate, + Delete: resourceBinaryAuthorizationPolicyDelete, + + Importer: &schema.ResourceImporter{ + State: resourceBinaryAuthorizationPolicyImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(4 * time.Minute), + Update: schema.DefaultTimeout(4 * time.Minute), + Delete: schema.DefaultTimeout(4 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "default_admission_rule": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enforcement_mode": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{"ENFORCED_BLOCK_AND_AUDIT_LOG", "DRYRUN_AUDIT_LOG_ONLY"}, false), + }, + "evaluation_mode": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{"ALWAYS_ALLOW", "REQUIRE_ATTESTATION", "ALWAYS_DENY"}, false), + }, + "require_attestations_by": { + Type: schema.TypeSet, + Optional: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Set: selfLinkNameHash, + }, + }, + }, + }, + "admission_whitelist_patterns": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name_pattern": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "cluster_admission_rules": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cluster": { + Type: schema.TypeString, + Required: true, + }, + "enforcement_mode": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{"ENFORCED_BLOCK_AND_AUDIT_LOG", "DRYRUN_AUDIT_LOG_ONLY", ""}, false), + }, + "evaluation_mode": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{"ALWAYS_ALLOW", "REQUIRE_ATTESTATION", "ALWAYS_DENY", ""}, false), + }, + "require_attestations_by": { + Type: schema.TypeSet, + Optional: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Set: selfLinkNameHash, + }, + }, + }, + Set: func(v interface{}) int { + // require_attestations_by is a set of strings that can have the format + // projects/{project}/attestors/{attestor} or {attestor}. We diffsuppress + // and hash that set on the name, but now we need to make sure that the + // overall hash here respects that so changing the attestor format doesn't + // change the hash code of cluster_admission_rules. + raw := v.(map[string]interface{}) + + // modifying raw actually modifies the values passed to the provider. + // Use a copy to avoid that. + copy := make((map[string]interface{})) + for key, value := range raw { + copy[key] = value + } + at := copy["require_attestations_by"].(*schema.Set) + if at != nil { + t := convertAndMapStringArr(at.List(), GetResourceNameFromSelfLink) + copy["require_attestations_by"] = schema.NewSet(selfLinkNameHash, convertStringArrToInterface(t)) + } + var buf bytes.Buffer + schema.SerializeResourceForHash(&buf, copy, resourceBinaryAuthorizationPolicy().Schema["cluster_admission_rules"].Elem.(*schema.Resource)) + return hashcode.String(buf.String()) + }, + }, + "description": { + Type: schema.TypeString, + Optional: true, + }, + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + }, + } +} + +func resourceBinaryAuthorizationPolicyCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + obj := make(map[string]interface{}) + descriptionProp, err := expandBinaryAuthorizationPolicyDescription(d.Get("description"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(descriptionProp)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { + obj["description"] = descriptionProp + } + admissionWhitelistPatternsProp, err := expandBinaryAuthorizationPolicyAdmissionWhitelistPatterns(d.Get("admission_whitelist_patterns"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("admission_whitelist_patterns"); !isEmptyValue(reflect.ValueOf(admissionWhitelistPatternsProp)) && (ok || !reflect.DeepEqual(v, admissionWhitelistPatternsProp)) { + obj["admissionWhitelistPatterns"] = admissionWhitelistPatternsProp + } + clusterAdmissionRulesProp, err := expandBinaryAuthorizationPolicyClusterAdmissionRules(d.Get("cluster_admission_rules"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("cluster_admission_rules"); !isEmptyValue(reflect.ValueOf(clusterAdmissionRulesProp)) && (ok || !reflect.DeepEqual(v, clusterAdmissionRulesProp)) { + obj["clusterAdmissionRules"] = clusterAdmissionRulesProp + } + defaultAdmissionRuleProp, err := expandBinaryAuthorizationPolicyDefaultAdmissionRule(d.Get("default_admission_rule"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("default_admission_rule"); !isEmptyValue(reflect.ValueOf(defaultAdmissionRuleProp)) && (ok || !reflect.DeepEqual(v, defaultAdmissionRuleProp)) { + obj["defaultAdmissionRule"] = defaultAdmissionRuleProp + } + + url, err := replaceVars(d, config, "{{BinaryAuthorizationBasePath}}projects/{{project}}/policy") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new Policy: %#v", obj) + res, err := sendRequestWithTimeout(config, "PUT", url, obj, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return fmt.Errorf("Error creating Policy: %s", err) + } + + // Store the ID now + id, err := replaceVars(d, config, "{{project}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + log.Printf("[DEBUG] Finished creating Policy %q: %#v", d.Id(), res) + + return resourceBinaryAuthorizationPolicyRead(d, meta) +} + +func resourceBinaryAuthorizationPolicyRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + url, err := replaceVars(d, config, "{{BinaryAuthorizationBasePath}}projects/{{project}}/policy") + if err != nil { + return err + } + + res, err := sendRequest(config, "GET", url, nil) + if err != nil { + return handleNotFoundError(err, d, fmt.Sprintf("BinaryAuthorizationPolicy %q", d.Id())) + } + + project, err := getProject(d, config) + if err != nil { + return err + } + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading Policy: %s", err) + } + + if err := d.Set("description", flattenBinaryAuthorizationPolicyDescription(res["description"], 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) + } + if err := d.Set("cluster_admission_rules", flattenBinaryAuthorizationPolicyClusterAdmissionRules(res["clusterAdmissionRules"], d)); err != nil { + return fmt.Errorf("Error reading Policy: %s", err) + } + if err := d.Set("default_admission_rule", flattenBinaryAuthorizationPolicyDefaultAdmissionRule(res["defaultAdmissionRule"], d)); err != nil { + return fmt.Errorf("Error reading Policy: %s", err) + } + + return nil +} + +func resourceBinaryAuthorizationPolicyUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + obj := make(map[string]interface{}) + descriptionProp, err := expandBinaryAuthorizationPolicyDescription(d.Get("description"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { + obj["description"] = descriptionProp + } + admissionWhitelistPatternsProp, err := expandBinaryAuthorizationPolicyAdmissionWhitelistPatterns(d.Get("admission_whitelist_patterns"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("admission_whitelist_patterns"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, admissionWhitelistPatternsProp)) { + obj["admissionWhitelistPatterns"] = admissionWhitelistPatternsProp + } + clusterAdmissionRulesProp, err := expandBinaryAuthorizationPolicyClusterAdmissionRules(d.Get("cluster_admission_rules"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("cluster_admission_rules"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, clusterAdmissionRulesProp)) { + obj["clusterAdmissionRules"] = clusterAdmissionRulesProp + } + defaultAdmissionRuleProp, err := expandBinaryAuthorizationPolicyDefaultAdmissionRule(d.Get("default_admission_rule"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("default_admission_rule"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, defaultAdmissionRuleProp)) { + obj["defaultAdmissionRule"] = defaultAdmissionRuleProp + } + + url, err := replaceVars(d, config, "{{BinaryAuthorizationBasePath}}projects/{{project}}/policy") + if err != nil { + return err + } + + log.Printf("[DEBUG] Updating Policy %q: %#v", d.Id(), obj) + _, err = sendRequestWithTimeout(config, "PUT", url, obj, d.Timeout(schema.TimeoutUpdate)) + + if err != nil { + return fmt.Errorf("Error updating Policy %q: %s", d.Id(), err) + } + + return resourceBinaryAuthorizationPolicyRead(d, meta) +} + +func resourceBinaryAuthorizationPolicyDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + url, err := replaceVars(d, config, "{{BinaryAuthorizationBasePath}}projects/{{project}}/policy") + if err != nil { + return err + } + + var obj map[string]interface{} + obj = defaultBinaryAuthorizationPolicy(d.Get("project").(string)) + log.Printf("[DEBUG] Deleting Policy %q", d.Id()) + res, err := sendRequestWithTimeout(config, "PUT", url, obj, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return handleNotFoundError(err, d, "Policy") + } + + log.Printf("[DEBUG] Finished deleting Policy %q: %#v", d.Id(), res) + return nil +} + +func resourceBinaryAuthorizationPolicyImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*Config) + if err := parseImportId([]string{ + "projects/(?P[^/]+)", + "(?P[^/]+)", + }, d, config); err != nil { + return nil, err + } + + // Replace import id for the resource id + id, err := replaceVars(d, config, "{{project}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenBinaryAuthorizationPolicyDescription(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenBinaryAuthorizationPolicyAdmissionWhitelistPatterns(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return v + } + l := v.([]interface{}) + transformed := make([]interface{}, 0, len(l)) + for _, raw := range l { + original := raw.(map[string]interface{}) + if len(original) < 1 { + // Do not include empty json objects coming back from the api + continue + } + transformed = append(transformed, map[string]interface{}{ + "name_pattern": flattenBinaryAuthorizationPolicyAdmissionWhitelistPatternsNamePattern(original["namePattern"], d), + }) + } + return transformed +} +func flattenBinaryAuthorizationPolicyAdmissionWhitelistPatternsNamePattern(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenBinaryAuthorizationPolicyClusterAdmissionRules(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return v + } + l := v.(map[string]interface{}) + transformed := make([]interface{}, 0, len(l)) + for k, raw := range l { + original := raw.(map[string]interface{}) + transformed = append(transformed, map[string]interface{}{ + "cluster": k, + "evaluation_mode": flattenBinaryAuthorizationPolicyClusterAdmissionRulesEvaluationMode(original["evaluationMode"], d), + "require_attestations_by": flattenBinaryAuthorizationPolicyClusterAdmissionRulesRequireAttestationsBy(original["requireAttestationsBy"], d), + "enforcement_mode": flattenBinaryAuthorizationPolicyClusterAdmissionRulesEnforcementMode(original["enforcementMode"], d), + }) + } + return transformed +} +func flattenBinaryAuthorizationPolicyClusterAdmissionRulesEvaluationMode(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenBinaryAuthorizationPolicyClusterAdmissionRulesRequireAttestationsBy(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return v + } + return schema.NewSet(selfLinkNameHash, v.([]interface{})) +} + +func flattenBinaryAuthorizationPolicyClusterAdmissionRulesEnforcementMode(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenBinaryAuthorizationPolicyDefaultAdmissionRule(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["evaluation_mode"] = + flattenBinaryAuthorizationPolicyDefaultAdmissionRuleEvaluationMode(original["evaluationMode"], d) + transformed["require_attestations_by"] = + flattenBinaryAuthorizationPolicyDefaultAdmissionRuleRequireAttestationsBy(original["requireAttestationsBy"], d) + transformed["enforcement_mode"] = + flattenBinaryAuthorizationPolicyDefaultAdmissionRuleEnforcementMode(original["enforcementMode"], d) + return []interface{}{transformed} +} +func flattenBinaryAuthorizationPolicyDefaultAdmissionRuleEvaluationMode(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenBinaryAuthorizationPolicyDefaultAdmissionRuleRequireAttestationsBy(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return v + } + return schema.NewSet(selfLinkNameHash, v.([]interface{})) +} + +func flattenBinaryAuthorizationPolicyDefaultAdmissionRuleEnforcementMode(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func expandBinaryAuthorizationPolicyDescription(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)) + for _, raw := range l { + if raw == nil { + continue + } + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedNamePattern, err := expandBinaryAuthorizationPolicyAdmissionWhitelistPatternsNamePattern(original["name_pattern"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedNamePattern); val.IsValid() && !isEmptyValue(val) { + transformed["namePattern"] = transformedNamePattern + } + + req = append(req, transformed) + } + return req, nil +} + +func expandBinaryAuthorizationPolicyAdmissionWhitelistPatternsNamePattern(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandBinaryAuthorizationPolicyClusterAdmissionRules(v interface{}, d TerraformResourceData, config *Config) (map[string]interface{}, error) { + if v == nil { + return map[string]interface{}{}, nil + } + m := make(map[string]interface{}) + for _, raw := range v.(*schema.Set).List() { + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedEvaluationMode, err := expandBinaryAuthorizationPolicyClusterAdmissionRulesEvaluationMode(original["evaluation_mode"], d, config) + if err != nil { + return nil, err + } + transformed["evaluationMode"] = transformedEvaluationMode + transformedRequireAttestationsBy, err := expandBinaryAuthorizationPolicyClusterAdmissionRulesRequireAttestationsBy(original["require_attestations_by"], d, config) + if err != nil { + return nil, err + } + transformed["requireAttestationsBy"] = transformedRequireAttestationsBy + transformedEnforcementMode, err := expandBinaryAuthorizationPolicyClusterAdmissionRulesEnforcementMode(original["enforcement_mode"], d, config) + if err != nil { + return nil, err + } + transformed["enforcementMode"] = transformedEnforcementMode + + m[original["cluster"].(string)] = transformed + } + return m, nil +} + +func expandBinaryAuthorizationPolicyClusterAdmissionRulesEvaluationMode(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandBinaryAuthorizationPolicyClusterAdmissionRulesRequireAttestationsBy(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + r := regexp.MustCompile("projects/(.+)/attestors/(.+)") + + // It's possible that all entries in the list will specify a project, in + // which case the user wouldn't necessarily have to specify a provider + // project. + var project string + var err error + for _, s := range v.(*schema.Set).List() { + if !r.MatchString(s.(string)) { + project, err = getProject(d, config) + if err != nil { + return []interface{}{}, err + } + break + } + } + + return convertAndMapStringArr(v.(*schema.Set).List(), func(s string) string { + if r.MatchString(s) { + return s + } + + return fmt.Sprintf("projects/%s/attestors/%s", project, s) + }), nil +} + +func expandBinaryAuthorizationPolicyClusterAdmissionRulesEnforcementMode(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandBinaryAuthorizationPolicyDefaultAdmissionRule(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{}) + + transformedEvaluationMode, err := expandBinaryAuthorizationPolicyDefaultAdmissionRuleEvaluationMode(original["evaluation_mode"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedEvaluationMode); val.IsValid() && !isEmptyValue(val) { + transformed["evaluationMode"] = transformedEvaluationMode + } + + transformedRequireAttestationsBy, err := expandBinaryAuthorizationPolicyDefaultAdmissionRuleRequireAttestationsBy(original["require_attestations_by"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedRequireAttestationsBy); val.IsValid() && !isEmptyValue(val) { + transformed["requireAttestationsBy"] = transformedRequireAttestationsBy + } + + transformedEnforcementMode, err := expandBinaryAuthorizationPolicyDefaultAdmissionRuleEnforcementMode(original["enforcement_mode"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedEnforcementMode); val.IsValid() && !isEmptyValue(val) { + transformed["enforcementMode"] = transformedEnforcementMode + } + + return transformed, nil +} + +func expandBinaryAuthorizationPolicyDefaultAdmissionRuleEvaluationMode(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandBinaryAuthorizationPolicyDefaultAdmissionRuleRequireAttestationsBy(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + r := regexp.MustCompile("projects/(.+)/attestors/(.+)") + + // It's possible that all entries in the list will specify a project, in + // which case the user wouldn't necessarily have to specify a provider + // project. + var project string + var err error + for _, s := range v.(*schema.Set).List() { + if !r.MatchString(s.(string)) { + project, err = getProject(d, config) + if err != nil { + return []interface{}{}, err + } + break + } + } + + return convertAndMapStringArr(v.(*schema.Set).List(), func(s string) string { + if r.MatchString(s) { + return s + } + + return fmt.Sprintf("projects/%s/attestors/%s", project, s) + }), nil +} + +func expandBinaryAuthorizationPolicyDefaultAdmissionRuleEnforcementMode(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} diff --git a/google/resource_binaryauthorization_attestor_test.go b/google/resource_binaryauthorization_attestor_test.go index 93cfad7a2a0..09f7ab0847a 100644 --- a/google/resource_binaryauthorization_attestor_test.go +++ b/google/resource_binaryauthorization_attestor_test.go @@ -1,3 +1,4 @@ package google -// Magic Modules doesn't let us remove files - blank out beta-only common-compile files for now. +// 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. diff --git a/google/resource_binaryauthorization_policy_test.go b/google/resource_binaryauthorization_policy_test.go index 93cfad7a2a0..23524e1a667 100644 --- a/google/resource_binaryauthorization_policy_test.go +++ b/google/resource_binaryauthorization_policy_test.go @@ -1,3 +1,97 @@ package google -// Magic Modules doesn't let us remove files - blank out beta-only common-compile files for now. +import ( + "fmt" + "reflect" + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccBinaryAuthorizationPolicy_basic(t *testing.T) { + t.Parallel() + + org := getTestOrgFromEnv(t) + pid := "tf-test-" + acctest.RandString(10) + billingId := getTestBillingAccountFromEnv(t) + 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, + }, + // 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), + }, + }, + }) +} + +// 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 testAccCheckBinaryAuthorizationPolicyDefault(pid string) resource.TestCheckFunc { + return func(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + url := fmt.Sprintf("https://binaryauthorization.googleapis.com/v1beta1/projects/%s/policy", pid) + pol, err := sendRequest(config, "GET", url, nil) + if err != nil { + return err + } + delete(pol, "updateTime") + + defaultPol := defaultBinaryAuthorizationPolicy(pid) + if !reflect.DeepEqual(pol, defaultPol) { + return fmt.Errorf("Policy for project %s was %v, expected default policy %v", pid, pol, defaultPol) + } + return nil + } +} + +func testAccBinaryAuthorizationPolicyDefault(pid, pname, org, billing 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" +} +`, pid, pname, org, billing) +} + +func testAccBinaryAuthorizationPolicyBasic(pid, pname, org, billing 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_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_DENY" + enforcement_mode = "ENFORCED_BLOCK_AND_AUDIT_LOG" + } +} +`, pid, pname, org, billing) +} diff --git a/website/docs/provider_reference.html.markdown b/website/docs/provider_reference.html.markdown index 6b2b2f31d7f..835c198fbd0 100644 --- a/website/docs/provider_reference.html.markdown +++ b/website/docs/provider_reference.html.markdown @@ -230,6 +230,7 @@ be used for configuration are below: * `app_engine_custom_endpoint` (`GOOGLE_APP_ENGINE_CUSTOM_ENDPOINT`) - `https://appengine.googleapis.com/v1/` * `bigquery_custom_endpoint` (`GOOGLE_BIGQUERY_CUSTOM_ENDPOINT`) - `https://www.googleapis.com/bigquery/v2/` * `bigtable_custom_endpoint` (`GOOGLE_BIGTABLE_CUSTOM_ENDPOINT`) - `https://bigtableadmin.googleapis.com/v2/` +* `binary_authorization_custom_endpoint` (`GOOGLE_BINARY_AUTHORIZATION_CUSTOM_ENDPOINT`) - `https://binaryauthorization.googleapis.com/v1/` * `cloud_billing_custom_endpoint` (`GOOGLE_CLOUD_BILLING_CUSTOM_ENDPOINT`) - `https://cloudbilling.googleapis.com/v1/` * `cloud_build_custom_endpoint` (`GOOGLE_CLOUD_BUILD_CUSTOM_ENDPOINT`) - `https://cloudbuild.googleapis.com/v1/` * `cloud_functions_custom_endpoint` (`GOOGLE_CLOUD_FUNCTIONS_CUSTOM_ENDPOINT`) - `https://cloudfunctions.googleapis.com/v1/` @@ -269,7 +270,6 @@ be used for configuration are below: The following keys are available exclusively in the `google-beta` provider: -* `binary_authorization_custom_endpoint` (`GOOGLE_BINARY_AUTHORIZATION_CUSTOM_ENDPOINT`) - `https://binaryauthorization.googleapis.com/v1beta1/` * `container_analysis_custom_endpoint` (`GOOGLE_CONTAINER_ANALYSIS_CUSTOM_ENDPOINT`) - `https://containeranalysis.googleapis.com/v1beta1/` * `iap_custom_endpoint` (`GOOGLE_IAP_CUSTOM_ENDPOINT`) - `https://iap.googleapis.com/v1beta1/` * `monitoring_custom_endpoint` (`GOOGLE_MONITORING_CUSTOM_ENDPOINT`) - `https://monitoring.googleapis.com/v3/` diff --git a/website/docs/r/binary_authorization_attestor.html.markdown b/website/docs/r/binary_authorization_attestor.html.markdown new file mode 100644 index 00000000000..18f2adac0ac --- /dev/null +++ b/website/docs/r/binary_authorization_attestor.html.markdown @@ -0,0 +1,172 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in +# .github/CONTRIBUTING.md. +# +# ---------------------------------------------------------------------------- +layout: "google" +page_title: "Google: google_binary_authorization_attestor" +sidebar_current: "docs-google-binary-authorization-attestor" +description: |- + An attestor that attests to container image artifacts. +--- + +# google\_binary\_authorization\_attestor + +An attestor that attests to container image artifacts. + + +To get more information about Attestor, see: + +* [API documentation](https://cloud.google.com/binary-authorization/docs/reference/rest/) +* How-to Guides + * [Official Documentation](https://cloud.google.com/binary-authorization/) + +## Example Usage - Binary Authorization Attestor Basic + + +```hcl +resource "google_binary_authorization_attestor" "attestor" { + name = "test-attestor" + attestation_authority_note { + note_reference = "${google_container_analysis_note.note.name}" + public_keys { + ascii_armored_pgp_public_key = < If you're importing a resource with beta features, make sure to include `-provider=google-beta` +as an argument so that Terraform uses the correct provider to import your resource. diff --git a/website/docs/r/binary_authorization_policy.html.markdown b/website/docs/r/binary_authorization_policy.html.markdown new file mode 100644 index 00000000000..897216ce197 --- /dev/null +++ b/website/docs/r/binary_authorization_policy.html.markdown @@ -0,0 +1,185 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in +# .github/CONTRIBUTING.md. +# +# ---------------------------------------------------------------------------- +layout: "google" +page_title: "Google: google_binary_authorization_policy" +sidebar_current: "docs-google-binary-authorization-policy" +description: |- + A policy for container image binary authorization. +--- + +# google\_binary\_authorization\_policy + +A policy for container image binary authorization. + + +To get more information about Policy, see: + +* [API documentation](https://cloud.google.com/binary-authorization/docs/reference/rest/) +* How-to Guides + * [Official Documentation](https://cloud.google.com/binary-authorization/) + +## Example Usage - Binary Authorization Policy Basic + + +```hcl +resource "google_binary_authorization_policy" "policy" { + 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}"] + } +} + +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 { + note_reference = "${google_container_analysis_note.note.name}" + } +} +``` + +## Argument Reference + +The following arguments are supported: + + +* `default_admission_rule` - + (Required) + Default admission rule for a cluster without a per-cluster admission + rule. Structure is documented below. + + +The `default_admission_rule` block supports: + +* `evaluation_mode` - + (Required) + How this admission rule will be evaluated. + +* `require_attestations_by` - + (Optional) + The resource names of the attestors that must attest to a + container image. If the attestor is in a different project from the + policy, it should be specified in the format `projects/*/attestors/*`. + Each attestor must exist before a policy can reference it. To add an + attestor to a policy the principal issuing the policy change + request must be able to read the attestor resource. + Note: this field must be non-empty when the evaluation_mode field + specifies REQUIRE_ATTESTATION, otherwise it must be empty. + +* `enforcement_mode` - + (Required) + The action when a pod creation is denied by the admission rule. + +- - - + + +* `description` - + (Optional) + A descriptive comment. + +* `admission_whitelist_patterns` - + (Optional) + A whitelist of image patterns to exclude from admission rules. If an + image's name matches a whitelist pattern, the image's admission + requests will always be permitted regardless of your admission rules. Structure is documented below. + +* `cluster_admission_rules` - + (Optional) + Per-cluster admission rules. An admission rule specifies either that + all container images used in a pod creation request must be attested + to by one or more attestors, that all pod creations will be allowed, + or that all pod creations will be denied. There can be at most one + admission rule per cluster spec. + + Identifier format: `{{location}}.{{clusterId}}`. + A location is either a compute zone (e.g. `us-central1-a`) or a region + (e.g. `us-central1`). Structure is documented below. + +* `project` - (Optional) The ID of the project in which the resource belongs. + If it is not provided, the provider project is used. + + +The `admission_whitelist_patterns` block supports: + +* `name_pattern` - + (Optional) + An image name pattern to whitelist, in the form + `registry/path/to/image`. This supports a trailing * as a + wildcard, but this is allowed only in text after the registry/ + part. + +The `cluster_admission_rules` block supports: + +* `cluster` - (Required) The identifier for this object. Format specified above. + +* `evaluation_mode` - + (Optional) + How this admission rule will be evaluated. + +* `require_attestations_by` - + (Optional) + The resource names of the attestors that must attest to a + container image. If the attestor is in a different project from the + policy, it should be specified in the format `projects/*/attestors/*`. + Each attestor must exist before a policy can reference it. To add an + attestor to a policy the principal issuing the policy change + request must be able to read the attestor resource. + Note: this field must be non-empty when the evaluation_mode field + specifies REQUIRE_ATTESTATION, otherwise it must be empty. + +* `enforcement_mode` - + (Optional) + The action when a pod creation is denied by the admission rule. + + +## Timeouts + +This resource provides the following +[Timeouts](/docs/configuration/resources.html#timeouts) configuration options: + +- `create` - Default is 4 minutes. +- `update` - Default is 4 minutes. +- `delete` - Default is 4 minutes. + +## Import + +Policy can be imported using any of these accepted formats: + +``` +$ terraform import google_binary_authorization_policy.default projects/{{project}} +$ terraform import google_binary_authorization_policy.default {{project}} +``` + +-> If you're importing a resource with beta features, make sure to include `-provider=google-beta` +as an argument so that Terraform uses the correct provider to import your resource. diff --git a/website/google.erb b/website/google.erb index 1e12b99a12a..12f466b2647 100644 --- a/website/google.erb +++ b/website/google.erb @@ -227,6 +227,17 @@ + > + Google Binary Authorization Resources + + + > Google Cloud Build Resources