github.com/andresvia/terraform@v0.6.15-0.20160412045437-d51c75946785/builtin/providers/aws/resource_aws_kms_key.go (about) 1 package aws 2 3 import ( 4 "fmt" 5 "log" 6 "time" 7 8 "github.com/hashicorp/terraform/helper/resource" 9 "github.com/hashicorp/terraform/helper/schema" 10 11 "github.com/aws/aws-sdk-go/aws" 12 "github.com/aws/aws-sdk-go/service/kms" 13 ) 14 15 func resourceAwsKmsKey() *schema.Resource { 16 return &schema.Resource{ 17 Create: resourceAwsKmsKeyCreate, 18 Read: resourceAwsKmsKeyRead, 19 Update: resourceAwsKmsKeyUpdate, 20 Delete: resourceAwsKmsKeyDelete, 21 22 Schema: map[string]*schema.Schema{ 23 "arn": &schema.Schema{ 24 Type: schema.TypeString, 25 Computed: true, 26 }, 27 "key_id": &schema.Schema{ 28 Type: schema.TypeString, 29 Computed: true, 30 }, 31 "description": &schema.Schema{ 32 Type: schema.TypeString, 33 Optional: true, 34 Computed: true, 35 }, 36 "key_usage": &schema.Schema{ 37 Type: schema.TypeString, 38 Optional: true, 39 Computed: true, 40 ForceNew: true, 41 ValidateFunc: func(v interface{}, k string) (ws []string, es []error) { 42 value := v.(string) 43 if !(value == "ENCRYPT_DECRYPT" || value == "") { 44 es = append(es, fmt.Errorf( 45 "%q must be ENCRYPT_DECRYPT or not specified", k)) 46 } 47 return 48 }, 49 }, 50 "policy": &schema.Schema{ 51 Type: schema.TypeString, 52 Optional: true, 53 Computed: true, 54 StateFunc: normalizeJson, 55 }, 56 "is_enabled": &schema.Schema{ 57 Type: schema.TypeBool, 58 Optional: true, 59 Default: true, 60 }, 61 "enable_key_rotation": &schema.Schema{ 62 Type: schema.TypeBool, 63 Optional: true, 64 Default: false, 65 }, 66 "deletion_window_in_days": &schema.Schema{ 67 Type: schema.TypeInt, 68 Optional: true, 69 ValidateFunc: func(v interface{}, k string) (ws []string, es []error) { 70 value := v.(int) 71 if value > 30 || value < 7 { 72 es = append(es, fmt.Errorf( 73 "%q must be between 7 and 30 days inclusive", k)) 74 } 75 return 76 }, 77 }, 78 }, 79 } 80 } 81 82 func resourceAwsKmsKeyCreate(d *schema.ResourceData, meta interface{}) error { 83 conn := meta.(*AWSClient).kmsconn 84 85 // Allow aws to chose default values if we don't pass them 86 var req kms.CreateKeyInput 87 if v, exists := d.GetOk("description"); exists { 88 req.Description = aws.String(v.(string)) 89 } 90 if v, exists := d.GetOk("key_usage"); exists { 91 req.KeyUsage = aws.String(v.(string)) 92 } 93 if v, exists := d.GetOk("policy"); exists { 94 req.Policy = aws.String(v.(string)) 95 } 96 97 resp, err := conn.CreateKey(&req) 98 if err != nil { 99 return err 100 } 101 102 d.SetId(*resp.KeyMetadata.KeyId) 103 d.Set("key_id", resp.KeyMetadata.KeyId) 104 105 return _resourceAwsKmsKeyUpdate(d, meta, true) 106 } 107 108 func resourceAwsKmsKeyRead(d *schema.ResourceData, meta interface{}) error { 109 conn := meta.(*AWSClient).kmsconn 110 111 req := &kms.DescribeKeyInput{ 112 KeyId: aws.String(d.Id()), 113 } 114 resp, err := conn.DescribeKey(req) 115 if err != nil { 116 return err 117 } 118 metadata := resp.KeyMetadata 119 120 if *metadata.KeyState == "PendingDeletion" { 121 log.Printf("[WARN] Removing KMS key %s because it's already gone", d.Id()) 122 d.SetId("") 123 return nil 124 } 125 126 d.SetId(*metadata.KeyId) 127 128 d.Set("arn", metadata.Arn) 129 d.Set("key_id", metadata.KeyId) 130 d.Set("description", metadata.Description) 131 d.Set("key_usage", metadata.KeyUsage) 132 d.Set("is_enabled", metadata.Enabled) 133 134 p, err := conn.GetKeyPolicy(&kms.GetKeyPolicyInput{ 135 KeyId: metadata.KeyId, 136 PolicyName: aws.String("default"), 137 }) 138 if err != nil { 139 return err 140 } 141 142 d.Set("policy", normalizeJson(*p.Policy)) 143 144 krs, err := conn.GetKeyRotationStatus(&kms.GetKeyRotationStatusInput{ 145 KeyId: metadata.KeyId, 146 }) 147 if err != nil { 148 return err 149 } 150 d.Set("enable_key_rotation", krs.KeyRotationEnabled) 151 152 return nil 153 } 154 155 func resourceAwsKmsKeyUpdate(d *schema.ResourceData, meta interface{}) error { 156 return _resourceAwsKmsKeyUpdate(d, meta, false) 157 } 158 159 // We expect new keys to be enabled already 160 // but there is no easy way to differentiate between Update() 161 // called from Create() and regular update, so we have this wrapper 162 func _resourceAwsKmsKeyUpdate(d *schema.ResourceData, meta interface{}, isFresh bool) error { 163 conn := meta.(*AWSClient).kmsconn 164 165 if d.HasChange("is_enabled") && d.Get("is_enabled").(bool) && !isFresh { 166 // Enable before any attributes will be modified 167 if err := updateKmsKeyStatus(conn, d.Id(), d.Get("is_enabled").(bool)); err != nil { 168 return err 169 } 170 } 171 172 if d.HasChange("enable_key_rotation") { 173 if err := updateKmsKeyRotationStatus(conn, d); err != nil { 174 return err 175 } 176 } 177 178 if d.HasChange("description") { 179 if err := resourceAwsKmsKeyDescriptionUpdate(conn, d); err != nil { 180 return err 181 } 182 } 183 if d.HasChange("policy") { 184 if err := resourceAwsKmsKeyPolicyUpdate(conn, d); err != nil { 185 return err 186 } 187 } 188 189 if d.HasChange("is_enabled") && !d.Get("is_enabled").(bool) { 190 // Only disable when all attributes are modified 191 // because we cannot modify disabled keys 192 if err := updateKmsKeyStatus(conn, d.Id(), d.Get("is_enabled").(bool)); err != nil { 193 return err 194 } 195 } 196 197 return resourceAwsKmsKeyRead(d, meta) 198 } 199 200 func resourceAwsKmsKeyDescriptionUpdate(conn *kms.KMS, d *schema.ResourceData) error { 201 description := d.Get("description").(string) 202 keyId := d.Get("key_id").(string) 203 204 log.Printf("[DEBUG] KMS key: %s, update description: %s", keyId, description) 205 206 req := &kms.UpdateKeyDescriptionInput{ 207 Description: aws.String(description), 208 KeyId: aws.String(keyId), 209 } 210 _, err := conn.UpdateKeyDescription(req) 211 return err 212 } 213 214 func resourceAwsKmsKeyPolicyUpdate(conn *kms.KMS, d *schema.ResourceData) error { 215 policy := d.Get("policy").(string) 216 keyId := d.Get("key_id").(string) 217 218 log.Printf("[DEBUG] KMS key: %s, update policy: %s", keyId, policy) 219 220 req := &kms.PutKeyPolicyInput{ 221 KeyId: aws.String(keyId), 222 Policy: aws.String(normalizeJson(policy)), 223 PolicyName: aws.String("default"), 224 } 225 _, err := conn.PutKeyPolicy(req) 226 return err 227 } 228 229 func updateKmsKeyStatus(conn *kms.KMS, id string, shouldBeEnabled bool) error { 230 var err error 231 232 if shouldBeEnabled { 233 log.Printf("[DEBUG] Enabling KMS key %q", id) 234 _, err = conn.EnableKey(&kms.EnableKeyInput{ 235 KeyId: aws.String(id), 236 }) 237 } else { 238 log.Printf("[DEBUG] Disabling KMS key %q", id) 239 _, err = conn.DisableKey(&kms.DisableKeyInput{ 240 KeyId: aws.String(id), 241 }) 242 } 243 244 if err != nil { 245 return fmt.Errorf("Failed to set KMS key %q status to %t: %q", 246 id, shouldBeEnabled, err.Error()) 247 } 248 249 // Wait for propagation since KMS is eventually consistent 250 wait := resource.StateChangeConf{ 251 Pending: []string{fmt.Sprintf("%t", !shouldBeEnabled)}, 252 Target: []string{fmt.Sprintf("%t", shouldBeEnabled)}, 253 Timeout: 20 * time.Minute, 254 MinTimeout: 2 * time.Second, 255 ContinuousTargetOccurence: 10, 256 Refresh: func() (interface{}, string, error) { 257 log.Printf("[DEBUG] Checking if KMS key %s enabled status is %t", 258 id, shouldBeEnabled) 259 resp, err := conn.DescribeKey(&kms.DescribeKeyInput{ 260 KeyId: aws.String(id), 261 }) 262 if err != nil { 263 return resp, "FAILED", err 264 } 265 status := fmt.Sprintf("%t", *resp.KeyMetadata.Enabled) 266 log.Printf("[DEBUG] KMS key %s status received: %s, retrying", id, status) 267 268 return resp, status, nil 269 }, 270 } 271 272 _, err = wait.WaitForState() 273 if err != nil { 274 return fmt.Errorf("Failed setting KMS key status to %t: %s", shouldBeEnabled, err) 275 } 276 277 return nil 278 } 279 280 func updateKmsKeyRotationStatus(conn *kms.KMS, d *schema.ResourceData) error { 281 var err error 282 shouldEnableRotation := d.Get("enable_key_rotation").(bool) 283 if shouldEnableRotation { 284 log.Printf("[DEBUG] Enabling key rotation for KMS key %q", d.Id()) 285 _, err = conn.EnableKeyRotation(&kms.EnableKeyRotationInput{ 286 KeyId: aws.String(d.Id()), 287 }) 288 } else { 289 log.Printf("[DEBUG] Disabling key rotation for KMS key %q", d.Id()) 290 _, err = conn.DisableKeyRotation(&kms.DisableKeyRotationInput{ 291 KeyId: aws.String(d.Id()), 292 }) 293 } 294 295 if err != nil { 296 return fmt.Errorf("Failed to set key rotation for %q to %t: %q", 297 d.Id(), shouldEnableRotation, err.Error()) 298 } 299 300 // Wait for propagation since KMS is eventually consistent 301 wait := resource.StateChangeConf{ 302 Pending: []string{fmt.Sprintf("%t", !shouldEnableRotation)}, 303 Target: []string{fmt.Sprintf("%t", shouldEnableRotation)}, 304 Timeout: 5 * time.Minute, 305 MinTimeout: 1 * time.Second, 306 ContinuousTargetOccurence: 5, 307 Refresh: func() (interface{}, string, error) { 308 log.Printf("[DEBUG] Checking if KMS key %s rotation status is %t", 309 d.Id(), shouldEnableRotation) 310 resp, err := conn.GetKeyRotationStatus(&kms.GetKeyRotationStatusInput{ 311 KeyId: aws.String(d.Id()), 312 }) 313 if err != nil { 314 return resp, "FAILED", err 315 } 316 status := fmt.Sprintf("%t", *resp.KeyRotationEnabled) 317 log.Printf("[DEBUG] KMS key %s rotation status received: %s, retrying", d.Id(), status) 318 319 return resp, status, nil 320 }, 321 } 322 323 _, err = wait.WaitForState() 324 if err != nil { 325 return fmt.Errorf("Failed setting KMS key rotation status to %t: %s", shouldEnableRotation, err) 326 } 327 328 return nil 329 } 330 331 func resourceAwsKmsKeyDelete(d *schema.ResourceData, meta interface{}) error { 332 conn := meta.(*AWSClient).kmsconn 333 keyId := d.Get("key_id").(string) 334 335 req := &kms.ScheduleKeyDeletionInput{ 336 KeyId: aws.String(keyId), 337 } 338 if v, exists := d.GetOk("deletion_window_in_days"); exists { 339 req.PendingWindowInDays = aws.Int64(int64(v.(int))) 340 } 341 _, err := conn.ScheduleKeyDeletion(req) 342 if err != nil { 343 return err 344 } 345 346 // Wait for propagation since KMS is eventually consistent 347 wait := resource.StateChangeConf{ 348 Pending: []string{"Enabled", "Disabled"}, 349 Target: []string{"PendingDeletion"}, 350 Timeout: 20 * time.Minute, 351 MinTimeout: 2 * time.Second, 352 ContinuousTargetOccurence: 10, 353 Refresh: func() (interface{}, string, error) { 354 log.Printf("[DEBUG] Checking if KMS key %s state is PendingDeletion", keyId) 355 resp, err := conn.DescribeKey(&kms.DescribeKeyInput{ 356 KeyId: aws.String(keyId), 357 }) 358 if err != nil { 359 return resp, "Failed", err 360 } 361 362 metadata := *resp.KeyMetadata 363 log.Printf("[DEBUG] KMS key %s state is %s, retrying", keyId, *metadata.KeyState) 364 365 return resp, *metadata.KeyState, nil 366 }, 367 } 368 369 _, err = wait.WaitForState() 370 if err != nil { 371 return fmt.Errorf("Failed deactivating KMS key %s: %s", keyId, err) 372 } 373 374 log.Printf("[DEBUG] KMS Key %s deactivated.", keyId) 375 d.SetId("") 376 return nil 377 }