Skip to content

Commit

Permalink
feat(kms): support key rotation management (#762)
Browse files Browse the repository at this point in the history
  • Loading branch information
ShiChangkuo authored Jun 15, 2022
1 parent a60efff commit a9eb1e7
Show file tree
Hide file tree
Showing 8 changed files with 230 additions and 32 deletions.
14 changes: 7 additions & 7 deletions docs/data-sources/kms_key_v1.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,15 @@
subcategory: "Key Management Service (KMS)"
---

# flexibleengine\_kms\_key_v1
# flexibleengine_kms_key_v1

Use this data source to get the ID of an available FlexibleEngine KMS key.

## Example Usage

```hcl
data "flexibleengine_kms_key_v1" "key_1" {
key_alias = "test_key"
key_description = "test key description"
key_state = "2"
key_id = "af650527-a0ff-4527-aef3-c493df1f3012"
key_alias = "test_key"
}
```

Expand Down Expand Up @@ -42,8 +39,11 @@ data "flexibleengine_kms_key_v1" "key_1" {

## Attributes Reference

`id` is set to the ID of the found key. In addition, the following attributes
are exported:
In addition to all arguments above, the following attributes are exported:

* `id` - The data source ID in UUID format.
* `creation_date` - Creation time (time stamp) of a key.
* `scheduled_deletion_date` - Scheduled deletion time (time stamp) of a key.
* `rotation_enabled` - Indicates whether the key rotation is enabled or not.
* `rotation_interval` - The key rotation interval. It's valid when rotation is enabled.
* `rotation_number` - The total number of key rotations. It's valid when rotation is enabled.
17 changes: 9 additions & 8 deletions docs/resources/kms_key_v1.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
subcategory: "Key Management Service (KMS)"
---

# flexibleengine\_kms\_key_v1
# flexibleengine_kms_key_v1

Manages a V1 key resource within KMS.

Expand All @@ -22,21 +22,22 @@ resource "flexibleengine_kms_key_v1" "key_1" {

The following arguments are supported:

* `key_alias` - (Required) The alias in which to create the key. It is required when
we create a new key. Changing this updates the alias of key.
* `key_alias` - (Required) Specifies the name of a KMS key.

* `key_description` - (Optional) The description of the key as viewed in FlexibleEngine console.
Changing this updates the description of key.
* `key_description` - (Optional) Specifies the description of a KMS key.

* `realm` - (Optional) Region where a key resides. Changing this creates a new key.

* `pending_days` - (Optional) Duration in days after which the key is deleted
* `pending_days` - (Optional) Specifies the duration in days after which the key is deleted
after destruction of the resource, must be between 7 and 1096 days. Defaults to 7.
It only be used when delete a key.

* `is_enabled` - (Optional) Specifies whether the key is enabled. Defaults to true.
Changing this updates the state of existing key.

* `rotation_enabled` - (Optional) Specifies whether the key rotation is enabled. Defaults to false.

* `rotation_interval` - (Optional) Specifies the key rotation interval. The valid value is range from 30 to 365,
defaults to 365.

## Attributes Reference

Expand All @@ -48,7 +49,7 @@ In addition to all arguments above, the following attributes are exported:
* `origin` - Origin of a key. The default value is kms.
* `domain_id` - ID of a user domain for the key.
* `creation_date` - Creation time (time stamp) of a key.

* `rotation_number` - The total number of key rotations.

## Import

Expand Down
28 changes: 28 additions & 0 deletions flexibleengine/data_source_flexibleengine_kms_key_v1.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"reflect"

"github.com/chnsz/golangsdk/openstack/kms/v1/keys"
"github.com/chnsz/golangsdk/openstack/kms/v1/rotation"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)
Expand Down Expand Up @@ -72,6 +73,18 @@ func dataSourceKmsKeyV1() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"rotation_enabled": {
Type: schema.TypeBool,
Computed: true,
},
"rotation_interval": {
Type: schema.TypeInt,
Computed: true,
},
"rotation_number": {
Type: schema.TypeInt,
Computed: true,
},
},
}
}
Expand Down Expand Up @@ -177,5 +190,20 @@ func dataSourceKmsKeyV1Read(d *schema.ResourceData, meta interface{}) error {
d.Set("creation_date", key.CreationDate)
d.Set("scheduled_deletion_date", key.ScheduledDeletionDate)

// Set KMS rotation
rotationOpts := &rotation.RotationOpts{
KeyID: key.KeyID,
}
r, err := rotation.Get(kmsClient, rotationOpts).Extract()
if err == nil {
d.Set("rotation_enabled", r.Enabled)
if r.Enabled {
d.Set("rotation_interval", r.Interval)
d.Set("rotation_number", r.NumberOfRotations)
}
} else {
log.Printf("[WARN] Error fetching details about key rotation: %s", err)
}

return nil
}
8 changes: 5 additions & 3 deletions flexibleengine/data_source_flexibleengine_kms_key_v1_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
var keyAlias = fmt.Sprintf("key_alias_%s", acctest.RandString(5))

