Skip to content

Commit

Permalink
azurerm_app_configuration - fix validation for value property (#2…
Browse files Browse the repository at this point in the history
…4702)

* fix validation for value

* only fix comment
  • Loading branch information
teowa authored Jan 31, 2024
1 parent 214a0a2 commit 8ad90e7
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,13 @@ func (k KeyResource) Arguments() map[string]*pluginsdk.Schema {
"value": {
Type: pluginsdk.TypeString,
Optional: true,
ConflictsWith: []string{
"vault_key_reference",
},
// if `type` is set to `vault`, then `value` will be set by `vault_key_reference`
DiffSuppressFunc: func(k, old, new string, d *pluginsdk.ResourceData) bool {
return d.Get("type").(string) == KeyTypeVault && d.Get("vault_key_reference").(string) != "" && old != "" && new == ""
},
},
"locked": {
Type: pluginsdk.TypeBool,
Expand All @@ -95,13 +102,16 @@ func (k KeyResource) Arguments() map[string]*pluginsdk.Schema {
"type": {
Type: pluginsdk.TypeString,
Optional: true,
Default: "kv",
Default: KeyTypeKV,
ValidateFunc: validation.StringInSlice([]string{KeyTypeVault, KeyTypeKV}, false),
},
"vault_key_reference": {
Type: pluginsdk.TypeString,
Optional: true,
ValidateFunc: validation.IsURLWithHTTPorHTTPS,
ConflictsWith: []string{
"value",
},
},
"tags": tags.Schema(),
}
Expand Down Expand Up @@ -416,23 +426,22 @@ func (k KeyResource) CustomizeDiff() sdk.ResourceFunc {
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
rd := metadata.ResourceDiff
keyType := rd.Get("type").(string)

if keyType == KeyTypeVault {
contentType := rd.Get("content_type").(string)
if rd.HasChange("content_type") && contentType != VaultKeyContentType {
return fmt.Errorf("vault reference key %q cannot have content type other than %q (found %q)", rd.Get("key").(string), VaultKeyContentType, contentType)
return fmt.Errorf("key type %q cannot have content type other than %q (found %q)", KeyTypeVault, VaultKeyContentType, contentType)
}

value := rd.Get("value").(string)
var v VaultKeyReference
if rd.HasChange("value") {
if err := json.Unmarshal([]byte(value), &v); err != nil {
return fmt.Errorf("while validating attribute 'value' (%q): %+v", value, err)
}
if v.URI == "" {
return fmt.Errorf("invalid data in 'value' contents: URI cannot be empty")
}
if rd.HasChange("value") && rd.Get("value").(string) != "" {
return fmt.Errorf("'value' should only be set when key type is set to %q", KeyTypeKV)
}
}

if keyType == KeyTypeKV && rd.Get("vault_key_reference").(string) != "" {
return fmt.Errorf("'vault_key_reference' should only be set when key type is set to %q", KeyTypeVault)
}

return nil
},
Timeout: 30 * time.Minute,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package appconfiguration_test
import (
"context"
"fmt"
"regexp"
"testing"

"github.com/hashicorp/terraform-provider-azurerm/internal/acceptance"
Expand Down Expand Up @@ -108,6 +109,46 @@ func TestAccAppConfigurationKey_KVToVault(t *testing.T) {
check.That(data.ResourceName).Key("type").HasValue("vault"),
),
},
{
Config: r.basic(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
check.That(data.ResourceName).Key("type").HasValue("kv"),
),
},
})
}

func TestAccAppConfigurationKey_errorTypeVaultWithValue(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_app_configuration_key", "test")
r := AppConfigurationKeyResource{}
data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.errorTypeVaultWithValue(data),
ExpectError: regexp.MustCompile("'value' should only be set when key type is set to \"kv\""),
},
})
}

func TestAccAppConfigurationKey_errorTypeWithVaultKeyReference(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_app_configuration_key", "test")
r := AppConfigurationKeyResource{}
data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.errorTypeWithVaultKeyReference(data),
ExpectError: regexp.MustCompile("'vault_key_reference' should only be set when key type is set to \"vault\""),
},
})
}

func TestAccAppConfigurationKey_errorTypeWithContentType(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_app_configuration_key", "test")
r := AppConfigurationKeyResource{}
data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.errorTypeWithContentType(data),
ExpectError: regexp.MustCompile("key type \"vault\" cannot have content type other than"),
},
})
}

