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

Support managing keystore entries during deployment creation and update #674

Merged
merged 11 commits into from
Sep 21, 2023
13 changes: 13 additions & 0 deletions docs/resources/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -493,6 +494,18 @@ Read-Only:



<a id="nestedatt--elasticsearch--keystore_contents"></a>
### 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.


<a id="nestedatt--elasticsearch--master"></a>
### Nested Schema for `elasticsearch.master`

Expand Down
4 changes: 4 additions & 0 deletions ec/acc/deployment_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand Down
90 changes: 90 additions & 0 deletions ec/acc/deployment_keystore_test.go
Original file line number Diff line number Diff line change
@@ -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"),
),
},
},
})
}
62 changes: 62 additions & 0 deletions ec/acc/testdata/deployment_keystore_create.tf
Original file line number Diff line number Diff line change
@@ -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 = <<EOF
xpack.security.authc.realms.oidc.oidc1:
order: 2
rp.client_id: 0oa5mogiwihtQzPzn697
rp.response_type: "code"
rp.requested_scopes: ["openid", "email"]
rp.redirect_uri: "https://es-test.192.168.44.10.ip.es.io:9243/api/security/oidc/callback"
op.issuer: "https://keystore-test.okta.com"
op.authorization_endpoint: "https://keystore-test.okta.com/oauth2/v1/authorize"
op.token_endpoint: "https://keystore-test.okta.com/oauth2/v1/token"
op.userinfo_endpoint: "https://keystore-test.okta.com/oauth2/v1/userinfo"
op.endsession_endpoint: "https://keystore-test.okta.com/oauth2/v1/logout"
op.jwkset_path: "https://keystore-test.okta.com/oauth2/v1/keys"
claims.principal: email
claim_patterns.principal: "^([^@]+)@elasticsearch\\.com$"
EOF
}

keystore_contents = {
"xpack.security.authc.realms.oidc.oidc1.rp.client_secret" = {
value = "secret-1"
}
}
}

kibana = {
zone_count = 1
config = {
user_settings_yaml = <<EOF
xpack.security.authc.providers:
oidc.oidc1:
order: 0
realm: oidc1
description: "Log in with Okta - test"
basic.basic1:
order: 1
EOF
}
}
}
68 changes: 68 additions & 0 deletions ec/acc/testdata/deployment_keystore_update1.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
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 = <<EOF
xpack.security.authc.realms.oidc.oidc1:
order: 2
rp.client_id: 0oa5mogiwihtQzPzn697
rp.response_type: "code"
rp.requested_scopes: ["openid", "email"]
rp.redirect_uri: "https://es-test.192.168.44.10.ip.es.io:9243/api/security/oidc/callback"
op.issuer: "https://keystore-test.okta.com"
op.authorization_endpoint: "https://keystore-test.okta.com/oauth2/v1/authorize"
op.token_endpoint: "https://keystore-test.okta.com/oauth2/v1/token"
op.userinfo_endpoint: "https://keystore-test.okta.com/oauth2/v1/userinfo"
op.endsession_endpoint: "https://keystore-test.okta.com/oauth2/v1/logout"
op.jwkset_path: "https://keystore-test.okta.com/oauth2/v1/keys"
claims.principal: email
claim_patterns.principal: "^([^@]+)@elasticsearch\\.com$"
EOF
}

keystore_contents = {
"xpack.security.authc.realms.oidc.oidc1.rp.client_secret" = {
value = "secret-1"
}
}
}

kibana = {
zone_count = 1
config = {
user_settings_yaml = <<EOF
xpack.security.authc.providers:
oidc.oidc1:
order: 0
realm: oidc1
description: "Log in with Okta - test"
basic.basic1:
order: 1
EOF
}
}
}

resource "ec_deployment_elasticsearch_keystore" "test" {
deployment_id = ec_deployment.test.id
setting_name = "xpack.notification.slack.account.monitoring.secure_url"
value = "secret-2"
}
33 changes: 33 additions & 0 deletions ec/acc/testdata/deployment_keystore_update2.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
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 = {}
}
}

kibana = {
zone_count = 1
}

}

resource "ec_deployment_elasticsearch_keystore" "test" {
deployment_id = ec_deployment.test.id
setting_name = "xpack.notification.slack.account.monitoring.secure_url"
value = "secret-2"
}
70 changes: 70 additions & 0 deletions ec/acc/testdata/deployment_keystore_update3.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
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 = <<EOF
xpack.security.authc.realms.oidc.oidc3:
order: 2
rp.client_id: 0oa5mogiwihtQzPzn697
rp.response_type: "code"
rp.requested_scopes: ["openid", "email"]
rp.redirect_uri: "https://es-test.192.168.44.10.ip.es.io:9243/api/security/oidc/callback"
op.issuer: "https://keystore-test.okta.com"
op.authorization_endpoint: "https://keystore-test.okta.com/oauth2/v1/authorize"
op.token_endpoint: "https://keystore-test.okta.com/oauth2/v1/token"
op.userinfo_endpoint: "https://keystore-test.okta.com/oauth2/v1/userinfo"
op.endsession_endpoint: "https://keystore-test.okta.com/oauth2/v1/logout"
op.jwkset_path: "https://keystore-test.okta.com/oauth2/v1/keys"
claims.principal: email
claim_patterns.principal: "^([^@]+)@elasticsearch\\.com$"
EOF
}

keystore_contents = {
"xpack.security.authc.realms.oidc.oidc3.rp.client_secret" = {
value = "secret-3"
as_file = true
}
}
}

kibana = {
zone_count = 1
config = {
user_settings_yaml = <<EOF
xpack.security.authc.providers:
oidc.oidc3:
order: 0
realm: oidc3
description: "Log in with Okta - test"
basic.basic1:
order: 1
EOF
}
}

}

resource "ec_deployment_elasticsearch_keystore" "test" {
deployment_id = ec_deployment.test.id
setting_name = "xpack.notification.slack.account.monitoring.secure_url"
value = "secret-2"
}
Loading