From ef9fdb412360aedf97f779db90ba293321372b01 Mon Sep 17 00:00:00 2001 From: Radek SPRTA Date: Mon, 11 Nov 2024 13:49:35 +0100 Subject: [PATCH 1/2] feat: support default_extensions_template in SSH Support the default_extensions_template parameter in SSH backend role resource. --- CHANGELOG.md | 1 + internal/consts/consts.go | 1 + internal/provider/meta.go | 2 + vault/resource_ssh_secret_backend_role.go | 15 +++ .../resource_ssh_secret_backend_role_test.go | 96 ++++++++++++++----- .../docs/r/ssh_secret_backend_role.html.md | 2 + 6 files changed, 95 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a77fae27a..8a1ccb4d80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ FEATURES: * Update `vault_database_secret_backend_connection` to support skip_verification config for Cassandra ([#2346](https://github.com/hashicorp/terraform-provider-vault/pull/2346)) * Update `vault_approle_auth_backend_role_secret_id` to support `num_uses` and `ttl` fields ([#2345](https://github.com/hashicorp/terraform-provider-vault/pull/2345)) * Add support for `use_annotations_as_alias_metadata` field for the `vault_kubernetes_auth_backend_config` resource ([#2206](https://github.com/hashicorp/terraform-provider-vault/pull/2206)) +* Add support for `default_extensions_template` field for the `vault_ssh_secret_backend_role` resource. ## 4.4.0 (Aug 7, 2024) diff --git a/internal/consts/consts.go b/internal/consts/consts.go index f9f28e3b44..aa4cb31252 100644 --- a/internal/consts/consts.go +++ b/internal/consts/consts.go @@ -507,6 +507,7 @@ const ( /* Vault version constants */ + VaultVersion180 = "1.8.0" VaultVersion190 = "1.9.0" VaultVersion110 = "1.10.0" VaultVersion111 = "1.11.0" diff --git a/internal/provider/meta.go b/internal/provider/meta.go index a50e599392..cfc5e512dc 100644 --- a/internal/provider/meta.go +++ b/internal/provider/meta.go @@ -35,6 +35,8 @@ const ( var ( MaxHTTPRetriesCCC int + VaultVersion180 = version.Must(version.NewSemver(consts.VaultVersion110)) + VaultVersion190 = version.Must(version.NewSemver(consts.VaultVersion190)) VaultVersion110 = version.Must(version.NewSemver(consts.VaultVersion110)) VaultVersion111 = version.Must(version.NewSemver(consts.VaultVersion111)) VaultVersion112 = version.Must(version.NewSemver(consts.VaultVersion112)) diff --git a/vault/resource_ssh_secret_backend_role.go b/vault/resource_ssh_secret_backend_role.go index b3ee38aa57..275e61fd9b 100644 --- a/vault/resource_ssh_secret_backend_role.go +++ b/vault/resource_ssh_secret_backend_role.go @@ -91,6 +91,11 @@ func sshSecretBackendRoleResource() *schema.Resource { Type: schema.TypeMap, Optional: true, }, + "default_extensions_template": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, "default_critical_options": { Type: schema.TypeMap, Optional: true, @@ -238,6 +243,12 @@ func sshSecretBackendRoleWrite(d *schema.ResourceData, meta interface{}) error { data["default_extensions"] = v } + if provider.IsAPISupported(meta, provider.VaultVersion180) { + if v, ok := d.GetOk("default_extensions_template"); ok { + data["default_extensions_template"] = v.(bool) + } + } + if v, ok := d.GetOk("default_critical_options"); ok { data["default_critical_options"] = v } @@ -356,6 +367,10 @@ func sshSecretBackendRoleRead(d *schema.ResourceData, meta interface{}) error { "max_ttl", "ttl", "algorithm_signer", "not_before_duration", } + if provider.IsAPISupported(meta, provider.VaultVersion180) { + fields = append(fields, []string{"default_extensions_template"}...) + } + if provider.IsAPISupported(meta, provider.VaultVersion112) { fields = append(fields, []string{"default_user_template", "allowed_domains_template"}...) } diff --git a/vault/resource_ssh_secret_backend_role_test.go b/vault/resource_ssh_secret_backend_role_test.go index c82e6e6dbe..3bc7909397 100644 --- a/vault/resource_ssh_secret_backend_role_test.go +++ b/vault/resource_ssh_secret_backend_role_test.go @@ -47,7 +47,7 @@ func TestAccSSHSecretBackendRole(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "algorithm_signer", "default"), resource.TestCheckResourceAttr(resourceName, "max_ttl", "0"), resource.TestCheckResourceAttr(resourceName, "ttl", "0"), - // 30s is the default value vault uese. + // 30s is the default value vault uses. // https://developer.hashicorp.com/vault/api-docs/secret/ssh#not_before_duration resource.TestCheckResourceAttr(resourceName, "not_before_duration", "30"), ) @@ -210,6 +210,33 @@ func TestAccSSHSecretBackendRole_template(t *testing.T) { }) } +func TestAccSSHSecretBackendRole_extensionsTemplate(t *testing.T) { + backend := acctest.RandomWithPrefix("tf-test/ssh") + name := acctest.RandomWithPrefix("tf-test-role") + resourceName := "vault_ssh_secret_backend_role.test_role" + + resource.Test(t, resource.TestCase{ + ProviderFactories: providerFactories, + PreCheck: func() { + testutil.TestAccPreCheck(t) + SkipIfAPIVersionLT(t, testProvider.Meta(), provider.VaultVersion112) + }, + CheckDestroy: testAccSSHSecretBackendRoleCheckDestroy, + Steps: []resource.TestStep{ + { + Config: testAccSSHSecretBackendRoleConfig_extensionsTemplate(name, backend), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "backend", backend), + resource.TestCheckResourceAttr(resourceName, "default_extensions.test_extension", "ssh-{{identity.entity.id}}-user"), + resource.TestCheckResourceAttr(resourceName, "default_extensions_template", "true"), + ), + }, + testutil.GetImportTestStep(resourceName, false, nil), + }, + }) +} + func testAccSSHSecretBackendRoleCheckDestroy(s *terraform.State) error { for _, rs := range s.RootModule().Resources { if rs.Type != "vault_ssh_secret_backend_role" { @@ -280,27 +307,28 @@ resource "vault_mount" "example" { } fragments = append(fragments, fmt.Sprintf(` resource "vault_ssh_secret_backend_role" "test_role" { - name = "%s" - backend = vault_mount.example.path - allow_bare_domains = true - allow_host_certificates = true - allow_subdomains = true - allow_user_certificates = false - allow_user_key_ids = true - allowed_critical_options = "foo,bar" - allowed_domains = "example.com,foo.com" - allowed_extensions = "ext1,ext2" - default_extensions = { "ext1" = "" } - default_critical_options = { "opt1" = "" } - allowed_users_template = true - allowed_users = "usr1,usr2" - default_user = "usr" - key_id_format = "{{role_name}}-test" - key_type = "ca" - algorithm_signer = "rsa-sha2-256" - max_ttl = "86400" - ttl = "43200" - not_before_duration = "3000" + name = "%s" + backend = vault_mount.example.path + allow_bare_domains = true + allow_host_certificates = true + allow_subdomains = true + allow_user_certificates = false + allow_user_key_ids = true + allowed_critical_options = "foo,bar" + allowed_domains = "example.com,foo.com" + allowed_extensions = "ext1,ext2" + default_extensions = { "ext1" = "" } + default_extensions_template = true + default_critical_options = { "opt1" = "" } + allowed_users_template = true + allowed_users = "usr1,usr2" + default_user = "usr" + key_id_format = "{{role_name}}-test" + key_type = "ca" + algorithm_signer = "rsa-sha2-256" + max_ttl = "86400" + ttl = "43200" + not_before_duration = "3000" %s `, name, extraFields)) @@ -358,3 +386,27 @@ resource "vault_ssh_secret_backend_role" "test_role" { return config } + +func testAccSSHSecretBackendRoleConfig_extensionsTemplate(name, path string) string { + config := fmt.Sprintf(` +resource "vault_mount" "example" { + path = "%s" + type = "ssh" +} + +resource "vault_ssh_secret_backend_role" "test_role" { + name = "%s" + backend = vault_mount.example.path + default_extensions = { + "test_extension" = "ssh-{{identity.entity.id}}-user" + } + default_extensions_template = true + default_user = "ssh-user" + key_type = "ca" + allow_user_certificates = true +} + +`, path, name) + + return config +} diff --git a/website/docs/r/ssh_secret_backend_role.html.md b/website/docs/r/ssh_secret_backend_role.html.md index a8acf10679..d02edf5e6f 100644 --- a/website/docs/r/ssh_secret_backend_role.html.md +++ b/website/docs/r/ssh_secret_backend_role.html.md @@ -73,6 +73,8 @@ The following arguments are supported: * `default_extensions` - (Optional) Specifies a map of extensions that certificates have when signed. +* `default_extensions_template` - (Optional) If set, `default_extensions` can be specified using identity template values. A non-templated user is also permitted. + * `default_critical_options` - (Optional) Specifies a map of critical options that certificates have when signed. * `allowed_users_template` - (Optional) Specifies if `allowed_users` can be declared using identity template policies. Non-templated users are also permitted. From beea539b07fac22147772b581ee500df08342272 Mon Sep 17 00:00:00 2001 From: radek-sprta Date: Tue, 12 Nov 2024 07:03:20 -0700 Subject: [PATCH 2/2] Update resource_ssh_secret_backend_role_test.go --- vault/resource_ssh_secret_backend_role_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/vault/resource_ssh_secret_backend_role_test.go b/vault/resource_ssh_secret_backend_role_test.go index f6a81af23e..0da8d995d1 100644 --- a/vault/resource_ssh_secret_backend_role_test.go +++ b/vault/resource_ssh_secret_backend_role_test.go @@ -287,6 +287,7 @@ resource "vault_ssh_secret_backend_role" "test_role" { allow_user_key_ids = true allowed_critical_options = "foo,bar" allowed_domains = "example.com,foo.com" + allowed_domains_template = true allowed_extensions = "ext1,ext2" default_extensions = { "ext1" = "" } default_extensions_template = true