Add Policy, Attestor, and Note resources for Binary Authorization (#1885)

<!-- This change is generated by MagicModules. -->
/cc @danawillow
This commit is contained in:
The Magician 2018-08-20 16:46:13 -07:00 committed by Dana Hoffman
parent fb66cd88c5
commit 3ff7ccca7c
35 changed files with 2300 additions and 26 deletions

View File

@ -99,7 +99,9 @@ func Provider() terraform.ResourceProvider {
},
ResourcesMap: mergeResourceMaps(
GeneratedBinaryAuthorizationResourcesMap,
GeneratedComputeResourcesMap,
GeneratedContainerAnalysisResourcesMap,
GeneratedRedisResourcesMap,
GeneratedResourceManagerResourcesMap,
map[string]*schema.Resource{

View File

@ -0,0 +1,22 @@
// ----------------------------------------------------------------------------
//
// *** 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"
var GeneratedBinaryAuthorizationResourcesMap = map[string]*schema.Resource{
"google_binary_authorization_attestor": resourceBinaryAuthorizationAttestor(),
"google_binary_authorization_policy": resourceBinaryAuthorizationPolicy(),
}

View File

@ -0,0 +1,21 @@
// ----------------------------------------------------------------------------
//
// *** 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"
var GeneratedContainerAnalysisResourcesMap = map[string]*schema.Resource{
"google_container_analysis_note": resourceContainerAnalysisNote(),
}

View File

@ -0,0 +1,397 @@
// ----------------------------------------------------------------------------
//
// *** 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"
"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,
},
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
}
url, err := replaceVars(d, config, "https://binaryauthorization.googleapis.com/v1beta1/projects/{{project}}/attestors?attestorId={{name}}")
if err != nil {
return err
}
log.Printf("[DEBUG] Creating new Attestor: %#v", obj)
res, err := sendRequest(config, "POST", url, obj)
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, "https://binaryauthorization.googleapis.com/v1beta1/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()))
}
if err := d.Set("name", flattenBinaryAuthorizationAttestorName(res["name"])); err != nil {
return fmt.Errorf("Error reading Attestor: %s", err)
}
if err := d.Set("description", flattenBinaryAuthorizationAttestorDescription(res["description"])); err != nil {
return fmt.Errorf("Error reading Attestor: %s", err)
}
if err := d.Set("attestation_authority_note", flattenBinaryAuthorizationAttestorAttestationAuthorityNote(res["userOwnedDrydockNote"])); err != nil {
return fmt.Errorf("Error reading Attestor: %s", 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)
}
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
}
url, err := replaceVars(d, config, "https://binaryauthorization.googleapis.com/v1beta1/projects/{{project}}/attestors/{{name}}")
if err != nil {
return err
}
log.Printf("[DEBUG] Updating Attestor %q: %#v", d.Id(), obj)
_, err = sendRequest(config, "PUT", url, obj)
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, "https://binaryauthorization.googleapis.com/v1beta1/projects/{{project}}/attestors/{{name}}")
if err != nil {
return err
}
var obj map[string]interface{}
log.Printf("[DEBUG] Deleting Attestor %q", d.Id())
res, err := sendRequest(config, "DELETE", url, obj)
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)
parseImportId([]string{"projects/(?P<project>[^/]+)/attestors/(?P<name>[^/]+)", "(?P<project>[^/]+)/(?P<name>[^/]+)", "(?P<name>[^/]+)"}, d, config)
// 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{}) interface{} {
if v == nil {
return v
}
return NameFromSelfLinkStateFunc(v)
}
func flattenBinaryAuthorizationAttestorDescription(v interface{}) interface{} {
return v
}
func flattenBinaryAuthorizationAttestorAttestationAuthorityNote(v interface{}) interface{} {
if v == nil {
return nil
}
original := v.(map[string]interface{})
transformed := make(map[string]interface{})
transformed["note_reference"] =
flattenBinaryAuthorizationAttestorAttestationAuthorityNoteNoteReference(original["noteReference"])
transformed["public_keys"] =
flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeys(original["publicKeys"])
transformed["delegation_service_account_email"] =
flattenBinaryAuthorizationAttestorAttestationAuthorityNoteDelegationServiceAccountEmail(original["delegationServiceAccountEmail"])
return []interface{}{transformed}
}
func flattenBinaryAuthorizationAttestorAttestationAuthorityNoteNoteReference(v interface{}) interface{} {
return v
}
func flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeys(v interface{}) interface{} {
if v == nil {
return v
}
l := v.([]interface{})
transformed := make([]interface{}, 0, len(l))
for _, raw := range l {
original := raw.(map[string]interface{})
transformed = append(transformed, map[string]interface{}{
"comment": flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysComment(original["comment"]),
"id": flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysId(original["id"]),
"ascii_armored_pgp_public_key": flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysAsciiArmoredPgpPublicKey(original["asciiArmoredPgpPublicKey"]),
})
}
return transformed
}
func flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysComment(v interface{}) interface{} {
return v
}
func flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysId(v interface{}) interface{} {
return v
}
func flattenBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysAsciiArmoredPgpPublicKey(v interface{}) interface{} {
return v
}
func flattenBinaryAuthorizationAttestorAttestationAuthorityNoteDelegationServiceAccountEmail(v interface{}) interface{} {
return v
}
func expandBinaryAuthorizationAttestorName(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
return v, nil
}
func expandBinaryAuthorizationAttestorDescription(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
return v, nil
}
func expandBinaryAuthorizationAttestorAttestationAuthorityNote(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
l := v.([]interface{})
if len(l) == 0 {
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
}
transformed["noteReference"] = transformedNoteReference
transformedPublicKeys, err := expandBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeys(original["public_keys"], d, config)
if err != nil {
return nil, err
}
transformed["publicKeys"] = transformedPublicKeys
transformedDelegationServiceAccountEmail, err := expandBinaryAuthorizationAttestorAttestationAuthorityNoteDelegationServiceAccountEmail(original["delegation_service_account_email"], d, config)
if err != nil {
return nil, err
}
transformed["delegationServiceAccountEmail"] = transformedDelegationServiceAccountEmail
return transformed, nil
}
func expandBinaryAuthorizationAttestorAttestationAuthorityNoteNoteReference(v interface{}, d *schema.ResourceData, 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 *schema.ResourceData, config *Config) (interface{}, error) {
l := v.([]interface{})
req := make([]interface{}, 0, len(l))
for _, raw := range l {
original := raw.(map[string]interface{})
transformed := make(map[string]interface{})
transformedComment, err := expandBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysComment(original["comment"], d, config)
if err != nil {
return nil, err
}
transformed["comment"] = transformedComment
transformedId, err := expandBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysId(original["id"], d, config)
if err != nil {
return nil, err
}
transformed["id"] = transformedId
transformedAsciiArmoredPgpPublicKey, err := expandBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysAsciiArmoredPgpPublicKey(original["ascii_armored_pgp_public_key"], d, config)
if err != nil {
return nil, err
}
transformed["asciiArmoredPgpPublicKey"] = transformedAsciiArmoredPgpPublicKey
req = append(req, transformed)
}
return req, nil
}
func expandBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysComment(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
return v, nil
}
func expandBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysId(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
return v, nil
}
func expandBinaryAuthorizationAttestorAttestationAuthorityNotePublicKeysAsciiArmoredPgpPublicKey(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
return v, nil
}
func expandBinaryAuthorizationAttestorAttestationAuthorityNoteDelegationServiceAccountEmail(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
return v, nil
}

