mirror of
https://github.com/letic/terraform-provider-google.git
synced 2024-07-05 17:52:38 +00:00
Add support for bucket encryption (#1876)
* Support encryption in Storage bucket. * Add self links to crypto keys and key ring ids * Update ID documentation to talk about self link instead.
This commit is contained in:
parent
503e029f4f
commit
d77c0adbb2
|
@ -39,6 +39,10 @@ func resourceKmsCryptoKey() *schema.Resource {
|
|||
Optional: true,
|
||||
ValidateFunc: validateKmsCryptoKeyRotationPeriod,
|
||||
},
|
||||
"self_link": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -163,6 +167,7 @@ func resourceKmsCryptoKeyRead(d *schema.ResourceData, meta interface{}) error {
|
|||
d.Set("key_ring", cryptoKeyId.KeyRingId.terraformId())
|
||||
d.Set("name", cryptoKeyId.Name)
|
||||
d.Set("rotation_period", cryptoKey.RotationPeriod)
|
||||
d.Set("self_link", cryptoKey.Name)
|
||||
|
||||
d.SetId(cryptoKeyId.cryptoKeyId())
|
||||
|
||||
|
|
|
@ -345,7 +345,7 @@ resource "google_kms_key_ring" "key_ring" {
|
|||
|
||||
resource "google_kms_crypto_key" "crypto_key" {
|
||||
name = "%s"
|
||||
key_ring = "${google_kms_key_ring.key_ring.id}"
|
||||
key_ring = "${google_kms_key_ring.key_ring.self_link}"
|
||||
rotation_period = "1000000s"
|
||||
}
|
||||
`, projectId, projectId, projectOrg, projectBillingAccount, keyRingName, cryptoKeyName)
|
||||
|
@ -376,7 +376,7 @@ resource "google_kms_key_ring" "key_ring" {
|
|||
|
||||
resource "google_kms_crypto_key" "crypto_key" {
|
||||
name = "%s"
|
||||
key_ring = "${google_kms_key_ring.key_ring.id}"
|
||||
key_ring = "${google_kms_key_ring.key_ring.self_link}"
|
||||
rotation_period = "%s"
|
||||
}
|
||||
`, projectId, projectId, projectOrg, projectBillingAccount, keyRingName, cryptoKeyName, rotationPeriod)
|
||||
|
@ -407,7 +407,7 @@ resource "google_kms_key_ring" "key_ring" {
|
|||
|
||||
resource "google_kms_crypto_key" "crypto_key" {
|
||||
name = "%s"
|
||||
key_ring = "${google_kms_key_ring.key_ring.id}"
|
||||
key_ring = "${google_kms_key_ring.key_ring.self_link}"
|
||||
}
|
||||
`, projectId, projectId, projectOrg, projectBillingAccount, keyRingName, cryptoKeyName)
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"log"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"google.golang.org/api/cloudkms/v1"
|
||||
|
@ -36,6 +37,10 @@ func resourceKmsKeyRing() *schema.Resource {
|
|||
Computed: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"self_link": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -72,16 +77,27 @@ func resourceKmsKeyRingCreate(d *schema.ResourceData, meta interface{}) error {
|
|||
Name: d.Get("name").(string),
|
||||
}
|
||||
|
||||
keyRing, err := config.clientKms.Projects.Locations.KeyRings.Create(keyRingId.parentId(), &cloudkms.KeyRing{}).KeyRingId(keyRingId.Name).Do()
|
||||
// This resource is often created just after a project, and requires
|
||||
// billing support, which is eventually consistent. We attempt to
|
||||
// wait on billing support in the project resource, but we can't
|
||||
// always get it right - this retry fixes a lot of flaky tests we were
|
||||
// noticing.
|
||||
err = retryTimeDuration(func() error {
|
||||
keyRing, err := config.clientKms.Projects.Locations.KeyRings.Create(keyRingId.parentId(), &cloudkms.KeyRing{}).KeyRingId(keyRingId.Name).Do()
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating KeyRing: %s", err)
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Created KeyRing %s", keyRing.Name)
|
||||
|
||||
d.SetId(keyRingId.keyRingId())
|
||||
return nil
|
||||
}, time.Duration(30*time.Second))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating KeyRing: %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Created KeyRing %s", keyRing.Name)
|
||||
|
||||
d.SetId(keyRingId.keyRingId())
|
||||
|
||||
return resourceKmsKeyRingRead(d, meta)
|
||||
}
|
||||
|
||||
|
@ -100,13 +116,14 @@ func resourceKmsKeyRingRead(d *schema.ResourceData, meta interface{}) error {
|
|||
|
||||
log.Printf("[DEBUG] Executing read for KMS KeyRing %s", keyRingId.keyRingId())
|
||||
|
||||
_, err = config.clientKms.Projects.Locations.KeyRings.Get(keyRingId.keyRingId()).Do()
|
||||
keyRing, err := config.clientKms.Projects.Locations.KeyRings.Get(keyRingId.keyRingId()).Do()
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error reading KeyRing: %s", err)
|
||||
}
|
||||
|
||||
d.Set("project", project)
|
||||
d.Set("self_link", keyRing.Name)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -34,6 +34,20 @@ func resourceStorageBucket() *schema.Resource {
|
|||
ForceNew: true,
|
||||
},
|
||||
|
||||
"encryption": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
MaxItems: 1,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"default_kms_key_name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"force_destroy": &schema.Schema{
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
|
@ -244,11 +258,11 @@ func resourceStorageBucketCreate(d *schema.ResourceData, meta interface{}) error
|
|||
return err
|
||||
}
|
||||
|
||||
// Get the bucket and acl
|
||||
// Get the bucket and location
|
||||
bucket := d.Get("name").(string)
|
||||
location := d.Get("location").(string)
|
||||
|
||||
// Create a bucket, setting the acl, location and name.
|
||||
// Create a bucket, setting the labels, location and name.
|
||||
sb := &storage.Bucket{
|
||||
Name: bucket,
|
||||
Labels: expandLabels(d),
|
||||
|
@ -295,6 +309,10 @@ func resourceStorageBucketCreate(d *schema.ResourceData, meta interface{}) error
|
|||
sb.Logging = expandBucketLogging(v.([]interface{}))
|
||||
}
|
||||
|
||||
if v, ok := d.GetOk("encryption"); ok {
|
||||
sb.Encryption = expandBucketEncryption(v.([]interface{}))
|
||||
}
|
||||
|
||||
var res *storage.Bucket
|
||||
|
||||
err = retry(func() error {
|
||||
|
@ -373,6 +391,14 @@ func resourceStorageBucketUpdate(d *schema.ResourceData, meta interface{}) error
|
|||
}
|
||||
}
|
||||
|
||||
if d.HasChange("encryption") {
|
||||
if v, ok := d.GetOk("encryption"); ok {
|
||||
sb.Encryption = expandBucketEncryption(v.([]interface{}))
|
||||
} else {
|
||||
sb.NullFields = append(sb.NullFields, "Encryption")
|
||||
}
|
||||
}
|
||||
|
||||
if d.HasChange("labels") {
|
||||
sb.Labels = expandLabels(d)
|
||||
if len(sb.Labels) == 0 {
|
||||
|
@ -438,6 +464,7 @@ func resourceStorageBucketRead(d *schema.ResourceData, meta interface{}) error {
|
|||
d.Set("self_link", res.SelfLink)
|
||||
d.Set("url", fmt.Sprintf("gs://%s", bucket))
|
||||
d.Set("storage_class", res.StorageClass)
|
||||
d.Set("encryption", flattenBucketEncryption(res.Encryption))
|
||||
d.Set("location", res.Location)
|
||||
d.Set("cors", flattenCors(res.Cors))
|
||||
d.Set("logging", flattenBucketLogging(res.Logging))
|
||||
|
@ -542,6 +569,29 @@ func flattenCors(corsRules []*storage.BucketCors) []map[string]interface{} {
|
|||
return corsRulesSchema
|
||||
}
|
||||
|
||||
func expandBucketEncryption(configured interface{}) *storage.BucketEncryption {
|
||||
encs := configured.([]interface{})
|
||||
enc := encs[0].(map[string]interface{})
|
||||
bucketenc := &storage.BucketEncryption{
|
||||
DefaultKmsKeyName: enc["default_kms_key_name"].(string),
|
||||
}
|
||||
return bucketenc
|
||||
}
|
||||
|
||||
func flattenBucketEncryption(enc *storage.BucketEncryption) []map[string]interface{} {
|
||||
encryption := make([]map[string]interface{}, 0, 1)
|
||||
|
||||
if enc == nil {
|
||||
return encryption
|
||||
}
|
||||
|
||||
encryption = append(encryption, map[string]interface{}{
|
||||
"default_kms_key_name": enc.DefaultKmsKeyName,
|
||||
})
|
||||
|
||||
return encryption
|
||||
}
|
||||
|
||||
func expandBucketLogging(configured interface{}) *storage.BucketLogging {
|
||||
loggings := configured.([]interface{})
|
||||
logging := loggings[0].(map[string]interface{})
|
||||
|
|
|
@ -547,6 +547,33 @@ func TestAccStorageBucket_cors(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestAccStorageBucket_encryption(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
projectId := "terraform-" + acctest.RandString(10)
|
||||
projectOrg := getTestOrgFromEnv(t)
|
||||
projectBillingAccount := getTestBillingAccountFromEnv(t)
|
||||
keyRingName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
|
||||
cryptoKeyName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
|
||||
bucketName := fmt.Sprintf("tf-test-crypto-bucket-%d", acctest.RandInt())
|
||||
var bucket storage.Bucket
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccStorageBucket_encryption(projectId, projectOrg, projectBillingAccount, keyRingName, cryptoKeyName, bucketName),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckGoogleKmsCryptoKeyExists("google_kms_crypto_key.crypto_key"),
|
||||
testAccCheckStorageBucketExists(
|
||||
"google_storage_bucket.bucket", bucketName, &bucket),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccStorageBucket_labels(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
@ -902,6 +929,44 @@ resource "google_storage_bucket" "bucket" {
|
|||
`, bucketName)
|
||||
}
|
||||
|
||||
func testAccStorageBucket_encryption(projectId, projectOrg, projectBillingAccount, keyRingName, cryptoKeyName, bucketName string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "google_project" "acceptance" {
|
||||
name = "%s"
|
||||
project_id = "%s"
|
||||
org_id = "%s"
|
||||
billing_account = "%s"
|
||||
}
|
||||
|
||||
resource "google_project_services" "acceptance" {
|
||||
project = "${google_project.acceptance.project_id}"
|
||||
|
||||
services = [
|
||||
"cloudkms.googleapis.com",
|
||||
]
|
||||
}
|
||||
|
||||
resource "google_kms_key_ring" "key_ring" {
|
||||
project = "${google_project_services.acceptance.project}"
|
||||
name = "%s"
|
||||
location = "us"
|
||||
}
|
||||
|
||||
resource "google_kms_crypto_key" "crypto_key" {
|
||||
name = "%s"
|
||||
key_ring = "${google_kms_key_ring.key_ring.id}"
|
||||
rotation_period = "1000000s"
|
||||
}
|
||||
|
||||
resource "google_storage_bucket" "bucket" {
|
||||
name = "%s"
|
||||
encryption {
|
||||
default_kms_key_name = "${google_kms_crypto_key.crypto_key.self_link}"
|
||||
}
|
||||
}
|
||||
`, projectId, projectId, projectOrg, projectBillingAccount, keyRingName, cryptoKeyName, bucketName)
|
||||
}
|
||||
|
||||
func testAccStorageBucket_updateLabels(bucketName string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "google_storage_bucket" "bucket" {
|
||||
|
|
|
@ -30,7 +30,7 @@ resource "google_kms_key_ring" "my_key_ring" {
|
|||
|
||||
resource "google_kms_crypto_key" "my_crypto_key" {
|
||||
name = "my-crypto-key"
|
||||
key_ring = "${google_kms_key_ring.my_key_ring.id}"
|
||||
key_ring = "${google_kms_key_ring.my_key_ring.self_link}"
|
||||
rotation_period = "100000s"
|
||||
}
|
||||
```
|
||||
|
@ -56,7 +56,7 @@ The following arguments are supported:
|
|||
In addition to the arguments listed above, the following computed attributes are
|
||||
exported:
|
||||
|
||||
* `id` - The ID of the created CryptoKey. Its format is `{projectId}/{location}/{keyRingName}/{cryptoKeyName}`.
|
||||
* `self_link` - The self link of the created CryptoKey. Its format is `projects/{projectId}/locations/{location}/keyRings/{keyRingName}/cryptoKeys/{cryptoKeyName}`.
|
||||
|
||||
## Import
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ The following arguments are supported:
|
|||
In addition to the arguments listed above, the following computed attributes are
|
||||
exported:
|
||||
|
||||
* `id` - The ID of the created KeyRing. Its format is `{projectId}/{location}/{keyRingName}`.
|
||||
* `self_link` - The self link of the created KeyRing. Its format is `projects/{projectId}/locations/{location}/keyRings/{keyRingName}`.
|
||||
|
||||
## Import
|
||||
|
||||
|
|
|
@ -64,6 +64,8 @@ The following arguments are supported:
|
|||
|
||||
* `logging` - (Optional) The bucket's [Access & Storage Logs](https://cloud.google.com/storage/docs/access-logs) configuration.
|
||||
|
||||
* `encryption` - (Optional) The bucket's encryption configuration.
|
||||
|
||||
The `lifecycle_rule` block supports:
|
||||
|
||||
* `action` - (Required) The Lifecycle Rule's action configuration. A single block of this type is supported. Structure is documented below.
|
||||
|
@ -117,6 +119,12 @@ The `logging` block supports:
|
|||
* `log_object_prefix` - (Optional, Computed) The object prefix for log objects. If it's not provided,
|
||||
by default GCS sets this to the log_bucket's name.
|
||||
|
||||
The `encryption` block supports:
|
||||
|
||||
* `default_kms_key_name`: A Cloud KMS key that will be used to encrypt objects inserted into this bucket, if no encryption method is specified.
|
||||
You must pay attention to whether the crypto key is available in the location that this bucket is created in.
|
||||
See [the docs](https://cloud.google.com/storage/docs/encryption/using-customer-managed-keys) for more details.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
In addition to the arguments listed above, the following computed attributes are
|
||||
|
|
Loading…
Reference in New Issue
Block a user