func TestAccKmsKeyV1DataSource_basic(t *testing.T) {
datasourceName := "data.flexibleengine_kms_key_v1.key1"

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Expand All @@ -22,9 +24,9 @@ func TestAccKmsKeyV1DataSource_basic(t *testing.T) {
{
Config: testAccKmsKeyV1DataSource_basic,
Check: resource.ComposeTestCheckFunc(
testAccCheckKmsKeyV1DataSourceID("data.flexibleengine_kms_key_v1.key1"),
resource.TestCheckResourceAttr(
"data.flexibleengine_kms_key_v1.key1", "key_alias", keyAlias),
testAccCheckKmsKeyV1DataSourceID(datasourceName),
resource.TestCheckResourceAttr(datasourceName, "key_alias", keyAlias),
resource.TestCheckResourceAttr(datasourceName, "rotation_enabled", "false"),
),
},
},
Expand Down
112 changes: 101 additions & 11 deletions flexibleengine/resource_flexibleengine_kms_key_v1.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ import (
"log"
"time"

"github.com/chnsz/golangsdk"
"github.com/chnsz/golangsdk/openstack/kms/v1/keys"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"

"github.com/chnsz/golangsdk"
"github.com/chnsz/golangsdk/openstack/kms/v1/keys"
"github.com/chnsz/golangsdk/openstack/kms/v1/rotation"
)

const (
Expand Down Expand Up @@ -47,6 +50,17 @@ func resourceKmsKeyV1() *schema.Resource {
Optional: true,
Default: true,
},
"rotation_enabled": {
Type: schema.TypeBool,
Optional: true,
},
"rotation_interval": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
RequiredWith: []string{"rotation_enabled"},
ValidateFunc: validation.IntBetween(30, 365),
},
"realm": {
Type: schema.TypeString,
Optional: true,
Expand All @@ -69,10 +83,24 @@ func resourceKmsKeyV1() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"rotation_number": {
Type: schema.TypeInt,
Computed: true,
},
},
}
}

func resourceKmsKeyValidation(d *schema.ResourceData) error {
_, rotationEnabled := d.GetOk("rotation_enabled")
_, hasInterval := d.GetOk("rotation_interval")

if !rotationEnabled && hasInterval {
return fmt.Errorf("invalid arguments: rotation_interval is only valid when rotation is enabled")
}
return nil
}

func resourceKmsKeyV1Create(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
kmsClient, err := config.KmsKeyV1Client(GetRegion(d, config))
Expand All @@ -91,11 +119,12 @@ func resourceKmsKeyV1Create(d *schema.ResourceData, meta interface{}) error {
if err != nil {
return fmt.Errorf("Error creating FlexibleEngine key: %s", err)
}
log.Printf("[INFO] Key ID: %s", v.KeyID)

// Store the key ID now
d.SetId(v.KeyID)

// Wait for the key to become enabled.
log.Printf("[DEBUG] Waiting for key (%s) to become enabled", v.KeyID)

stateConf := &resource.StateChangeConf{
Pending: []string{WaitingForEnableState, DisabledState},
Target: []string{EnabledState},
Expand Down Expand Up @@ -123,8 +152,27 @@ func resourceKmsKeyV1Create(d *schema.ResourceData, meta interface{}) error {
}
}

// Store the key ID now
d.SetId(v.KeyID)
// enable rotation and change interval if necessary
if _, ok := d.GetOk("rotation_enabled"); ok {
rotationOpts := &rotation.RotationOpts{
KeyID: v.KeyID,
}
err := rotation.Enable(kmsClient, rotationOpts).ExtractErr()
if err != nil {
return fmt.Errorf("failed to enable key rotation: %s", err)
}

if i, ok := d.GetOk("rotation_interval"); ok {
intervalOpts := &rotation.IntervalOpts{
KeyID: v.KeyID,
Interval: i.(int),
}
err := rotation.Update(kmsClient, intervalOpts).ExtractErr()
if err != nil {
return fmt.Errorf("failed to change key rotation interval: %s", err)
}
}
}

return resourceKmsKeyV1Read(d, meta)
}
Expand Down Expand Up @@ -163,6 +211,19 @@ func resourceKmsKeyV1Read(d *schema.ResourceData, meta interface{}) error {
d.Set("pending_days", "7")
}

// Set KMS rotation
rotationOpts := &rotation.RotationOpts{
KeyID: v.KeyID,
}
r, err := rotation.Get(kmsClient, rotationOpts).Extract()
if err == nil {
d.Set("rotation_enabled", r.Enabled)
d.Set("rotation_interval", r.Interval)
d.Set("rotation_number", r.NumberOfRotations)
} else {
log.Printf("[WARN] Error fetching details about key rotation: %s", err)
}

return nil
}

