forked from auth0/terraform-provider-auth0
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add auth0_encryption_keys resource to allow rekeying of encryption ke…
…ys (auth0#1031) * Add auth0_encryption_key resource to allow rekeying of tenant encryption keys * Slight renaming, and use key_rotation_id instead of rekey attribute * Rename auth0_encryption_key to auth0_encryption_key_manager Signed-off-by: BryanLewis-AtOkta <[email protected]>
- Loading branch information
1 parent
f188374
commit 8886fec
Showing
8 changed files
with
851 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
--- | ||
page_title: "Resource: auth0_encryption_key_manager" | ||
description: |- | ||
Resource to allow the rekeying of your tenant master key. | ||
--- | ||
|
||
# Resource: auth0_encryption_key_manager | ||
|
||
Resource to allow the rekeying of your tenant master key. | ||
|
||
## Example Usage | ||
|
||
```terraform | ||
resource "auth0_encryption_key_manager" "my_encryption_key_manager_initial" { | ||
key_rotation_id = "da9f2f3b-1c7e-4245-8982-9a25da8407c4" | ||
} | ||
resource "auth0_encryption_key_manager" "my_encryption_key_manager_rekey" { | ||
key_rotation_id = "68feba2c-7768-40f3-9d71-4b91e0233abf" | ||
} | ||
``` | ||
|
||
<!-- schema generated by tfplugindocs --> | ||
## Schema | ||
|
||
### Optional | ||
|
||
- `key_rotation_id` (String) If this value is changed, the encryption keys will be rotated. A UUID is recommended for the `key_rotation_id`. | ||
|
||
### Read-Only | ||
|
||
- `encryption_keys` (List of Object) All encryption keys. (see [below for nested schema](#nestedatt--encryption_keys)) | ||
- `id` (String) The ID of this resource. | ||
|
||
<a id="nestedatt--encryption_keys"></a> | ||
### Nested Schema for `encryption_keys` | ||
|
||
Read-Only: | ||
|
||
- `created_at` (String) | ||
- `key_id` (String) | ||
- `parent_key_id` (String) | ||
- `state` (String) | ||
- `type` (String) | ||
- `updated_at` (String) | ||
|
||
## Import | ||
|
||
Import is supported using the following syntax: | ||
|
||
```shell | ||
# As this is not a resource identifiable by an ID within the Auth0 Management API, | ||
# auth0_encryption_key_manager can be imported using a random string. | ||
# | ||
# We recommend [Version 4 UUID](https://www.uuidgenerator.net/version4) | ||
# | ||
# Example: | ||
terraform import auth0_encryption_key_manager.my_key_manager "6f0519ad-ea35-44a3-9b0e-ac9c631612c2" | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# As this is not a resource identifiable by an ID within the Auth0 Management API, | ||
# auth0_encryption_key_manager can be imported using a random string. | ||
# | ||
# We recommend [Version 4 UUID](https://www.uuidgenerator.net/version4) | ||
# | ||
# Example: | ||
terraform import auth0_encryption_key_manager.my_key_manager "6f0519ad-ea35-44a3-9b0e-ac9c631612c2" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
resource "auth0_encryption_key_manager" "my_encryption_key_manager_initial" { | ||
key_rotation_id = "da9f2f3b-1c7e-4245-8982-9a25da8407c4" | ||
} | ||
|
||
resource "auth0_encryption_key_manager" "my_encryption_key_manager_rekey" { | ||
key_rotation_id = "68feba2c-7768-40f3-9d71-4b91e0233abf" | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package encryptionkeymanager | ||
|
||
import ( | ||
"github.com/auth0/go-auth0/management" | ||
) | ||
|
||
func flattenEncryptionKeys(keys []*management.EncryptionKey) []interface{} { | ||
var result []interface{} | ||
const timeRFC3339WithMilliseconds = "2006-01-02T15:04:05.000Z07:00" | ||
|
||
for _, key := range keys { | ||
result = append(result, map[string]interface{}{ | ||
"key_id": key.GetKID(), | ||
"parent_key_id": key.GetParentKID(), | ||
"type": key.GetType(), | ||
"state": key.GetState(), | ||
"created_at": key.GetCreatedAt().Format(timeRFC3339WithMilliseconds), | ||
"updated_at": key.GetUpdatedAt().Format(timeRFC3339WithMilliseconds), | ||
}) | ||
} | ||
return result | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
package encryptionkeymanager | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/id" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" | ||
|
||
"github.com/auth0/terraform-provider-auth0/internal/config" | ||
) | ||
|
||
// NewEncryptionKeyManagerResource will return a new auth0_encryption_key_manager resource. | ||
func NewEncryptionKeyManagerResource() *schema.Resource { | ||
return &schema.Resource{ | ||
CreateContext: createEncryptionKeyManager, | ||
UpdateContext: updateEncryptionKeyManager, | ||
ReadContext: readEncryptionKeyManager, | ||
DeleteContext: deleteEncryptionKeyManager, | ||
Description: "Resource to allow the rekeying of your tenant master key.", | ||
Schema: map[string]*schema.Schema{ | ||
"key_rotation_id": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
Description: "If this value is changed, the encryption keys will be rotated. A UUID is recommended for the `key_rotation_id`.", | ||
}, | ||
"encryption_keys": { | ||
Type: schema.TypeList, | ||
Computed: true, | ||
Description: "All encryption keys.", | ||
Elem: &schema.Resource{ | ||
Schema: map[string]*schema.Schema{ | ||
"key_id": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
Description: "The key ID of the encryption key.", | ||
}, | ||
"type": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
Description: "The type of the encryption key. One of " + | ||
"`customer-provided-root-key`, `environment-root-key`, " + | ||
"or `tenant-master-key`.", | ||
}, | ||
"state": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
Description: "The state of the encryption key. One of " + | ||
"`pre-activation`, `active`, `deactivated`, or `destroyed`.", | ||
}, | ||
"parent_key_id": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
Description: "The key ID of the parent wrapping key.", | ||
}, | ||
"created_at": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
Description: "The ISO 8601 formatted date the encryption key was created.", | ||
}, | ||
"updated_at": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
Description: "The ISO 8601 formatted date the encryption key was updated.", | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func createEncryptionKeyManager(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
data.SetId(id.UniqueId()) | ||
|
||
return updateEncryptionKeyManager(ctx, data, meta) | ||
} | ||
|
||
func updateEncryptionKeyManager(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
api := meta.(*config.Config).GetAPI() | ||
|
||
if !data.IsNewResource() && data.HasChange("key_rotation_id") { | ||
keyRotationID := data.GetRawConfig().GetAttr("key_rotation_id") | ||
if !keyRotationID.IsNull() && len(keyRotationID.AsString()) > 0 { | ||
if err := api.EncryptionKey.Rekey(ctx); err != nil { | ||
return diag.FromErr(err) | ||
} | ||
} | ||
} | ||
|
||
return readEncryptionKeyManager(ctx, data, meta) | ||
} | ||
|
||
func readEncryptionKeyManager(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
api := meta.(*config.Config).GetAPI() | ||
|
||
encryptionKeys, err := api.EncryptionKey.List(ctx) | ||
if err != nil { | ||
return diag.FromErr(err) | ||
} | ||
|
||
data.SetId(id.UniqueId()) | ||
|
||
return diag.FromErr(data.Set("encryption_keys", flattenEncryptionKeys(encryptionKeys.Keys))) | ||
} | ||
|
||
func deleteEncryptionKeyManager(_ context.Context, _ *schema.ResourceData, _ interface{}) diag.Diagnostics { | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
package encryptionkeymanager_test | ||
|
||
import ( | ||
"fmt" | ||
"regexp" | ||
"strconv" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform-plugin-testing/helper/resource" | ||
"github.com/hashicorp/terraform-plugin-testing/terraform" | ||
"github.com/stretchr/testify/assert" | ||
|
||
"github.com/auth0/terraform-provider-auth0/internal/acctest" | ||
) | ||
|
||
const testAccEncryptionKeyManagerCreate = ` | ||
resource "auth0_encryption_key_manager" "my_key_manager" { } | ||
` | ||
|
||
const testAccEncryptionKeyManagerFirstRotation = ` | ||
resource "auth0_encryption_key_manager" "my_key_manager" { | ||
key_rotation_id = "initial_value" | ||
} | ||
` | ||
|
||
const testAccEncryptionKeyManagerSecondRotation = ` | ||
resource "auth0_encryption_key_manager" "my_key_manager" { | ||
key_rotation_id = "changed_value" | ||
} | ||
` | ||
|
||
const testAccEncryptionKeyManagerUnsetRotation = ` | ||
resource "auth0_encryption_key_manager" "my_key_manager" { | ||
} | ||
` | ||
|
||
func TestAccEncryptionKeyManager(t *testing.T) { | ||
initialKey := make(map[string]string) | ||
firstRotationKey := make(map[string]string) | ||
secondRotationKey := make(map[string]string) | ||
unsetRotationKey := make(map[string]string) | ||
|
||
acctest.Test(t, resource.TestCase{ | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccEncryptionKeyManagerCreate, | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestMatchResourceAttr("auth0_encryption_key_manager.my_key_manager", "encryption_keys.#", regexp.MustCompile("^[1-9][0-9]*")), | ||
extractActiveKey("auth0_encryption_key_manager.my_key_manager", "encryption_keys", "tenant-master-key", &initialKey), | ||
func(_ *terraform.State) error { | ||
keyID, ok := initialKey["key_id"] | ||
assert.True(t, ok && len(keyID) > 0, "key_id should exist") | ||
parentKeyID, ok := initialKey["parent_key_id"] | ||
assert.True(t, ok && len(parentKeyID) > 0, "parent_key_id should exist") | ||
assert.Equal(t, initialKey["type"], "tenant-master-key") | ||
assert.Equal(t, initialKey["state"], "active") | ||
createdAt, ok := initialKey["created_at"] | ||
assert.True(t, ok && len(createdAt) > 0, "created_at should exist") | ||
updatedAt, ok := initialKey["updated_at"] | ||
assert.True(t, ok && len(updatedAt) > 0, "updated_at should exist") | ||
|
||
return nil | ||
}, | ||
), | ||
}, | ||
{ | ||
Config: testAccEncryptionKeyManagerFirstRotation, | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestMatchResourceAttr("auth0_encryption_key_manager.my_key_manager", "encryption_keys.#", regexp.MustCompile("^[1-9][0-9]*")), | ||
extractActiveKey("auth0_encryption_key_manager.my_key_manager", "encryption_keys", "tenant-master-key", &firstRotationKey), | ||
func(_ *terraform.State) error { | ||
keyID, ok := firstRotationKey["key_id"] | ||
assert.True(t, ok && len(keyID) > 0, "key_id should exist") | ||
assert.NotEqual(t, firstRotationKey["key_id"], initialKey["key_id"]) | ||
parentKeyID, ok := firstRotationKey["parent_key_id"] | ||
assert.True(t, ok && len(parentKeyID) > 0, "parent_key_id should exist") | ||
assert.Equal(t, firstRotationKey["type"], "tenant-master-key") | ||
assert.Equal(t, firstRotationKey["state"], "active") | ||
createdAt, ok := firstRotationKey["created_at"] | ||
assert.True(t, ok && len(createdAt) > 0, "created_at should exist") | ||
updatedAt, ok := firstRotationKey["updated_at"] | ||
assert.True(t, ok && len(updatedAt) > 0, "updated_at should exist") | ||
|
||
return nil | ||
}, | ||
), | ||
}, | ||
{ | ||
Config: testAccEncryptionKeyManagerSecondRotation, | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestMatchResourceAttr("auth0_encryption_key_manager.my_key_manager", "encryption_keys.#", regexp.MustCompile("^[1-9][0-9]*")), | ||
extractActiveKey("auth0_encryption_key_manager.my_key_manager", "encryption_keys", "tenant-master-key", &secondRotationKey), | ||
func(_ *terraform.State) error { | ||
keyID, ok := secondRotationKey["key_id"] | ||
assert.True(t, ok && len(keyID) > 0, "key_id should exist") | ||
assert.NotEqual(t, secondRotationKey["key_id"], firstRotationKey["key_id"]) | ||
parentKeyID, ok := secondRotationKey["parent_key_id"] | ||
assert.True(t, ok && len(parentKeyID) > 0, "parent_key_id should exist") | ||
assert.Equal(t, secondRotationKey["type"], "tenant-master-key") | ||
assert.Equal(t, secondRotationKey["state"], "active") | ||
createdAt, ok := secondRotationKey["created_at"] | ||
assert.True(t, ok && len(createdAt) > 0, "created_at should exist") | ||
updatedAt, ok := secondRotationKey["updated_at"] | ||
assert.True(t, ok && len(updatedAt) > 0, "updated_at should exist") | ||
|
||
return nil | ||
}, | ||
), | ||
}, | ||
{ | ||
Config: testAccEncryptionKeyManagerUnsetRotation, | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestMatchResourceAttr("auth0_encryption_key_manager.my_key_manager", "encryption_keys.#", regexp.MustCompile("^[1-9][0-9]*")), | ||
extractActiveKey("auth0_encryption_key_manager.my_key_manager", "encryption_keys", "tenant-master-key", &unsetRotationKey), | ||
func(_ *terraform.State) error { | ||
keyID, ok := unsetRotationKey["key_id"] | ||
assert.True(t, ok && len(keyID) > 0, "key_id should exist") | ||
assert.Equal(t, unsetRotationKey["key_id"], secondRotationKey["key_id"]) | ||
parentKeyID, ok := unsetRotationKey["parent_key_id"] | ||
assert.True(t, ok && len(parentKeyID) > 0, "parent_key_id should exist") | ||
assert.Equal(t, unsetRotationKey["type"], "tenant-master-key") | ||
assert.Equal(t, unsetRotationKey["state"], "active") | ||
createdAt, ok := unsetRotationKey["created_at"] | ||
assert.True(t, ok && len(createdAt) > 0, "created_at should exist") | ||
updatedAt, ok := unsetRotationKey["updated_at"] | ||
assert.True(t, ok && len(updatedAt) > 0, "updated_at should exist") | ||
|
||
return nil | ||
}, | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func extractActiveKey(resource, attribute, keyType string, keyMapPtr *map[string]string) resource.TestCheckFunc { | ||
return func(state *terraform.State) error { | ||
clear(*keyMapPtr) | ||
|
||
tfResource, ok := state.RootModule().Resources[resource] | ||
if !ok { | ||
return fmt.Errorf("extractActiveKey: failed to find resource with name: %q", resource) | ||
} | ||
countValue, ok := tfResource.Primary.Attributes[fmt.Sprintf("%s.#", attribute)] | ||
if !ok { | ||
return fmt.Errorf("extractActiveKey: failed to find attribute with name: %q", attribute) | ||
} | ||
count, err := strconv.Atoi(countValue) | ||
if err != nil { | ||
return err | ||
} | ||
fmt.Printf("DEBUG: CRAIG: extract count: %d\n", count) | ||
for i := range count { | ||
stateValue, ok := tfResource.Primary.Attributes[keyName(attribute, i, "state")] | ||
if !ok { | ||
return fmt.Errorf("extractActiveKey: failed to find state for attribute with name: %q", attribute) | ||
} | ||
if stateValue != "active" { | ||
continue | ||
} | ||
typeValue, ok := tfResource.Primary.Attributes[keyName(attribute, i, "type")] | ||
if !ok { | ||
return fmt.Errorf("extractActiveKey: failed to find type for attribute with name: %q", attribute) | ||
} | ||
if typeValue != keyType { | ||
continue | ||
} | ||
for key, value := range tfResource.Primary.Attributes { | ||
if strings.HasPrefix(key, keyName(attribute, i, "")) { | ||
foundKey, _ := strings.CutPrefix(key, keyName(attribute, i, "")) | ||
(*keyMapPtr)[foundKey] = value | ||
} | ||
} | ||
return nil | ||
} | ||
return fmt.Errorf("extractActiveKey: active key of type %q not found", keyType) | ||
} | ||
} | ||
|
||
func keyName(attribute string, index int, key string) string { | ||
return fmt.Sprintf("%s.%d.%s", attribute, index, key) | ||
} |
Oops, something went wrong.