diff --git a/CHANGELOG.md b/CHANGELOG.md index a1b8db6ed..41c6e002c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -139,6 +139,7 @@ FEATURES: * GCP Auth/Secrets ([#2427](https://github.com/hashicorp/terraform-provider-vault/pull/2427)) * Add new resource `vault_pki_secret_backend_config_auto_tidy` to set PKI automatic tidy configuration [#1934](https://github.com/hashicorp/terraform-provider-vault/pull/1934) * Add support for cross-account management of static roles in AWS Secrets: ([#2413](https://github.com/hashicorp/terraform-provider-vault/pull/2413)) +* Add support for whitelisting certificate extensions with `allowed_metadata_extensions` in `vault_cert_auth_backend_role`: ([#2436](https://github.com/hashicorp/terraform-provider-vault/pull/2436)) BUGS: diff --git a/vault/resource_cert_auth_backend_role.go b/vault/resource_cert_auth_backend_role.go index c70efd92c..6085fe9ce 100644 --- a/vault/resource_cert_auth_backend_role.go +++ b/vault/resource_cert_auth_backend_role.go @@ -29,6 +29,7 @@ const ( fieldOCSPQueryAllServers = "ocsp_query_all_servers" fieldOCSPServersOverride = "ocsp_servers_override" fieldRequiredExtensions = "required_extensions" + fieldAllowedMetadataExtensions = "allowed_metadata_extensions" ) var ( @@ -46,6 +47,7 @@ var ( fieldAllowedURISans, fieldOCSPServersOverride, fieldRequiredExtensions, + fieldAllowedMetadataExtensions, } certAuthBoolFields = []string{ fieldOCSPEnabled, @@ -182,6 +184,14 @@ func certAuthBackendRoleResource() *schema.Resource { "successful OCSP response, query all servers and consider the " + "certificate valid only if all servers agree.", }, + fieldAllowedMetadataExtensions: { + Type: schema.TypeSet, + Optional: true, + Description: "A array of oid extensions.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, } addTokenFields(fields, &addTokenFieldsConfig{}) @@ -385,6 +395,17 @@ func certAuthResourceRead(_ context.Context, d *schema.ResourceData, meta interf schema.HashString, []interface{}{})) } + // Vault sometimes returns these as null instead of an empty list. + if resp.Data["allowed_metadata_extensions"] != nil { + d.Set("allowed_metadata_extensions", + schema.NewSet( + schema.HashString, resp.Data["allowed_metadata_extensions"].([]interface{}))) + } else { + d.Set("allowed_metadata_extensions", + schema.NewSet( + schema.HashString, []interface{}{})) + } + if err := d.Set("allowed_organizational_units", resp.Data["allowed_organizational_units"]); err != nil { return diag.FromErr(err) } diff --git a/vault/resource_cert_auth_backend_role_test.go b/vault/resource_cert_auth_backend_role_test.go index f648fc9d1..f5d8f9483 100644 --- a/vault/resource_cert_auth_backend_role_test.go +++ b/vault/resource_cert_auth_backend_role_test.go @@ -83,6 +83,11 @@ func TestCertAuthBackend(t *testing.T) { allowedOrgUnits := []string{"foo", "baz"} + allowedMetadataExtensions := []string{ + "1.3.6.1.4.1.34380.1.2.1", + "1.3.6.1.4.1.34380.1.2.2", + } + resourceName := "vault_cert_auth_backend_role.test" resource.Test(t, resource.TestCase{ PreCheck: func() { testutil.TestAccPreCheck(t) }, @@ -90,7 +95,7 @@ func TestCertAuthBackend(t *testing.T) { CheckDestroy: testCertAuthBackendDestroy, Steps: []resource.TestStep{ { - Config: testCertAuthBackendConfig_basic(backend, name, testCertificate, allowedNames, allowedOrgUnits), + Config: testCertAuthBackendConfig_basic(backend, name, testCertificate, allowedNames, allowedOrgUnits, allowedMetadataExtensions), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "backend", backend), resource.TestCheckResourceAttr(resourceName, "name", name), @@ -101,6 +106,9 @@ func TestCertAuthBackend(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "allowed_organizational_units.#", "2"), resource.TestCheckTypeSetElemAttr(resourceName, "allowed_organizational_units.*", "foo"), resource.TestCheckTypeSetElemAttr(resourceName, "allowed_organizational_units.*", "baz"), + resource.TestCheckResourceAttr(resourceName, "allowed_organizational_units.#", "2"), + resource.TestCheckResourceAttr(resourceName, "allowed_metadata_extensions.0", "1.3.6.1.4.1.34380.1.2.1"), + resource.TestCheckResourceAttr(resourceName, "allowed_metadata_extensions.1", "1.3.6.1.4.1.34380.1.2.2"), testCertAuthBackendCheck_attrs(resourceName, backend, name), ), }, @@ -114,6 +122,7 @@ func TestCertAuthBackend(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "token_max_ttl", "0"), resource.TestCheckResourceAttr(resourceName, "allowed_names.#", "2"), resource.TestCheckResourceAttr(resourceName, "allowed_organizational_units.#", "0"), + resource.TestCheckResourceAttr(resourceName, "allowed_metadata_extensions.#", "0"), testCertAuthBackendCheck_attrs(resourceName, backend, name), ), }, @@ -226,6 +235,7 @@ func testCertAuthBackendCheck_attrs(resourceName, backend, name string) resource "allowed_email_sans": "allowed_email_sans", "allowed_uri_sans": "allowed_uri_sans", "allowed_organizational_units": "allowed_organizational_units", + "allowed_metadata_extensions": "allowed_metadata_extensions", "required_extensions": "required_extensions", "certificate": "certificate", } @@ -242,7 +252,7 @@ func testCertAuthBackendCheck_attrs(resourceName, backend, name string) resource VaultAttr: v, } switch k { - case TokenFieldPolicies, "allowed_names", "allowed_organizational_units": + case TokenFieldPolicies, "allowed_names", "allowed_organizational_units", "allowed_metadata_extensions": ta.AsSet = true } @@ -253,7 +263,7 @@ func testCertAuthBackendCheck_attrs(resourceName, backend, name string) resource } } -func testCertAuthBackendConfig_basic(backend, name, certificate string, allowedNames, allowedOrgUnits []string) string { +func testCertAuthBackendConfig_basic(backend, name, certificate string, allowedNames, allowedOrgUnits []string, allowedMetadataExtensions []string) string { config := fmt.Sprintf(` resource "vault_auth_backend" "cert" { @@ -272,8 +282,9 @@ EOF token_max_ttl = 600 token_policies = ["test_policy_1", "test_policy_2"] allowed_organizational_units = %s + allowed_metadata_extensions = %s } -`, backend, name, certificate, util.ArrayToTerraformList(allowedNames), util.ArrayToTerraformList(allowedOrgUnits)) +`, backend, name, certificate, util.ArrayToTerraformList(allowedNames), util.ArrayToTerraformList(allowedOrgUnits), util.ArrayToTerraformList(allowedMetadataExtensions)) return config } diff --git a/website/docs/r/cert_auth_backend_role.html.md b/website/docs/r/cert_auth_backend_role.html.md index 1e2204604..a1a3f7cce 100644 --- a/website/docs/r/cert_auth_backend_role.html.md +++ b/website/docs/r/cert_auth_backend_role.html.md @@ -56,6 +56,9 @@ The following arguments are supported: * `allowed_organizational_units` - (Optional array: []) Allowed organization units for authenticated client certificates. +* `allowed_metadata_extensions` - (Optional array: []) Allowed oid extensions. Upon successful authentication, + these extensions will be added as metadata if they are present in the certificate. + * `required_extensions` - (Optional array: []) TLS extensions required on client certificates