diff --git a/.changelog/674.txt b/.changelog/674.txt new file mode 100644 index 000000000..f47d896a0 --- /dev/null +++ b/.changelog/674.txt @@ -0,0 +1,3 @@ +```release-note:feature +resource/deployment: new "elasticsearch"'s "keystore_contents" attribute to manage deployment keystore items during deployment create and update calls. +``` diff --git a/docs/resources/deployment.md b/docs/resources/deployment.md index 1638e9085..bb3c50f10 100644 --- a/docs/resources/deployment.md +++ b/docs/resources/deployment.md @@ -294,6 +294,7 @@ Optional: - `coordinating` (Attributes) 'coordinating' topology element (see [below for nested schema](#nestedatt--elasticsearch--coordinating)) - `extension` (Attributes Set) Optional Elasticsearch extensions such as custom bundles or plugins. (see [below for nested schema](#nestedatt--elasticsearch--extension)) - `frozen` (Attributes) 'frozen' topology element (see [below for nested schema](#nestedatt--elasticsearch--frozen)) +- `keystore_contents` (Attributes Map) Keystore contents that are controlled by the deployment resource. (see [below for nested schema](#nestedatt--elasticsearch--keystore_contents)) - `master` (Attributes) 'master' topology element (see [below for nested schema](#nestedatt--elasticsearch--master)) - `ml` (Attributes) 'ml' topology element (see [below for nested schema](#nestedatt--elasticsearch--ml)) - `ref_id` (String) A human readable reference for the Elasticsearch resource. The default value `main-elasticsearch` is recommended. @@ -493,6 +494,18 @@ Read-Only: + +### Nested Schema for `elasticsearch.keystore_contents` + +Required: + +- `value` (String, Sensitive) Secret value. This can either be a string or a JSON object that is stored as a JSON string in the keystore. + +Optional: + +- `as_file` (Boolean) If true, the secret is handled as a file. Otherwise, it's handled as a plain string. + + ### Nested Schema for `elasticsearch.master` diff --git a/ec/acc/deployment_config_test.go b/ec/acc/deployment_config_test.go index d3e55bbfe..670943a57 100644 --- a/ec/acc/deployment_config_test.go +++ b/ec/acc/deployment_config_test.go @@ -86,6 +86,10 @@ func setDefaultTemplate(region, template string) string { } func buildAwsTemplate(template string) string { + if template == "default" { + return template + } + v2Templates := []string{defaultTemplate, hotWarmTemplate, ccsTemplate, computeOpTemplate, memoryOpTemplate, enterpriseSearchTemplate, } diff --git a/ec/acc/deployment_keystore_test.go b/ec/acc/deployment_keystore_test.go new file mode 100644 index 000000000..ae5068243 --- /dev/null +++ b/ec/acc/deployment_keystore_test.go @@ -0,0 +1,90 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you under +// the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package acc + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccDeployment_keystore(t *testing.T) { + depResName := "ec_deployment.test" + keystoreResName := "ec_deployment_elasticsearch_keystore.test" + randomName := prefix + acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + configs := []string{ + fixtureAccDeploymentResourceBasicDefaults(t, "testdata/deployment_keystore_create.tf", randomName, getRegion(), "default"), + fixtureAccDeploymentResourceBasicDefaults(t, "testdata/deployment_keystore_update1.tf", randomName, getRegion(), "default"), + fixtureAccDeploymentResourceBasicDefaults(t, "testdata/deployment_keystore_update2.tf", randomName, getRegion(), "default"), + fixtureAccDeploymentResourceBasicDefaults(t, "testdata/deployment_keystore_update3.tf", randomName, getRegion(), "default"), + fixtureAccDeploymentResourceBasicDefaults(t, "testdata/deployment_keystore_update4.tf", randomName, getRegion(), "default"), + } + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProviderFactory, + CheckDestroy: testAccDeploymentDestroy, + Steps: []resource.TestStep{ + { + // test deployment creation with an embedded keystore secret and an appropriate entry in ES config + Config: configs[0], + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(depResName, "elasticsearch.keystore_contents.%", "1"), + ), + }, + { + // add `ec_deployment_elasticsearch_keystore resource` with another secret + Config: configs[1], + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(depResName, "elasticsearch.keystore_contents.%", "1"), + + resource.TestCheckResourceAttr(keystoreResName, "setting_name", "xpack.notification.slack.account.monitoring.secure_url"), + ), + }, + { + // remove the deployment's keystore entry and the appropriate entry in ES config + // test that such removal doesn't affect the secret in `ec_deployment_elasticsearch_keystore` resource + Config: configs[2], + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckNoResourceAttr(depResName, "elasticsearch.keystore_contents"), + + resource.TestCheckResourceAttr(keystoreResName, "setting_name", "xpack.notification.slack.account.monitoring.secure_url"), + ), + }, + { + // test deployment update with new embedded keystore secret and an apppropirate ES config entry + Config: configs[3], + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(depResName, "elasticsearch.keystore_contents.%", "1"), + + resource.TestCheckResourceAttr(keystoreResName, "setting_name", "xpack.notification.slack.account.monitoring.secure_url"), + ), + }, + { + // remove `ec_deployment_elasticsearch_keystore` resource + // test that such removal doesn't affect the embedded secret + Config: configs[4], + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(depResName, "elasticsearch.keystore_contents.%", "1"), + ), + }, + }, + }) +} diff --git a/ec/acc/testdata/deployment_keystore_create.tf b/ec/acc/testdata/deployment_keystore_create.tf new file mode 100644 index 000000000..eb6d7324a --- /dev/null +++ b/ec/acc/testdata/deployment_keystore_create.tf @@ -0,0 +1,62 @@ +data "ec_stack" "latest" { + version_regex = "latest" + region = "%s" +} + +resource "ec_deployment" "test" { + name = "%s" + region = "%s" + version = data.ec_stack.latest.version + deployment_template_id = "%s" + + elasticsearch = { + hot = { + size = "1g" + autoscaling = {} + } + + ml = { + autoscaling = {} + } + + config = { + user_settings_yaml = <" + rp.response_type: "code" + rp.requested_scopes: ["openid", "email"] + rp.redirect_uri: "/api/security/oidc/callback" + op.issuer: "" + op.authorization_endpoint: "/oauth2/v1/authorize" + op.token_endpoint: "/oauth2/v1/token" + op.userinfo_endpoint: "/oauth2/v1/userinfo" + op.endsession_endpoint: "/oauth2/v1/logout" + op.jwkset_path: "/oauth2/v1/keys" + claims.principal: email + claim_patterns.principal: "^([^@]+)@elastic\\.co$" +EOF + } + + keystore_contents = { + "xpack.security.authc.realms.oidc.oidc1.rp.client_secret" = { + value = "secret-1" + } + } + } + + kibana = { + zone_count = 1 + config = { + user_settings_yaml = <