Expand All @@ -173,9 +234,10 @@ func resourceKmsKeyV1Update(d *schema.ResourceData, meta interface{}) error {
return fmt.Errorf("Error creating FlexibleEngine kms key client: %s", err)
}

keyID := d.Id()
if d.HasChange("key_alias") {
updateAliasOpts := keys.UpdateAliasOpts{
KeyID: d.Id(),
KeyID: keyID,
KeyAlias: d.Get("key_alias").(string),
}
_, err = keys.UpdateAlias(kmsClient, updateAliasOpts).ExtractKeyInfo()
Expand All @@ -186,7 +248,7 @@ func resourceKmsKeyV1Update(d *schema.ResourceData, meta interface{}) error {

if d.HasChange("key_description") {
updateDesOpts := keys.UpdateDesOpts{
KeyID: d.Id(),
KeyID: keyID,
KeyDescription: d.Get("key_description").(string),
}
_, err = keys.UpdateDes(kmsClient, updateDesOpts).ExtractKeyInfo()
Expand All @@ -196,13 +258,13 @@ func resourceKmsKeyV1Update(d *schema.ResourceData, meta interface{}) error {
}

if d.HasChange("is_enabled") {
v, err := keys.Get(kmsClient, d.Id()).ExtractKeyInfo()
v, err := keys.Get(kmsClient, keyID).ExtractKeyInfo()
if err != nil {
return fmt.Errorf("Error fetching FlexibleEngine key: %s", err)
}

if d.Get("is_enabled").(bool) && v.KeyState == DisabledState {
key, err := keys.EnableKey(kmsClient, d.Id()).ExtractKeyInfo()
key, err := keys.EnableKey(kmsClient, keyID).ExtractKeyInfo()
if err != nil {
return fmt.Errorf("Error enabling key: %s", err)
}
Expand All @@ -212,7 +274,7 @@ func resourceKmsKeyV1Update(d *schema.ResourceData, meta interface{}) error {
}

if !d.Get("is_enabled").(bool) && v.KeyState == EnabledState {
key, err := keys.DisableKey(kmsClient, d.Id()).ExtractKeyInfo()
key, err := keys.DisableKey(kmsClient, keyID).ExtractKeyInfo()
if err != nil {
return fmt.Errorf("Error disabling key: %s", err)
}
Expand All @@ -222,6 +284,34 @@ func resourceKmsKeyV1Update(d *schema.ResourceData, meta interface{}) error {
}
}

_, rotationEnabled := d.GetOk("rotation_enabled")
if d.HasChange("rotation_enabled") {
var rotationErr error
rotationOpts := &rotation.RotationOpts{
KeyID: keyID,
}
if rotationEnabled {
rotationErr = rotation.Enable(kmsClient, rotationOpts).ExtractErr()
} else {
rotationErr = rotation.Disable(kmsClient, rotationOpts).ExtractErr()
}

if rotationErr != nil {
return fmt.Errorf("failed to update key rotation status: %s", err)
}
}

if rotationEnabled && d.HasChange("rotation_interval") {
intervalOpts := &rotation.IntervalOpts{
KeyID: keyID,
Interval: d.Get("rotation_interval").(int),
}
err := rotation.Update(kmsClient, intervalOpts).ExtractErr()
if err != nil {
return fmt.Errorf("failed to change key rotation interval: %s", err)
}
}

return resourceKmsKeyV1Read(d, meta)
}

Expand Down
Loading

0 comments on commit a9eb1e7

Please sign in to comment.