View File

@ -0,0 +1,182 @@
package google
import (
"fmt"
"testing"
"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)
func TestAccBinaryAuthorizationAttestor_basic(t *testing.T) {
t.Parallel()
name := acctest.RandString(10)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckBinaryAuthorizationAttestorDestroy,
Steps: []resource.TestStep{
{
Config: testAccBinaryAuthorizationAttestorBasic(name),
},
{
ResourceName: "google_binary_authorization_attestor.attestor",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
func TestAccBinaryAuthorizationAttestor_full(t *testing.T) {
t.Parallel()
name := acctest.RandString(10)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckBinaryAuthorizationAttestorDestroy,
Steps: []resource.TestStep{
{
Config: testAccBinaryAuthorizationAttestorFull(name),
},
{
ResourceName: "google_binary_authorization_attestor.attestor",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
func TestAccBinaryAuthorizationAttestor_update(t *testing.T) {
t.Parallel()
name := acctest.RandString(10)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckBinaryAuthorizationAttestorDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccBinaryAuthorizationAttestorBasic(name),
},
{
ResourceName: "google_binary_authorization_attestor.attestor",
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccBinaryAuthorizationAttestorFull(name),
},
{
ResourceName: "google_binary_authorization_attestor.attestor",
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccBinaryAuthorizationAttestorBasic(name),
},
{
ResourceName: "google_binary_authorization_attestor.attestor",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
func testAccCheckBinaryAuthorizationAttestorDestroy(s *terraform.State) error {
config := testAccProvider.Meta().(*Config)
for _, rs := range s.RootModule().Resources {
if rs.Type != "google_binary_authorization_attestor" {
continue
}
project, err := getTestProject(rs.Primary, config)
if err != nil {
return err
}
name := rs.Primary.Attributes["name"]
url := fmt.Sprintf("https://binaryauthorization.googleapis.com/v1beta1/projects/%s/attestors/%s", project, name)
_, err = sendRequest(config, "GET", url, nil)
if err == nil {
return fmt.Errorf("Error, attestor %s still exists", name)
}
}
return nil
}
func testAccBinaryAuthorizationAttestorBasic(name string) string {
return fmt.Sprintf(`
resource "google_container_analysis_note" "note" {
name = "tf-test-%s"
attestation_authority {
hint {
human_readable_name = "My Attestor"
}
}
}
resource "google_binary_authorization_attestor" "attestor" {
name = "tf-test-%s"
attestation_authority_note {
note_reference = "${google_container_analysis_note.note.name}"
}
}
`, name, name)
}
func testAccBinaryAuthorizationAttestorFull(name string) string {
return fmt.Sprintf(`
resource "google_container_analysis_note" "note" {
name = "tf-test-%s"
attestation_authority {
hint {
human_readable_name = "My Attestor"
}
}
}
resource "google_binary_authorization_attestor" "attestor" {
name = "tf-test-%s"
description = "my description"
attestation_authority_note {
note_reference = "${google_container_analysis_note.note.name}"
public_keys {
ascii_armored_pgp_public_key = <<EOF
%s
EOF
comment = "this key has a comment"
}
}
}
`, name, name, armoredPubKey)
}
// Generated key using instructions from
// https://cloud.google.com/binary-authorization/docs/creating-attestors#generate_pgp_key_pairs.
// This key has no real meaning and was generated in order to have a valid key
// for testing.
const armoredPubKey = `mQENBFtP0doBCADF+joTiXWKVuP8kJt3fgpBSjT9h8ezMfKA4aXZctYLx5wslWQl
bB7Iu2ezkECNzoEeU7WxUe8a61pMCh9cisS9H5mB2K2uM4Jnf8tgFeXn3akJDVo0
oR1IC+Dp9mXbRSK3MAvKkOwWlG99sx3uEdvmeBRHBOO+grchLx24EThXFOyP9Fk6
V39j6xMjw4aggLD15B4V0v9JqBDdJiIYFzszZDL6pJwZrzcP0z8JO4rTZd+f64bD
Mpj52j/pQfA8lZHOaAgb1OrthLdMrBAjoDjArV4Ek7vSbrcgYWcI6BhsQrFoxKdX
83TZKai55ZCfCLIskwUIzA1NLVwyzCS+fSN/ABEBAAG0KCJUZXN0IEF0dGVzdG9y
IiA8ZGFuYWhvZmZtYW5AZ29vZ2xlLmNvbT6JAU4EEwEIADgWIQRfWkqHt6hpTA1L
uY060eeM4dc66AUCW0/R2gIbLwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRA6
0eeM4dc66HdpCAC4ot3b0OyxPb0Ip+WT2U0PbpTBPJklesuwpIrM4Lh0N+1nVRLC
51WSmVbM8BiAFhLbN9LpdHhds1kUrHF7+wWAjdR8sqAj9otc6HGRM/3qfa2qgh+U
WTEk/3us/rYSi7T7TkMuutRMIa1IkR13uKiW56csEMnbOQpn9rDqwIr5R8nlZP5h
MAU9vdm1DIv567meMqTaVZgR3w7bck2P49AO8lO5ERFpVkErtu/98y+rUy9d789l
+OPuS1NGnxI1YKsNaWJF4uJVuvQuZ1twrhCbGNtVorO2U12+cEq+YtUxj7kmdOC1
qoIRW6y0+UlAc+MbqfL0ziHDOAmcqz1GnROg
=6Bvm`

View File

@ -0,0 +1,556 @@
// ----------------------------------------------------------------------------
//
// *** 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"
"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,
},
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,
},
},
},
},
"description": {
Type: schema.TypeString,
Optional: true,
},
"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,
},
"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,
},
"enforcement_mode": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice([]string{"ENFORCED_BLOCK_AND_AUDIT_LOG", "DRYRUN_AUDIT_LOG_ONLY", ""}, false),
},
},
},
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{})
at := raw["require_attestations_by"].(*schema.Set)
if at != nil {
t := convertAndMapStringArr(at.List(), GetResourceNameFromSelfLink)
raw["require_attestations_by"] = schema.NewSet(selfLinkNameHash, convertStringArrToInterface(t))
}
var buf bytes.Buffer
schema.SerializeResourceForHash(&buf, raw, resourceBinaryAuthorizationPolicy().Schema["cluster_admission_rules"].Elem.(*schema.Resource))
return hashcode.String(buf.String())
},
},
"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, "https://binaryauthorization.googleapis.com/v1beta1/projects/{{project}}/policy")
if err != nil {
return err
}
log.Printf("[DEBUG] Creating new Policy: %#v", obj)
res, err := sendRequest(config, "PUT", url, obj)
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, "https://binaryauthorization.googleapis.com/v1beta1/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()))
}
if err := d.Set("description", flattenBinaryAuthorizationPolicyDescription(res["description"])); err != nil {
return fmt.Errorf("Error reading Policy: %s", err)
}
if err := d.Set("admission_whitelist_patterns", flattenBinaryAuthorizationPolicyAdmissionWhitelistPatterns(res["admissionWhitelistPatterns"])); err != nil {
return fmt.Errorf("Error reading Policy: %s", err)
}
if err := d.Set("cluster_admission_rules", flattenBinaryAuthorizationPolicyClusterAdmissionRules(res["clusterAdmissionRules"])); err != nil {
return fmt.Errorf("Error reading Policy: %s", err)
}
if err := d.Set("default_admission_rule", flattenBinaryAuthorizationPolicyDefaultAdmissionRule(res["defaultAdmissionRule"])); err != nil {
return fmt.Errorf("Error reading Policy: %s", err)
}
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)
}
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, "https://binaryauthorization.googleapis.com/v1beta1/projects/{{project}}/policy")
if err != nil {
return err
}
log.Printf("[DEBUG] Updating Policy %q: %#v", d.Id(), obj)
_, err = sendRequest(config, "PUT", url, obj)
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, "https://binaryauthorization.googleapis.com/v1beta1/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 := sendRequest(config, "PUT", url, obj)
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)
parseImportId([]string{"projects/(?P<project>[^/]+)", "(?P<project>[^/]+)"}, d, config)
// 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{}) interface{} {
return v
}
func flattenBinaryAuthorizationPolicyAdmissionWhitelistPatterns(v interface{}) interface{} {
if v == nil {
return v
}
l := v.([]interface{})
transformed := make([]interface{}, 0, len(l))
for _, raw := range l {
original := raw.(map[string]interface{})
transformed = append(transformed, map[string]interface{}{
"name_pattern": flattenBinaryAuthorizationPolicyAdmissionWhitelistPatternsNamePattern(original["namePattern"]),
})
}
return transformed
}
func flattenBinaryAuthorizationPolicyAdmissionWhitelistPatternsNamePattern(v interface{}) interface{} {
return v
}
func flattenBinaryAuthorizationPolicyClusterAdmissionRules(v interface{}) 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"]),
"require_attestations_by": flattenBinaryAuthorizationPolicyClusterAdmissionRulesRequireAttestationsBy(original["requireAttestationsBy"]),
"enforcement_mode": flattenBinaryAuthorizationPolicyClusterAdmissionRulesEnforcementMode(original["enforcementMode"]),
})
}
return transformed
}
func flattenBinaryAuthorizationPolicyClusterAdmissionRulesEvaluationMode(v interface{}) interface{} {
return v
}
func flattenBinaryAuthorizationPolicyClusterAdmissionRulesRequireAttestationsBy(v interface{}) interface{} {
if v == nil {
return v
}
return schema.NewSet(selfLinkNameHash, v.([]interface{}))
}
func flattenBinaryAuthorizationPolicyClusterAdmissionRulesEnforcementMode(v interface{}) interface{} {
return v
}
func flattenBinaryAuthorizationPolicyDefaultAdmissionRule(v interface{}) interface{} {
if v == nil {
return nil
}
original := v.(map[string]interface{})
transformed := make(map[string]interface{})
transformed["evaluation_mode"] =
flattenBinaryAuthorizationPolicyDefaultAdmissionRuleEvaluationMode(original["evaluationMode"])
transformed["require_attestations_by"] =
flattenBinaryAuthorizationPolicyDefaultAdmissionRuleRequireAttestationsBy(original["requireAttestationsBy"])
transformed["enforcement_mode"] =
flattenBinaryAuthorizationPolicyDefaultAdmissionRuleEnforcementMode(original["enforcementMode"])
return []interface{}{transformed}
}
func flattenBinaryAuthorizationPolicyDefaultAdmissionRuleEvaluationMode(v interface{}) interface{} {
return v
}
func flattenBinaryAuthorizationPolicyDefaultAdmissionRuleRequireAttestationsBy(v interface{}) interface{} {
if v == nil {
return v
}
return schema.NewSet(selfLinkNameHash, v.([]interface{}))
}
func flattenBinaryAuthorizationPolicyDefaultAdmissionRuleEnforcementMode(v interface{}) interface{} {
return v
}
func expandBinaryAuthorizationPolicyDescription(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
return v, nil
}
func expandBinaryAuthorizationPolicyAdmissionWhitelistPatterns(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
l := v.([]interface{})
req := make([]interface{}, 0, len(l))
for _, raw := range l {
original := raw.(map[string]interface{})
transformed := make(map[string]interface{})
transformedNamePattern, err := expandBinaryAuthorizationPolicyAdmissionWhitelistPatternsNamePattern(original["name_pattern"], d, config)
if err != nil {
return nil, err
}
transformed["namePattern"] = transformedNamePattern
req = append(req, transformed)
}
return req, nil
}
func expandBinaryAuthorizationPolicyAdmissionWhitelistPatternsNamePattern(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
return v, nil
}
func expandBinaryAuthorizationPolicyClusterAdmissionRules(v interface{}, d *schema.ResourceData, 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 *schema.ResourceData, config *Config) (interface{}, error) {
return v, nil
}
func expandBinaryAuthorizationPolicyClusterAdmissionRulesRequireAttestationsBy(v interface{}, d *schema.ResourceData, 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 *schema.ResourceData, config *Config) (interface{}, error) {
return v, nil
}
func expandBinaryAuthorizationPolicyDefaultAdmissionRule(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
l := v.([]interface{})
if len(l) == 0 {
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
}
transformed["evaluationMode"] = transformedEvaluationMode
transformedRequireAttestationsBy, err := expandBinaryAuthorizationPolicyDefaultAdmissionRuleRequireAttestationsBy(original["require_attestations_by"], d, config)
if err != nil {
return nil, err
}
transformed["requireAttestationsBy"] = transformedRequireAttestationsBy
transformedEnforcementMode, err := expandBinaryAuthorizationPolicyDefaultAdmissionRuleEnforcementMode(original["enforcement_mode"], d, config)
if err != nil {
return nil, err
}
transformed["enforcementMode"] = transformedEnforcementMode
return transformed, nil
}
func expandBinaryAuthorizationPolicyDefaultAdmissionRuleEvaluationMode(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
return v, nil
}
func expandBinaryAuthorizationPolicyDefaultAdmissionRuleRequireAttestationsBy(v interface{}, d *schema.ResourceData, 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 *schema.ResourceData, config *Config) (interface{}, error) {
return v, nil
}

