Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add EncryptionConfig to Cloud Composer's EnvironmentConfig #2967

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/4310.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
composer: added `encryption_config` to `google_composer_environment` resource (TPGB only)
```
51 changes: 51 additions & 0 deletions google-beta/resource_composer_environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ var (
"config.0.web_server_network_access_control",
"config.0.database_config",
"config.0.web_server_config",
"config.0.encryption_config",
}

allowedIpRangesConfig = &schema.Resource{
Expand Down Expand Up @@ -422,6 +423,24 @@ func resourceComposerEnvironment() *schema.Resource {
},
},
},
"encryption_config": {
Type: schema.TypeList,
Optional: true,
Computed: true,
AtLeastOneOf: composerConfigKeys,
MaxItems: 1,
Description: `The encryption options for the Composer environment and its dependencies.`,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"kms_key_name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: `Optional. Customer-managed Encryption Key available through Google's Key Management Service. Cannot be updated.`,
},
},
},
},
"airflow_uri": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -809,6 +828,7 @@ func flattenComposerEnvironmentConfig(envCfg *composer.EnvironmentConfig) interf
transformed["web_server_network_access_control"] = flattenComposerEnvironmentConfigWebServerNetworkAccessControl(envCfg.WebServerNetworkAccessControl)
transformed["database_config"] = flattenComposerEnvironmentConfigDatabaseConfig(envCfg.DatabaseConfig)
transformed["web_server_config"] = flattenComposerEnvironmentConfigWebServerConfig(envCfg.WebServerConfig)
transformed["encryption_config"] = flattenComposerEnvironmentConfigEncryptionConfig(envCfg.EncryptionConfig)

return []interface{}{transformed}
}
Expand Down Expand Up @@ -856,6 +876,17 @@ func flattenComposerEnvironmentConfigWebServerConfig(webServerCfg *composer.WebS
return []interface{}{transformed}
}

func flattenComposerEnvironmentConfigEncryptionConfig(encryptionCfg *composer.EncryptionConfig) interface{} {
if encryptionCfg == nil {
return nil
}

transformed := make(map[string]interface{})
transformed["kms_key_name"] = encryptionCfg.KmsKeyName

return []interface{}{transformed}
}

func flattenComposerEnvironmentConfigPrivateEnvironmentConfig(envCfg *composer.PrivateEnvironmentConfig) interface{} {
if envCfg == nil {
return nil
Expand Down Expand Up @@ -980,6 +1011,12 @@ func expandComposerEnvironmentConfig(v interface{}, d *schema.ResourceData, conf
}
transformed.WebServerConfig = transformedWebServerConfig

transformedEncryptionConfig, err := expandComposerEnvironmentConfigEncryptionConfig(original["encryption_config"], d, config)
if err != nil {
return nil, err
}
transformed.EncryptionConfig = transformedEncryptionConfig

return transformed, nil
}

Expand Down Expand Up @@ -1047,6 +1084,20 @@ func expandComposerEnvironmentConfigWebServerConfig(v interface{}, d *schema.Res
return transformed, nil
}

func expandComposerEnvironmentConfigEncryptionConfig(v interface{}, d *schema.ResourceData, config *Config) (*composer.EncryptionConfig, error) {
l := v.([]interface{})
if len(l) == 0 || l[0] == nil {
return nil, nil
}
raw := l[0]
original := raw.(map[string]interface{})

transformed := &composer.EncryptionConfig{}
transformed.KmsKeyName = original["kms_key_name"].(string)

return transformed, nil
}

func expandComposerEnvironmentConfigPrivateEnvironmentConfig(v interface{}, d *schema.ResourceData, config *Config) (*composer.PrivateEnvironmentConfig, error) {
l := v.([]interface{})
if len(l) == 0 {
Expand Down
101 changes: 101 additions & 0 deletions google-beta/resource_composer_environment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,41 @@ func TestAccComposerEnvironment_withWebServerConfig(t *testing.T) {
})
}

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

kms := BootstrapKMSKeyInLocation(t, "us-central1")
pid := getTestProjectFromEnv()
envName := fmt.Sprintf("%s-%d", testComposerEnvironmentPrefix, randInt(t))
network := fmt.Sprintf("%s-%d", testComposerNetworkPrefix, randInt(t))
subnetwork := network + "-1"

vcrTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccComposerEnvironmentDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccComposerEnvironment_encryptionCfg(pid, envName, kms.CryptoKey.Name, network, subnetwork),
},
{
ResourceName: "google_composer_environment.test",
ImportState: true,
ImportStateVerify: true,
},
// This is a terrible clean-up step in order to get destroy to succeed,
// due to dangling firewall rules left by the Composer Environment blocking network deletion.
// TODO(dzarmola): Remove this check if firewall rules bug gets fixed by Composer.
{
PlanOnly: true,
ExpectNonEmptyPlan: false,
Config: testAccComposerEnvironment_encryptionCfg(pid, envName, kms.CryptoKey.Name, network, subnetwork),
Check: testAccCheckClearComposerEnvironmentFirewalls(t, network),
},
},
})
}

