Skip to content

Commit

Permalink
BigQuery Dataset default CMEK encryption
Browse files Browse the repository at this point in the history
Signed-off-by: Modular Magician <[email protected]>
  • Loading branch information
drebes authored and modular-magician committed Aug 21, 2019
1 parent 24c3610 commit fc2d55d
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 0 deletions.
68 changes: 68 additions & 0 deletions google/resource_big_query_dataset.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,19 @@ func resourceBigQueryDataset() *schema.Resource {
Elem: bigqueryDatasetAccessSchema(),
// Default schema.HashSchema is used.
},
"default_encryption_configuration": {
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"kms_key_name": {
Type: schema.TypeString,
Required: true,
},
},
},
},
"default_partition_expiration_ms": {
Type: schema.TypeInt,
Optional: true,
Expand Down Expand Up @@ -241,6 +254,12 @@ func resourceBigQueryDatasetCreate(d *schema.ResourceData, meta interface{}) err
} else if v, ok := d.GetOkExists("location"); !isEmptyValue(reflect.ValueOf(locationProp)) && (ok || !reflect.DeepEqual(v, locationProp)) {
obj["location"] = locationProp
}
defaultEncryptionConfigurationProp, err := expandBigQueryDatasetDefaultEncryptionConfiguration(d.Get("default_encryption_configuration"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("default_encryption_configuration"); !isEmptyValue(reflect.ValueOf(defaultEncryptionConfigurationProp)) && (ok || !reflect.DeepEqual(v, defaultEncryptionConfigurationProp)) {
obj["defaultEncryptionConfiguration"] = defaultEncryptionConfigurationProp
}

url, err := replaceVars(d, config, "{{BigQueryBasePath}}projects/{{project}}/datasets")
if err != nil {
Expand Down Expand Up @@ -335,6 +354,9 @@ func resourceBigQueryDatasetRead(d *schema.ResourceData, meta interface{}) error
if err := d.Set("location", flattenBigQueryDatasetLocation(res["location"], d)); err != nil {
return fmt.Errorf("Error reading Dataset: %s", err)
}
if err := d.Set("default_encryption_configuration", flattenBigQueryDatasetDefaultEncryptionConfiguration(res["defaultEncryptionConfiguration"], d)); err != nil {
return fmt.Errorf("Error reading Dataset: %s", err)
}
if err := d.Set("self_link", ConvertSelfLinkToV1(res["selfLink"].(string))); err != nil {
return fmt.Errorf("Error reading Dataset: %s", err)
}
Expand Down Expand Up @@ -399,6 +421,12 @@ func resourceBigQueryDatasetUpdate(d *schema.ResourceData, meta interface{}) err
} else if v, ok := d.GetOkExists("location"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, locationProp)) {
obj["location"] = locationProp
}
defaultEncryptionConfigurationProp, err := expandBigQueryDatasetDefaultEncryptionConfiguration(d.Get("default_encryption_configuration"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("default_encryption_configuration"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, defaultEncryptionConfigurationProp)) {
obj["defaultEncryptionConfiguration"] = defaultEncryptionConfigurationProp
}

url, err := replaceVars(d, config, "{{BigQueryBasePath}}projects/{{project}}/datasets/{{dataset_id}}")
if err != nil {
Expand Down Expand Up @@ -618,6 +646,23 @@ func flattenBigQueryDatasetLocation(v interface{}, d *schema.ResourceData) inter
return v
}

func flattenBigQueryDatasetDefaultEncryptionConfiguration(v interface{}, d *schema.ResourceData) interface{} {
if v == nil {
return nil
}
original := v.(map[string]interface{})
if len(original) == 0 {
return nil
}
transformed := make(map[string]interface{})
transformed["kms_key_name"] =
flattenBigQueryDatasetDefaultEncryptionConfigurationKmsKeyName(original["kmsKeyName"], d)
return []interface{}{transformed}
}
func flattenBigQueryDatasetDefaultEncryptionConfigurationKmsKeyName(v interface{}, d *schema.ResourceData) interface{} {
return v
}

func expandBigQueryDatasetAccess(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
v = v.(*schema.Set).List()
l := v.([]interface{})
Expand Down Expand Up @@ -787,3 +832,26 @@ func expandBigQueryDatasetLabels(v interface{}, d TerraformResourceData, config
func expandBigQueryDatasetLocation(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
return v, nil
}

func expandBigQueryDatasetDefaultEncryptionConfiguration(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
l := v.([]interface{})
if len(l) == 0 || l[0] == nil {
return nil, nil
}
raw := l[0]
original := raw.(map[string]interface{})
transformed := make(map[string]interface{})

transformedKmsKeyName, err := expandBigQueryDatasetDefaultEncryptionConfigurationKmsKeyName(original["kms_key_name"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedKmsKeyName); val.IsValid() && !isEmptyValue(val) {
transformed["kmsKeyName"] = transformedKmsKeyName
}

return transformed, nil
}

func expandBigQueryDatasetDefaultEncryptionConfigurationKmsKeyName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
return v, nil
}
51 changes: 51 additions & 0 deletions google/resource_big_query_dataset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,29 @@ func TestAccBigQueryDataset_regionalLocation(t *testing.T) {
})
}

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

kms := BootstrapKMSKeyInLocation(t, "us")
pid := getTestProjectFromEnv()
datasetID1 := fmt.Sprintf("tf_test_%s", acctest.RandString(10))

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccBigQueryDataset_cmek(pid, datasetID1, kms.CryptoKey.Name),
},
{
ResourceName: "google_bigquery_dataset.test",
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func testAccAddTable(datasetID string, tableID string) resource.TestCheckFunc {
// Not actually a check, but adds a table independently of terraform
return func(s *terraform.State) error {
Expand Down Expand Up @@ -303,3 +326,31 @@ resource "google_bigquery_dataset" "access_test" {
}
}`, otherDatasetID, otherTableID, datasetID)
}

func testAccBigQueryDataset_cmek(pid, datasetID, kmsKey string) string {
return fmt.Sprintf(`
data "google_project" "project" {
project_id = "%s"
}
resource "google_project_iam_member" "kms-project-binding" {
project = "${data.google_project.project.project_id}"
role = "roles/cloudkms.cryptoKeyEncrypterDecrypter"
member = "serviceAccount:bq-${data.google_project.project.number}@bigquery-encryption.iam.gserviceaccount.com"
}
resource "google_bigquery_dataset" "test" {
dataset_id = "%s"
friendly_name = "test"
description = "This is a test description"
location = "US"
default_table_expiration_ms = 3600000
default_encryption_configuration {
kms_key_name = "%s"
}
project = "${google_project_iam_member.kms-project-binding.project}"
}
`, pid, datasetID, kmsKey)
}
40 changes: 40 additions & 0 deletions website/docs/r/big_query_dataset.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,32 @@ resource "google_bigquery_dataset" "dataset" {
}
}
```
## Example Usage - Bigquery Dataset Cmek


```hcl
resource "google_bigquery_dataset" "dataset" {
dataset_id = "example_dataset"
friendly_name = "test"
description = "This is a test description"
location = "US"
default_table_expiration_ms = 3600000
default_encryption_configuration {
kms_key_name = "${google_kms_crypto_key.crypto_key.self_link}"
}
}
resource "google_kms_crypto_key" "crypto_key" {
name = "example-key"
key_ring = "${google_kms_key_ring.key_ring.self_link}"
}
resource "google_kms_key_ring" "key_ring" {
name = "example-keyring"
location = "us"
}
```

## Argument Reference

Expand Down Expand Up @@ -139,6 +165,12 @@ The following arguments are supported:
The default value is multi-regional location `US`.
Changing this forces a new resource to be created.

* `default_encryption_configuration` -
(Optional)
The default encryption key for all tables in the dataset. Once this property is set,
all newly-created partitioned tables in the dataset will have encryption key set to
this value, unless table creation request (or query) overrides the key. Structure is documented below.

* `project` - (Optional) The ID of the project in which the resource belongs.
If it is not provided, the provider project is used.

Expand Down Expand Up @@ -210,6 +242,14 @@ The `view` block supports:
A-Z), numbers (0-9), or underscores (_). The maximum length
is 1,024 characters.

The `default_encryption_configuration` block supports:

* `kms_key_name` -
(Required)
Describes the Cloud KMS encryption key that will be used to protect destination
BigQuery table. The BigQuery Service Account associated with your project requires
access to this encryption key.

## Attributes Reference

In addition to the arguments listed above, the following computed attributes are exported:
Expand Down

0 comments on commit fc2d55d

Please sign in to comment.