View File

@ -0,0 +1,226 @@
package google
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)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccBinaryAuthorizationPolicyBasic(pid, pname, org),
},
{
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),
Check: testAccCheckBinaryAuthorizationPolicyDefault(pid),
},
},
})
}
func TestAccBinaryAuthorizationPolicy_full(t *testing.T) {
t.Parallel()
org := getTestOrgFromEnv(t)
pid := "tf-test-" + acctest.RandString(10)
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, 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),
Check: testAccCheckBinaryAuthorizationPolicyDefault(pid),
},
},
})
}
func TestAccBinaryAuthorizationPolicy_update(t *testing.T) {
t.Parallel()
org := getTestOrgFromEnv(t)
pid := "tf-test-" + acctest.RandString(10)
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),
},
{
ResourceName: "google_binary_authorization_policy.policy",
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccBinaryAuthorizationPolicyFull(pid, pname, org, note, attestor),
},
{
ResourceName: "google_binary_authorization_policy.policy",
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccBinaryAuthorizationPolicyBasic(pid, pname, org),
},
{
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),
Check: testAccCheckBinaryAuthorizationPolicyDefault(pid),
},
},
})
}
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 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"
}
`, pid, pname, org)
}
func testAccBinaryAuthorizationPolicyBasic(pid, pname, org 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"
}
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)
}
func testAccBinaryAuthorizationPolicyFull(pid, pname, org, 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"
}
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}"]
}
}
`, pid, pname, org, note, attestor)
}

