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 = <