// Checks behavior of node config, including dependencies on Compute resources.
func TestAccComposerEnvironment_withNodeConfig(t *testing.T) {
t.Parallel()
Expand Down Expand Up @@ -726,6 +761,72 @@ resource "google_compute_subnetwork" "test" {
`, name, network, subnetwork)
}

func testAccComposerEnvironment_encryptionCfg(pid, name, kmsKey, network, subnetwork string) string {
return fmt.Sprintf(`
data "google_project" "project" {
project_id = "%s"
}
resource "google_project_iam_member" "kms-project-binding1" {
project = data.google_project.project.project_id
role = "roles/cloudkms.cryptoKeyEncrypterDecrypter"
member = "serviceAccount:service-${data.google_project.project.number}@cloudcomposer-accounts.iam.gserviceaccount.com"
}
resource "google_project_iam_member" "kms-project-binding2" {
project = data.google_project.project.project_id
role = "roles/cloudkms.cryptoKeyEncrypterDecrypter"
member = "serviceAccount:service-${data.google_project.project.number}@compute-system.iam.gserviceaccount.com"
}
resource "google_project_iam_member" "kms-project-binding3" {
project = data.google_project.project.project_id
role = "roles/cloudkms.cryptoKeyEncrypterDecrypter"
member = "serviceAccount:service-${data.google_project.project.number}@container-engine-robot.iam.gserviceaccount.com"
}
resource "google_project_iam_member" "kms-project-binding4" {
project = data.google_project.project.project_id
role = "roles/cloudkms.cryptoKeyEncrypterDecrypter"
member = "serviceAccount:service-${data.google_project.project.number}@gcp-sa-artifactregistry.iam.gserviceaccount.com"
}
resource "google_project_iam_member" "kms-project-binding5" {
project = data.google_project.project.project_id
role = "roles/cloudkms.cryptoKeyEncrypterDecrypter"
member = "serviceAccount:service-${data.google_project.project.number}@gcp-sa-pubsub.iam.gserviceaccount.com"
}
resource "google_kms_crypto_key_iam_member" "iam" {
crypto_key_id = "%s"
role = "roles/cloudkms.cryptoKeyEncrypterDecrypter"
member = "serviceAccount:service-${data.google_project.project.number}@gs-project-accounts.iam.gserviceaccount.com"
}
resource "google_composer_environment" "test" {
depends_on = [google_project_iam_member.kms-project-binding1, google_project_iam_member.kms-project-binding2,
google_project_iam_member.kms-project-binding3, google_project_iam_member.kms-project-binding4,
google_project_iam_member.kms-project-binding5, google_kms_crypto_key_iam_member.iam]
name = "%s"
region = "us-central1"
config {
node_config {
network = google_compute_network.test.self_link
subnetwork = google_compute_subnetwork.test.self_link
zone = "us-central1-a"
}
encryption_config {
kms_key_name = "%s"
}
}
}
// use a separate network to avoid conflicts with other tests running in parallel
// that use the default network/subnet
resource "google_compute_network" "test" {
name = "%s"
auto_create_subnetworks = false
}
resource "google_compute_subnetwork" "test" {
name = "%s"
ip_cidr_range = "10.2.0.0/16"
region = "us-central1"
network = google_compute_network.test.self_link
}
`, pid, kmsKey, name, kmsKey, network, subnetwork)
}
func testAccComposerEnvironment_update(name, network, subnetwork string) string {
return fmt.Sprintf(`
data "google_composer_image_versions" "all" {
Expand Down
11 changes: 11 additions & 0 deletions website/docs/r/composer_environment.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,10 @@ The `config` block supports:
(Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html))
The configuration settings for the Airflow web server App Engine instance.

* `encryption_config` -
(Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html))
The encryption options for the Cloud Composer environment and its dependencies.

The `node_config` block supports:

* `zone` -
Expand Down Expand Up @@ -390,6 +394,13 @@ The `web_server_config` block supports:
Value custom is returned only in response, if Airflow web server parameters were
manually changed to a non-standard values.

The `encryption_config` block supports:

* `kms_key_name` -
(Required)
Customer-managed Encryption Key available through Google's Key Management Service. It must
be the fully qualified resource name,
i.e. projects/project-id/locations/location/keyRings/keyring/cryptoKeys/key. Cannot be updated.


## Attributes Reference
Expand Down