Expand Down Expand Up @@ -385,11 +426,85 @@ resource "azurerm_app_configuration_key" "test" {
type = "vault"
label = "acctest-ackeylabel-%d"
vault_key_reference = azurerm_key_vault_secret.example.id
lifecycle {
ignore_changes = [
value
}
`, t.base(data), data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger)
}

func (t AppConfigurationKeyResource) errorTypeVaultWithValue(data acceptance.TestData) string {
return fmt.Sprintf(`
%s
resource "azurerm_app_configuration_key" "test" {
configuration_store_id = azurerm_app_configuration.test.id
key = "acctest-ackey-%d"
type = "vault"
label = "acctest-ackeylabel-%d"
value = "a test"
}
`, t.base(data), data.RandomInteger, data.RandomInteger)
}

func (t AppConfigurationKeyResource) errorTypeWithContentType(data acceptance.TestData) string {
return fmt.Sprintf(`
%s
resource "azurerm_key_vault" "example" {
name = "a-v2-%d"
location = azurerm_resource_group.test.location
resource_group_name = azurerm_resource_group.test.name
tenant_id = data.azurerm_client_config.test.tenant_id
sku_name = "premium"
soft_delete_retention_days = 7
access_policy {
tenant_id = data.azurerm_client_config.test.tenant_id
object_id = data.azurerm_client_config.test.object_id
key_permissions = [
"Create",
"Get",
]
secret_permissions = [
"Set",
"Get",
"Delete",
"Purge",
"Recover"
]
}
}
`, t.base(data), data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger)
resource "azurerm_key_vault_secret" "example" {
name = "acctest-secret-%d"
value = "szechuan"
key_vault_id = azurerm_key_vault.example.id
}
resource "azurerm_app_configuration_key" "test" {
configuration_store_id = azurerm_app_configuration.test.id
key = "acctest-ackey-%d"
type = "vault"
label = "acctest-ackeylabel-%d"
content_type = "test"
vault_key_reference = azurerm_key_vault_secret.example.id
}
`, t.base(data), data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger)
}

func (t AppConfigurationKeyResource) errorTypeWithVaultKeyReference(data acceptance.TestData) string {
return fmt.Sprintf(`
%s
resource "azurerm_app_configuration_key" "test" {
configuration_store_id = azurerm_app_configuration.test.id
key = "acctest-ackey-%d"
type = "kv"
label = "acctest-ackeylabel-%d"
content_type = "test"
# use a fake vault key reference to trigger the error, so we can skip creating a vault
vault_key_reference = "https://example-keyvault.vault.azure.net/keys/example/fdf067c93bbb4b22bff4d8b7a9a56217"
}
`, t.base(data), data.RandomInteger, data.RandomInteger)
}
12 changes: 5 additions & 7 deletions website/docs/r/app_configuration_key.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,6 @@ resource "azurerm_app_configuration_key" "test" {
depends_on = [
azurerm_role_assignment.appconf_dataowner
]
lifecycle {
ignore_changes = [
value
]
}
}
```

Expand All @@ -135,11 +129,15 @@ The following arguments are supported:

* `value` - (Optional) The value of the App Configuration Key. This should only be set when type is set to `kv`.

~> **NOTE:** `value` and `vault_key_reference` are mutually exclusive.

* `locked` - (Optional) Should this App Configuration Key be Locked to prevent changes?

* `type` - (Optional) The type of the App Configuration Key. It can either be `kv` (simple [key/value](https://docs.microsoft.com/azure/azure-app-configuration/concept-key-value)) or `vault` (where the value is a reference to a [Key Vault Secret](https://azure.microsoft.com/en-gb/services/key-vault/). Defaults to `kv`.

* `vault_key_reference` - (Optional) The ID of the vault secret this App Configuration Key refers to, when `type` is set to `vault`.
* `vault_key_reference` - (Optional) The ID of the vault secret this App Configuration Key refers to. This should only be set when `type` is set to `vault`.

~> **NOTE:** `vault_key_reference` and `value` are mutually exclusive.

~> **NOTE:** When setting the `vault_key_reference` using the `id` will pin the value to specific version of the secret, to reference latest secret value use `versionless_id`

Expand Down

0 comments on commit 8ad90e7

Please sign in to comment.