View File

@ -0,0 +1,291 @@
// ----------------------------------------------------------------------------
//
// *** 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"
"strings"
"github.com/hashicorp/terraform/helper/schema"
)
func resourceContainerAnalysisNote() *schema.Resource {
return &schema.Resource{
Create: resourceContainerAnalysisNoteCreate,
Read: resourceContainerAnalysisNoteRead,
Update: resourceContainerAnalysisNoteUpdate,
Delete: resourceContainerAnalysisNoteDelete,
Importer: &schema.ResourceImporter{
State: resourceContainerAnalysisNoteImport,
},
Schema: map[string]*schema.Schema{
"attestation_authority": {
Type: schema.TypeList,
Required: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"hint": {
Type: schema.TypeList,
Required: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"human_readable_name": {
Type: schema.TypeString,
Required: true,
},
},
},
},
},
},
},
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"project": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},
},
}
}
func resourceContainerAnalysisNoteCreate(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
obj := make(map[string]interface{})
nameProp, err := expandContainerAnalysisNoteName(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
}
attestationAuthorityProp, err := expandContainerAnalysisNoteAttestationAuthority(d.Get("attestation_authority"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("attestation_authority"); !isEmptyValue(reflect.ValueOf(attestationAuthorityProp)) && (ok || !reflect.DeepEqual(v, attestationAuthorityProp)) {
obj["attestationAuthority"] = attestationAuthorityProp
}
url, err := replaceVars(d, config, "https://containeranalysis.googleapis.com/v1alpha1/projects/{{project}}/notes?noteId={{name}}")
if err != nil {
return err
}
log.Printf("[DEBUG] Creating new Note: %#v", obj)
res, err := sendRequest(config, "POST", url, obj)
if err != nil {
return fmt.Errorf("Error creating Note: %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 Note %q: %#v", d.Id(), res)
return resourceContainerAnalysisNoteRead(d, meta)
}
func resourceContainerAnalysisNoteRead(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
url, err := replaceVars(d, config, "https://containeranalysis.googleapis.com/v1alpha1/projects/{{project}}/notes/{{name}}")
if err != nil {
return err
}
res, err := sendRequest(config, "GET", url, nil)
if err != nil {
return handleNotFoundError(err, d, fmt.Sprintf("ContainerAnalysisNote %q", d.Id()))
}
if err := d.Set("name", flattenContainerAnalysisNoteName(res["name"])); err != nil {
return fmt.Errorf("Error reading Note: %s", err)
}
if err := d.Set("attestation_authority", flattenContainerAnalysisNoteAttestationAuthority(res["attestationAuthority"])); err != nil {
return fmt.Errorf("Error reading Note: %s", err)
}
project, err := getProject(d, config)
if err != nil {
return err
}
if err := d.Set("project", project); err != nil {
return fmt.Errorf("Error reading Note: %s", err)
}
return nil
}
func resourceContainerAnalysisNoteUpdate(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
obj := make(map[string]interface{})
nameProp, err := expandContainerAnalysisNoteName(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
}
attestationAuthorityProp, err := expandContainerAnalysisNoteAttestationAuthority(d.Get("attestation_authority"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("attestation_authority"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, attestationAuthorityProp)) {
obj["attestationAuthority"] = attestationAuthorityProp
}
url, err := replaceVars(d, config, "https://containeranalysis.googleapis.com/v1alpha1/projects/{{project}}/notes/{{name}}")
if err != nil {
return err
}
log.Printf("[DEBUG] Updating Note %q: %#v", d.Id(), obj)
updateMask := []string{}
if d.HasChange("attestation_authority.0.hint.0.human_readable_name") {
updateMask = append(updateMask, "attestationAuthority.hint.humanReadableName")
}
// updateMask is a URL parameter but not present in the schema, so replaceVars
// won't set it
url, err = addQueryParams(url, map[string]string{"updateMask": strings.Join(updateMask, ",")})
if err != nil {
return err
}
_, err = sendRequest(config, "PATCH", url, obj)
if err != nil {
return fmt.Errorf("Error updating Note %q: %s", d.Id(), err)
}
return resourceContainerAnalysisNoteRead(d, meta)
}
func resourceContainerAnalysisNoteDelete(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
url, err := replaceVars(d, config, "https://containeranalysis.googleapis.com/v1alpha1/projects/{{project}}/notes/{{name}}")
if err != nil {
return err
}
var obj map[string]interface{}
log.Printf("[DEBUG] Deleting Note %q", d.Id())
res, err := sendRequest(config, "DELETE", url, obj)
if err != nil {
return handleNotFoundError(err, d, "Note")
}
log.Printf("[DEBUG] Finished deleting Note %q: %#v", d.Id(), res)
return nil
}
func resourceContainerAnalysisNoteImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
config := meta.(*Config)
parseImportId([]string{"projects/(?P<project>[^/]+)/notes/(?P<name>[^/]+)", "(?P<project>[^/]+)/(?P<name>[^/]+)", "(?P<name>[^/]+)"}, d, config)
// 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 flattenContainerAnalysisNoteName(v interface{}) interface{} {
if v == nil {
return v
}
return NameFromSelfLinkStateFunc(v)
}
func flattenContainerAnalysisNoteAttestationAuthority(v interface{}) interface{} {
if v == nil {
return nil
}
original := v.(map[string]interface{})
transformed := make(map[string]interface{})
transformed["hint"] =
flattenContainerAnalysisNoteAttestationAuthorityHint(original["hint"])
return []interface{}{transformed}
}
func flattenContainerAnalysisNoteAttestationAuthorityHint(v interface{}) interface{} {
if v == nil {
return nil
}
original := v.(map[string]interface{})
transformed := make(map[string]interface{})
transformed["human_readable_name"] =
flattenContainerAnalysisNoteAttestationAuthorityHintHumanReadableName(original["humanReadableName"])
return []interface{}{transformed}
}
func flattenContainerAnalysisNoteAttestationAuthorityHintHumanReadableName(v interface{}) interface{} {
return v
}
func expandContainerAnalysisNoteName(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
return v, nil
}
func expandContainerAnalysisNoteAttestationAuthority(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
l := v.([]interface{})
if len(l) == 0 {
return nil, nil
}
raw := l[0]
original := raw.(map[string]interface{})
transformed := make(map[string]interface{})
transformedHint, err := expandContainerAnalysisNoteAttestationAuthorityHint(original["hint"], d, config)
if err != nil {
return nil, err
}
transformed["hint"] = transformedHint
return transformed, nil
}
func expandContainerAnalysisNoteAttestationAuthorityHint(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
l := v.([]interface{})
if len(l) == 0 {
return nil, nil
}
raw := l[0]
original := raw.(map[string]interface{})
transformed := make(map[string]interface{})
transformedHumanReadableName, err := expandContainerAnalysisNoteAttestationAuthorityHintHumanReadableName(original["human_readable_name"], d, config)
if err != nil {
return nil, err
}
transformed["humanReadableName"] = transformedHumanReadableName
return transformed, nil
}
func expandContainerAnalysisNoteAttestationAuthorityHintHumanReadableName(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
return v, nil
}

View File

@ -0,0 +1,102 @@
package google
import (
"fmt"
"testing"
"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)
func TestAccContainerAnalysisNote_basic(t *testing.T) {
t.Parallel()
name := acctest.RandString(10)
readableName := acctest.RandString(10)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckContainerAnalysisNoteDestroy,
Steps: []resource.TestStep{
{
Config: testAccContainerAnalysisNoteBasic(name, readableName),
},
{
ResourceName: "google_container_analysis_note.note",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
func TestAccContainerAnalysisNote_update(t *testing.T) {
t.Parallel()
name := acctest.RandString(10)
readableName := acctest.RandString(10)
readableName2 := acctest.RandString(10)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckContainerAnalysisNoteDestroy,
Steps: []resource.TestStep{
{
Config: testAccContainerAnalysisNoteBasic(name, readableName),
},
{
ResourceName: "google_container_analysis_note.note",
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccContainerAnalysisNoteBasic(name, readableName2),
},
{
ResourceName: "google_container_analysis_note.note",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
func testAccCheckContainerAnalysisNoteDestroy(s *terraform.State) error {
config := testAccProvider.Meta().(*Config)
for _, rs := range s.RootModule().Resources {
if rs.Type != "google_container_analysis_note" {
continue
}
project, err := getTestProject(rs.Primary, config)
if err != nil {
return err
}
name := rs.Primary.Attributes["name"]
url := fmt.Sprintf("https://containeranalysis.googleapis.com/v1alpha1/projects/%s/notes/%s", project, name)
_, err = sendRequest(config, "GET", url, nil)
if err == nil {
return fmt.Errorf("Error, container analysis note %s still exists", name)
}
}
return nil
}
func testAccContainerAnalysisNoteBasic(name, readableName string) string {
return fmt.Sprintf(`
resource "google_container_analysis_note" "note" {
name = "tf-test-%s"
attestation_authority {
hint {
human_readable_name = "My Attestor %s"
}
}
}
`, name, readableName)
}

View File

@ -0,0 +1,158 @@
---
# ----------------------------------------------------------------------------
#
# *** 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
```hcl
resource "google_container_analysis_note" "note" {
name = "test-attestor-note"
attestation_authority {
hint {
human_readable_name = "Attestor Note"
}
}
}
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 = <<EOF
mQENBFtP0doBCADF+joTiXWKVuP8kJt3fgpBSjT9h8ezMfKA4aXZctYLx5wslWQl
bB7Iu2ezkECNzoEeU7WxUe8a61pMCh9cisS9H5mB2K2uM4Jnf8tgFeXn3akJDVo0
oR1IC+Dp9mXbRSK3MAvKkOwWlG99sx3uEdvmeBRHBOO+grchLx24EThXFOyP9Fk6
V39j6xMjw4aggLD15B4V0v9JqBDdJiIYFzszZDL6pJwZrzcP0z8JO4rTZd+f64bD
Mpj52j/pQfA8lZHOaAgb1OrthLdMrBAjoDjArV4Ek7vSbrcgYWcI6BhsQrFoxKdX
83TZKai55ZCfCLIskwUIzA1NLVwyzCS+fSN/ABEBAAG0KCJUZXN0IEF0dGVzdG9y
IiA8ZGFuYWhvZmZtYW5AZ29vZ2xlLmNvbT6JAU4EEwEIADgWIQRfWkqHt6hpTA1L
uY060eeM4dc66AUCW0/R2gIbLwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRA6
0eeM4dc66HdpCAC4ot3b0OyxPb0Ip+WT2U0PbpTBPJklesuwpIrM4Lh0N+1nVRLC
51WSmVbM8BiAFhLbN9LpdHhds1kUrHF7+wWAjdR8sqAj9otc6HGRM/3qfa2qgh+U
WTEk/3us/rYSi7T7TkMuutRMIa1IkR13uKiW56csEMnbOQpn9rDqwIr5R8nlZP5h
MAU9vdm1DIv567meMqTaVZgR3w7bck2P49AO8lO5ERFpVkErtu/98y+rUy9d789l
+OPuS1NGnxI1YKsNaWJF4uJVuvQuZ1twrhCbGNtVorO2U12+cEq+YtUxj7kmdOC1
qoIRW6y0+UlAc+MbqfL0ziHDOAmcqz1GnROg
=6Bvm
EOF
}
}
}
```
## Argument Reference
The following arguments are supported:
* `name` -
(Required)
The resource name.
* `attestation_authority_note` -
(Required)
A Container Analysis ATTESTATION_AUTHORITY Note, created by the user. Structure is documented below.
The `attestation_authority_note` block supports:
* `note_reference` -
(Required)
The resource name of a ATTESTATION_AUTHORITY Note, created by the
user. If the Note is in a different project from the Attestor, it
should be specified in the format `projects/*/notes/*` (or the legacy
`providers/*/notes/*`). This field may not be updated.
An attestation by this attestor is stored as a Container Analysis
ATTESTATION_AUTHORITY Occurrence that names a container image
and that links to this Note.
* `public_keys` -
(Optional)
Public keys that verify attestations signed by this attestor. This
field may be updated.
If this field is non-empty, one of the specified public keys must
verify that an attestation was signed by this attestor for the
image specified in the admission request.
If this field is empty, this attestor always returns that no valid
attestations exist. Structure is documented below.
* `delegation_service_account_email` -
This field will contain the service account email address that
this Attestor will use as the principal when querying Container
Analysis. Attestor administrators must grant this service account
the IAM role needed to read attestations from the noteReference in
Container Analysis (containeranalysis.notes.occurrences.viewer).
This email address is fixed for the lifetime of the Attestor, but
callers should not make any other assumptions about the service
account email; future versions may use an email based on a
different naming pattern.
The `public_keys` block supports:
* `comment` -
(Optional)
A descriptive comment. This field may be updated.
* `id` -
This field will be overwritten with key ID information, for
example, an identifier extracted from a PGP public key. This
field may not be updated.
* `ascii_armored_pgp_public_key` -
(Required)
ASCII-armored representation of a PGP public key, as the
entire output by the command
`gpg --export --armor foo@example.com` (either LF or CRLF
line endings).
- - -
* `description` -
(Optional)
A descriptive comment. This field may be updated. The field may be
displayed in chooser dialogs.
* `project` - (Optional) The ID of the project in which the resource belongs.
If it is not provided, the provider project is used.
## Import
Attestor can be imported using any of these accepted formats:
```
$ terraform import google_binary_authorization_attestor.default projects/{{project}}/attestors/{{name}}
$ terraform import google_binary_authorization_attestor.default {{project}}/{{name}}
$ terraform import google_binary_authorization_attestor.default {{name}}
```

View File

@ -0,0 +1,165 @@
---
# ----------------------------------------------------------------------------
#
# *** 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
```hcl
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}"
}
}
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}"]
}
}
```
## 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)
Admission policy whitelisting. A matching admission request will
always be permitted. This feature is typically used to exclude Google
or third-party infrastructure images from Binary Authorization
policies. Structure is documented below.
* `cluster_admission_rules` -
(Optional)
Admission policy whitelisting. A matching admission request will
always be permitted. This feature is typically used to exclude Google
or third-party infrastructure images from Binary Authorization
policies.
* `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:
* `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.
## 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}}
```

View File

@ -84,6 +84,7 @@ The following arguments are supported:
following characters must be a dash, lowercase letter, or digit,
except the last character, which cannot be a dash.
- - -

View File

@ -114,6 +114,8 @@ The following arguments are supported:
* `target` -
(Required)
URL of the managed instance group that this autoscaler will scale.
The `autoscaling_policy` block supports:
* `min_replicas` -
@ -157,7 +159,9 @@ The `autoscaling_policy` block supports:
* `load_balancing_utilization` -
(Optional)
Configuration parameters of autoscaling based on a load balancer. Structure is documented below.
The `cpu_utilization` block supports:
The `cpu_utilization` block supports:
* `target` -
(Required)
@ -172,8 +176,8 @@ The `autoscaling_policy` block supports:
scales up until it reaches the maximum number of instances you
specified or until the average utilization reaches the target
utilization.
The `metric` block supports:
The `metric` block supports:
* `name` -
(Required)
@ -197,15 +201,14 @@ The `autoscaling_policy` block supports:
Defines how target utilization value is expressed for a
Stackdriver Monitoring metric. Either GAUGE, DELTA_PER_SECOND,
or DELTA_PER_MINUTE.
The `load_balancing_utilization` block supports:
The `load_balancing_utilization` block supports:
* `target` -
(Required)
Fraction of backend capacity utilization (set in HTTP(s) load
balancing configuration) that autoscaler should maintain. Must
be a positive float value. If not defined, the default is 0.8.
- - -

View File

@ -71,6 +71,7 @@ The following arguments are supported:
characters must be a dash, lowercase letter, or digit, except the
last character, which cannot be a dash.
- - -

View File

@ -77,6 +77,7 @@ The following arguments are supported:
characters must be a dash, lowercase letter, or digit, except the last
character, which cannot be a dash.
- - -
@ -155,6 +156,7 @@ The following arguments are supported:
* `project` - (Optional) The ID of the project in which the resource belongs.
If it is not provided, the provider project is used.
The `source_image_encryption_key` block supports:
* `raw_key` -
@ -165,7 +167,7 @@ The `source_image_encryption_key` block supports:
* `sha256` -
The RFC 4648 base64 encoded SHA-256 hash of the customer-supplied
encryption key that protects this resource.
The `disk_encryption_key` block supports:
* `raw_key` -
@ -176,7 +178,7 @@ The `disk_encryption_key` block supports:
* `sha256` -
The RFC 4648 base64 encoded SHA-256 hash of the customer-supplied
encryption key that protects this resource.
The `source_snapshot_encryption_key` block supports:
* `raw_key` -
@ -187,7 +189,6 @@ The `source_snapshot_encryption_key` block supports:
* `sha256` -
The RFC 4648 base64 encoded SHA-256 hash of the customer-supplied
encryption key that protects this resource.
* (Deprecated) `disk_encryption_key_raw`: This is an alias for
`disk_encryption_key.raw_key`. It is deprecated to enhance

View File

@ -56,6 +56,7 @@ The following arguments are supported:
characters must be a dash, lowercase letter, or digit, except the last
character, which cannot be a dash.
- - -

View File

@ -53,6 +53,7 @@ The following arguments are supported:
characters must be a dash, lowercase letter, or digit, except the last
character, which cannot be a dash.
- - -

View File

@ -64,6 +64,7 @@ The following arguments are supported:
characters must be a dash, lowercase letter, or digit, except the
last character, which cannot be a dash.
- - -

View File

@ -64,6 +64,7 @@ The following arguments are supported:
characters must be a dash, lowercase letter, or digit, except the
last character, which cannot be a dash.
- - -

View File

@ -114,6 +114,8 @@ The following arguments are supported:
* `target` -
(Required)
URL of the managed instance group that this autoscaler will scale.
The `autoscaling_policy` block supports:
* `min_replicas` -
@ -157,7 +159,9 @@ The `autoscaling_policy` block supports:
* `load_balancing_utilization` -
(Optional)
Configuration parameters of autoscaling based on a load balancer. Structure is documented below.
The `cpu_utilization` block supports:
The `cpu_utilization` block supports:
* `target` -
(Required)
@ -172,8 +176,8 @@ The `autoscaling_policy` block supports:
scales up until it reaches the maximum number of instances you
specified or until the average utilization reaches the target
utilization.
The `metric` block supports:
The `metric` block supports:
* `name` -
(Required)
@ -197,15 +201,14 @@ The `autoscaling_policy` block supports:
Defines how target utilization value is expressed for a
Stackdriver Monitoring metric. Either GAUGE, DELTA_PER_SECOND,
or DELTA_PER_MINUTE.
The `load_balancing_utilization` block supports:
The `load_balancing_utilization` block supports:
* `target` -
(Required)
Fraction of backend capacity utilization (set in HTTP(s) load
balancing configuration) that autoscaler should maintain. Must
be a positive float value. If not defined, the default is 0.8.
- - -

View File

@ -94,6 +94,7 @@ The following arguments are supported:
(Required)
URLs of the zones where the disk should be replicated to.
- - -
@ -155,6 +156,7 @@ The following arguments are supported:
* `project` - (Optional) The ID of the project in which the resource belongs.
If it is not provided, the provider project is used.
The `disk_encryption_key` block supports:
* `raw_key` -
@ -165,7 +167,7 @@ The `disk_encryption_key` block supports:
* `sha256` -
The RFC 4648 base64 encoded SHA-256 hash of the customer-supplied
encryption key that protects this resource.
The `source_snapshot_encryption_key` block supports:
* `raw_key` -
@ -176,7 +178,6 @@ The `source_snapshot_encryption_key` block supports:
* `sha256` -
The RFC 4648 base64 encoded SHA-256 hash of the customer-supplied
encryption key that protects this resource.
## Attributes Reference

View File

@ -96,6 +96,7 @@ The following arguments are supported:
(Required)
The network that this route applies to.
- - -

View File

@ -72,6 +72,7 @@ The following arguments are supported:
(Required)
A reference to the network to which this router belongs.
- - -
@ -89,6 +90,7 @@ The following arguments are supported:
* `project` - (Optional) The ID of the project in which the resource belongs.
If it is not provided, the provider project is used.
The `bgp` block supports:
* `asn` -
@ -119,7 +121,9 @@ The `bgp` block supports:
is CUSTOM and is advertised to all peers of the router. These IP
ranges will be advertised in addition to any specified groups.
Leave this field blank to advertise no custom IP ranges. Structure is documented below.
The `advertised_ip_ranges` block supports:
The `advertised_ip_ranges` block supports:
* `range` -
(Optional)
@ -129,7 +133,6 @@ The `bgp` block supports:
* `description` -
(Optional)
User-specified description for the IP range.
## Attributes Reference

View File

@ -67,6 +67,7 @@ The following arguments are supported:
characters must be a dash, lowercase letter, or digit, except the last
character, which cannot be a dash.
- - -

View File

@ -99,6 +99,7 @@ The following arguments are supported:
The network this subnet belongs to.
Only networks that are in the distributed mode can have subnetworks.
- - -
@ -130,6 +131,7 @@ The following arguments are supported:
* `project` - (Optional) The ID of the project in which the resource belongs.
If it is not provided, the provider project is used.
The `secondary_ip_range` block supports:
* `range_name` -
@ -145,7 +147,6 @@ The `secondary_ip_range` block supports:
range. Provide this property when you create the subnetwork.
Ranges must be unique and non-overlapping with all primary and
secondary IP ranges within a network. Only IPv4 is supported.
## Attributes Reference

View File

@ -99,6 +99,7 @@ The following arguments are supported:
A reference to the UrlMap resource that defines the mapping from URL
to the BackendService.
- - -

View File

@ -113,6 +113,7 @@ The following arguments are supported:
A reference to the UrlMap resource that defines the mapping from URL
to the BackendService.
- - -

View File

@ -89,6 +89,7 @@ The following arguments are supported:
connections between users and the load balancer. Currently, exactly
one SSL certificate must be specified.
- - -

View File

@ -80,6 +80,7 @@ The following arguments are supported:
(Required)
A reference to the BackendService resource.
- - -

View File

@ -117,6 +117,7 @@ The following arguments are supported:
(Required)
The network this VPN gateway is accepting traffic for.
- - -

View File

@ -138,6 +138,7 @@ The following arguments are supported:
Shared secret used to set the secure session between the Cloud VPN
gateway and the peer VPN gateway.
- - -

View File

@ -0,0 +1,104 @@
---
# ----------------------------------------------------------------------------
#
# *** 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_container_analysis_note"
sidebar_current: "docs-google-container-analysis-note"
description: |-
Provides a detailed description of a Note.
---
# google\_container\_analysis\_note
Provides a detailed description of a Note.
To get more information about Note, see:
* [API documentation](https://cloud.google.com/container-analysis/api/reference/rest/)
* How-to Guides
* [Official Documentation](https://cloud.google.com/container-analysis/)
## Example Usage
```hcl
resource "google_container_analysis_note" "note" {
name = "test-attestor-note"
attestation_authority {
hint {
human_readable_name = "Attestor Note"
}
}
}
```
## Argument Reference
The following arguments are supported:
* `name` -
(Required)
The name of the note.
* `attestation_authority` -
(Required)
Note kind that represents a logical attestation "role" or "authority".
For example, an organization might have one AttestationAuthority for
"QA" and one for "build". This Note is intended to act strictly as a
grouping mechanism for the attached Occurrences (Attestations). This
grouping mechanism also provides a security boundary, since IAM ACLs
gate the ability for a principle to attach an Occurrence to a given
Note. It also provides a single point of lookup to find all attached
Attestation Occurrences, even if they don't all live in the same
project. Structure is documented below.
The `attestation_authority` block supports:
* `hint` -
(Required)
This submessage provides human-readable hints about the purpose of
the AttestationAuthority. Because the name of a Note acts as its
resource reference, it is important to disambiguate the canonical
name of the Note (which might be a UUID for security purposes)
from "readable" names more suitable for debug output. Note that
these hints should NOT be used to look up AttestationAuthorities
in security sensitive contexts, such as when looking up
Attestations to verify. Structure is documented below.
The `hint` block supports:
* `human_readable_name` -
(Required)
The human readable name of this Attestation Authority, for
example "qa".
- - -
* `project` - (Optional) The ID of the project in which the resource belongs.
If it is not provided, the provider project is used.
## Import
Note can be imported using any of these accepted formats:
```
$ terraform import google_container_analysis_note.default projects/{{project}}/notes/{{name}}
$ terraform import google_container_analysis_note.default {{project}}/{{name}}
$ terraform import google_container_analysis_note.default {{name}}
```

View File

@ -80,6 +80,7 @@ The following arguments are supported:
(Required)
Redis memory size in GiB.
- - -

View File

@ -13,13 +13,13 @@
#
# ----------------------------------------------------------------------------
layout: "google"
page_title: "Google: google_resourcemanager_lien"
sidebar_current: "docs-google-resourcemanager-lien"
page_title: "Google: google_resource_manager_lien"
sidebar_current: "docs-google-resource-manager-lien"
description: |-
A Lien represents an encumbrance on the actions that can be performed on a resource.
---
# google\_resourcemanager\_lien
# google\_resource\_manager\_lien
A Lien represents an encumbrance on the actions that can be performed on a resource.
@ -75,6 +75,7 @@ The following arguments are supported:
list is meaningless and will be rejected.
e.g. ['resourcemanager.projects.delete']
- - -
@ -97,5 +98,5 @@ In addition to the arguments listed above, the following computed attributes are
Lien can be imported using any of these accepted formats:
```
$ terraform import google_resourcemanager_lien.default {{parent}}/{{name}}
$ terraform import google_resource_manager_lien.default {{parent}}/{{name}}
```

View File

@ -143,6 +143,17 @@
</ul>
</li>
<li<%= sidebar_current("docs-google-binary-authorization") %>>
<a href="#">Google Binary Authorization Resources</a>
<ul class="nav nav-visible">
<li<%= sidebar_current("docs-google-binary-authorization-attestor") %>>
<a href="/docs/providers/google/r/binaryauthorization_attestor.html">google_binary_authorization_attestor</a>
<li<%= sidebar_current("docs-google-binary-authorization-policy") %>>
<a href="/docs/providers/google/r/binaryauthorization_policy.html">google_binary_authorization_policy</a>
</li>
</ul>
</li>
<li<%= sidebar_current("docs-google-cloudbuild") %>>
<a href="#">Google Cloud Build Resources</a>
<ul class="nav nav-visible">
@ -221,8 +232,8 @@
<li<%= sidebar_current("docs-google-project-usage-export-bucket") %>>
<a href="/docs/providers/google/r/usage_export_bucket.html">google_project_usage_export_bucket</a>
</li>
<li<%= sidebar_current("docs-google-resourcemanager-lien") %>>
<a href="/docs/providers/google/r/resourcemanager_lien.html">google_resourcemanager_lien</a>
<li<%= sidebar_current("docs-google-resource-manager-lien") %>>
<a href="/docs/providers/google/r/resourcemanager_lien.html">google_resource_manager_lien</a>
</li>
<li<%= sidebar_current("docs-google-service-account-x") %>>
<a href="/docs/providers/google/r/google_service_account.html">google_service_account</a>
@ -440,6 +451,15 @@
</ul>
</li>
<li<%= sidebar_current("docs-google-container-analysis") %>>
<a href="#">Google Container Analysis Resources</a>
<ul class="nav nav-visible">
<li<%= sidebar_current("docs-google-container-analysis-note") %>>
<a href="/docs/providers/google/r/containeranalysis_note.html">google_container_analysis_note</a>
</li>
</ul>
</li>
<li<%= sidebar_current("docs-google-container") %>>
<a href="#">Google Kubernetes (Container) Engine Resources</a>
<ul class="nav nav-visible">