|
| 1 | +/* |
| 2 | +Provide a resource to create a KMS external import key. |
| 3 | +
|
| 4 | +Example Usage |
| 5 | +
|
| 6 | +```hcl |
| 7 | +resource "tencentcloud_kms_external_key" "foo" { |
| 8 | + alias = "test" |
| 9 | + description = "describe key test message." |
| 10 | + wrapping_algorithm = "RSAES_PKCS1_V1_5" |
| 11 | + key_material_base64 = "MTIzMTIzMTIzMTIzMTIzQQ==" |
| 12 | + valid_to = 2147443200 |
| 13 | +} |
| 14 | +``` |
| 15 | +
|
| 16 | +Import |
| 17 | +
|
| 18 | +KMS external keys can be imported using the id, e.g. |
| 19 | +
|
| 20 | +``` |
| 21 | +$ terraform import tencentcloud_kms_external_key.foo 287e8f40-7cbb-11eb-9a3a-5254004f7f94 |
| 22 | +``` |
| 23 | +*/ |
| 24 | +package tencentcloud |
| 25 | + |
| 26 | +import ( |
| 27 | + "context" |
| 28 | + "log" |
| 29 | + |
| 30 | + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" |
| 31 | + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" |
| 32 | + kms "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms/v20190118" |
| 33 | + "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/internal/helper" |
| 34 | +) |
| 35 | + |
| 36 | +func resourceTencentCloudKmsExternalKey() *schema.Resource { |
| 37 | + return &schema.Resource{ |
| 38 | + Create: resourceTencentCloudKmsExternalKeyCreate, |
| 39 | + Read: resourceTencentCloudKmsExternalKeyRead, |
| 40 | + Update: resourceTencentCloudKmsExternalKeyUpdate, |
| 41 | + Delete: resourceTencentCloudKmsExternalKeyDelete, |
| 42 | + Importer: &schema.ResourceImporter{ |
| 43 | + State: schema.ImportStatePassthrough, |
| 44 | + }, |
| 45 | + |
| 46 | + Schema: map[string]*schema.Schema{ |
| 47 | + "key_id": { |
| 48 | + Type: schema.TypeString, |
| 49 | + Optional: true, |
| 50 | + Computed: true, |
| 51 | + Description: "ID of CMK.", |
| 52 | + }, |
| 53 | + "alias": { |
| 54 | + Type: schema.TypeString, |
| 55 | + Required: true, |
| 56 | + ValidateFunc: validateStringLengthInRange(1, 60), |
| 57 | + Description: "Name of CMK.The name can only contain English letters, numbers, underscore and hyphen '-'.The first character must be a letter or number.", |
| 58 | + }, |
| 59 | + "description": { |
| 60 | + Type: schema.TypeString, |
| 61 | + Optional: true, |
| 62 | + Computed: true, |
| 63 | + Description: "Description of CMK.The maximum is 1024 bytes.", |
| 64 | + }, |
| 65 | + "key_state": { |
| 66 | + Type: schema.TypeString, |
| 67 | + Optional: true, |
| 68 | + ValidateFunc: validateAllowedStringValue(KMS_KEY_STATE), |
| 69 | + Computed: true, |
| 70 | + Description: "State of CMK.Available values include `Enabled`, `Disabled`, `PendingDelete`, `PendingImport`, `Archived`.", |
| 71 | + }, |
| 72 | + "pending_delete_window_in_days": { |
| 73 | + Type: schema.TypeInt, |
| 74 | + Optional: true, |
| 75 | + Default: 7, |
| 76 | + ValidateFunc: validateIntegerInRange(7, 30), |
| 77 | + Description: "Duration in days after which the key is deleted after destruction of the resource, must be between 7 and 30 days. Defaults to 7 days.", |
| 78 | + }, |
| 79 | + "wrapping_algorithm": { |
| 80 | + Type: schema.TypeString, |
| 81 | + Optional: true, |
| 82 | + Default: KMS_WRAPPING_ALGORITHM_RSAES_PKCS1_V1_5, |
| 83 | + ValidateFunc: validateAllowedStringValue(KMS_WRAPPING_ALGORITHM), |
| 84 | + Description: "The algorithm for encrypting key material.Available values include `RSAES_PKCS1_V1_5`, `RSAES_OAEP_SHA_1` and `RSAES_OAEP_SHA_256`.", |
| 85 | + }, |
| 86 | + "key_material_base64": { |
| 87 | + Type: schema.TypeString, |
| 88 | + Optional: true, |
| 89 | + Sensitive: true, |
| 90 | + Description: "The base64-encoded key material encrypted with the public_key.For regions using the national secret version, the length of the imported key material is required to be 128 bits, and for regions using the FIPS version, the length of the imported key material is required to be 256 bits。", |
| 91 | + }, |
| 92 | + "valid_to": { |
| 93 | + Type: schema.TypeInt, |
| 94 | + Optional: true, |
| 95 | + Computed: true, |
| 96 | + Description: "this value means the effective timestamp of the key material, 0 means it does not expire.Need to be greater than the current time point, the maximum support is 2147443200.", |
| 97 | + }, |
| 98 | + "tags": { |
| 99 | + Type: schema.TypeMap, |
| 100 | + Optional: true, |
| 101 | + Computed: true, |
| 102 | + Description: "Tags of CMK.", |
| 103 | + }, |
| 104 | + }, |
| 105 | + } |
| 106 | +} |
| 107 | + |
| 108 | +func resourceTencentCloudKmsExternalKeyCreate(d *schema.ResourceData, meta interface{}) error { |
| 109 | + defer logElapsed("resource.tencentcloud_kms_external_key.create")() |
| 110 | + |
| 111 | + logId := getLogId(contextNil) |
| 112 | + ctx := context.WithValue(context.TODO(), logIdKey, logId) |
| 113 | + kmsService := KmsService{ |
| 114 | + client: meta.(*TencentCloudClient).apiV3Conn, |
| 115 | + } |
| 116 | + |
| 117 | + keyType := KMS_ORIGIN_TYPE[KMS_ORIGIN_EXTERNAL] |
| 118 | + alias := d.Get("alias").(string) |
| 119 | + description := "" |
| 120 | + keyUsage := KMS_KEY_USAGE_ENCRYPT_DECRYPT |
| 121 | + if v, ok := d.GetOk("description"); ok { |
| 122 | + description = v.(string) |
| 123 | + } |
| 124 | + |
| 125 | + var keyId string |
| 126 | + var outErr, inErr error |
| 127 | + outErr = resource.Retry(writeRetryTimeout, func() *resource.RetryError { |
| 128 | + keyId, inErr = kmsService.CreateKey(ctx, keyType, alias, description, keyUsage) |
| 129 | + if inErr != nil { |
| 130 | + return retryError(inErr) |
| 131 | + } |
| 132 | + return nil |
| 133 | + }) |
| 134 | + if outErr != nil { |
| 135 | + log.Printf("[CRITAL]%s create KMS key failed, reason:%+v", logId, outErr) |
| 136 | + return outErr |
| 137 | + } |
| 138 | + d.SetId(keyId) |
| 139 | + _ = d.Set("key_id", helper.String(keyId)) |
| 140 | + |
| 141 | + if v, ok := d.GetOk("key_material_base64"); ok { |
| 142 | + param := make(map[string]interface{}) |
| 143 | + param["key_id"] = keyId |
| 144 | + param["algorithm"] = d.Get("wrapping_algorithm").(string) |
| 145 | + param["key_spec"] = KMS_WRAPPING_KEY_SPEC_RSA_2048 |
| 146 | + param["key_material_base64"] = v.(string) |
| 147 | + param["valid_to"] = d.Get("valid_to").(int) |
| 148 | + |
| 149 | + err := resource.Retry(writeRetryTimeout, func() *resource.RetryError { |
| 150 | + e := kmsService.ImportKeyMaterial(ctx, param) |
| 151 | + if e != nil { |
| 152 | + return retryError(e) |
| 153 | + } |
| 154 | + return nil |
| 155 | + }) |
| 156 | + if err != nil { |
| 157 | + log.Printf("[CRITAL]%s Create KMS external key failed, reason:%+v", logId, err) |
| 158 | + return err |
| 159 | + } |
| 160 | + } |
| 161 | + |
| 162 | + if keyState := d.Get("key_state").(string); keyState == KMS_KEY_STATE_DISABLED { |
| 163 | + err := resource.Retry(writeRetryTimeout, func() *resource.RetryError { |
| 164 | + e := kmsService.DisableKey(ctx, d.Id()) |
| 165 | + if e != nil { |
| 166 | + return retryError(e) |
| 167 | + } |
| 168 | + return nil |
| 169 | + }) |
| 170 | + if err != nil { |
| 171 | + log.Printf("[CRITAL]%s modify KMS key state failed, reason:%+v", logId, err) |
| 172 | + return err |
| 173 | + } |
| 174 | + } |
| 175 | + |
| 176 | + if tags := helper.GetTags(d, "tags"); len(tags) > 0 { |
| 177 | + tcClient := meta.(*TencentCloudClient).apiV3Conn |
| 178 | + tagService := &TagService{client: tcClient} |
| 179 | + keyMetaData, err := kmsService.DescribeKeyById(ctx, keyId) |
| 180 | + if err != nil { |
| 181 | + return err |
| 182 | + } |
| 183 | + resourceName := BuildTagResourceName("kms", "key", tcClient.Region, *keyMetaData.ResourceId) |
| 184 | + if err := tagService.ModifyTags(ctx, resourceName, tags, nil); err != nil { |
| 185 | + return err |
| 186 | + } |
| 187 | + } |
| 188 | + |
| 189 | + return resourceTencentCloudKmsExternalKeyRead(d, meta) |
| 190 | +} |
| 191 | + |
| 192 | +func resourceTencentCloudKmsExternalKeyRead(d *schema.ResourceData, meta interface{}) error { |
| 193 | + defer logElapsed("resource.tencentcloud_kms_external_key.read")() |
| 194 | + defer inconsistentCheck(d, meta)() |
| 195 | + |
| 196 | + logId := getLogId(contextNil) |
| 197 | + ctx := context.WithValue(context.TODO(), logIdKey, logId) |
| 198 | + |
| 199 | + keyId := d.Id() |
| 200 | + kmsService := &KmsService{ |
| 201 | + client: meta.(*TencentCloudClient).apiV3Conn, |
| 202 | + } |
| 203 | + var key *kms.KeyMetadata |
| 204 | + err := resource.Retry(readRetryTimeout, func() *resource.RetryError { |
| 205 | + result, e := kmsService.DescribeKeyById(ctx, keyId) |
| 206 | + if e != nil { |
| 207 | + return retryError(e) |
| 208 | + } |
| 209 | + key = result |
| 210 | + return nil |
| 211 | + }) |
| 212 | + if err != nil { |
| 213 | + log.Printf("[CRITAL]%s read KMS external key failed, reason:%+v", logId, err) |
| 214 | + return err |
| 215 | + } |
| 216 | + |
| 217 | + if key == nil { |
| 218 | + d.SetId("") |
| 219 | + return nil |
| 220 | + } |
| 221 | + |
| 222 | + _ = d.Set("key_id", key.KeyId) |
| 223 | + _ = d.Set("alias", key.Alias) |
| 224 | + _ = d.Set("description", key.Description) |
| 225 | + _ = d.Set("key_state", key.KeyState) |
| 226 | + tcClient := meta.(*TencentCloudClient).apiV3Conn |
| 227 | + tagService := &TagService{client: tcClient} |
| 228 | + tags, err := tagService.DescribeResourceTags(ctx, "kms", "key", tcClient.Region, *key.ResourceId) |
| 229 | + if err != nil { |
| 230 | + return err |
| 231 | + } |
| 232 | + _ = d.Set("tags", tags) |
| 233 | + return nil |
| 234 | +} |
| 235 | + |
| 236 | +func resourceTencentCloudKmsExternalKeyUpdate(d *schema.ResourceData, meta interface{}) error { |
| 237 | + defer logElapsed("resource.tencentcloud_kms_external_key.update")() |
| 238 | + |
| 239 | + logId := getLogId(contextNil) |
| 240 | + ctx := context.WithValue(context.TODO(), logIdKey, logId) |
| 241 | + keyId := d.Id() |
| 242 | + kmsService := KmsService{ |
| 243 | + client: meta.(*TencentCloudClient).apiV3Conn, |
| 244 | + } |
| 245 | + |
| 246 | + if d.HasChange("description") { |
| 247 | + description := d.Get("description").(string) |
| 248 | + err := resource.Retry(writeRetryTimeout, func() *resource.RetryError { |
| 249 | + e := kmsService.UpdateKeyDescription(ctx, keyId, description) |
| 250 | + if e != nil { |
| 251 | + return retryError(e) |
| 252 | + } |
| 253 | + return nil |
| 254 | + }) |
| 255 | + if err != nil { |
| 256 | + log.Printf("[CRITAL]%s modify KMS external key description failed, reason:%+v", logId, err) |
| 257 | + return err |
| 258 | + } |
| 259 | + } |
| 260 | + |
| 261 | + if d.HasChange("alias") { |
| 262 | + alias := d.Get("alias").(string) |
| 263 | + err := resource.Retry(writeRetryTimeout, func() *resource.RetryError { |
| 264 | + e := kmsService.UpdateKeyAlias(ctx, keyId, alias) |
| 265 | + if e != nil { |
| 266 | + return retryError(e) |
| 267 | + } |
| 268 | + return nil |
| 269 | + }) |
| 270 | + if err != nil { |
| 271 | + log.Printf("[CRITAL]%s modify KMS external key alias failed, reason:%+v", logId, err) |
| 272 | + return err |
| 273 | + } |
| 274 | + } |
| 275 | + |
| 276 | + if d.HasChange("key_material_base64") || d.HasChange("valid_to") { |
| 277 | + err := updateKeyMaterial(ctx, kmsService, d) |
| 278 | + if err != nil { |
| 279 | + log.Printf("[CRITAL]%s import KMS external key material key failed, reason:%+v", logId, err) |
| 280 | + return err |
| 281 | + } |
| 282 | + } |
| 283 | + |
| 284 | + if d.HasChange("key_state") { |
| 285 | + oldKeyState, newKeyState := d.GetChange("key_state") |
| 286 | + err := updateKeyState(ctx, kmsService, keyId, oldKeyState.(string), newKeyState.(string)) |
| 287 | + if err != nil { |
| 288 | + log.Printf("[CRITAL]%s modify KMS key state failed, reason:%+v", logId, err) |
| 289 | + return err |
| 290 | + } |
| 291 | + } |
| 292 | + |
| 293 | + if d.HasChange("tags") { |
| 294 | + tcClient := meta.(*TencentCloudClient).apiV3Conn |
| 295 | + tagService := &TagService{client: tcClient} |
| 296 | + |
| 297 | + oldValue, newValue := d.GetChange("tags") |
| 298 | + replaceTags, deleteTags := diffTags(oldValue.(map[string]interface{}), newValue.(map[string]interface{})) |
| 299 | + keyMetaData, err := kmsService.DescribeKeyById(ctx, keyId) |
| 300 | + if err != nil { |
| 301 | + return err |
| 302 | + } |
| 303 | + resourceName := BuildTagResourceName("kms", "key", tcClient.Region, *keyMetaData.ResourceId) |
| 304 | + if err := tagService.ModifyTags(ctx, resourceName, replaceTags, deleteTags); err != nil { |
| 305 | + return err |
| 306 | + } |
| 307 | + } |
| 308 | + |
| 309 | + return resourceTencentCloudKmsKeyRead(d, meta) |
| 310 | +} |
| 311 | + |
| 312 | +func resourceTencentCloudKmsExternalKeyDelete(d *schema.ResourceData, meta interface{}) error { |
| 313 | + defer logElapsed("resource.tencentcloud_kms_external_key.delete")() |
| 314 | + |
| 315 | + logId := getLogId(contextNil) |
| 316 | + ctx := context.WithValue(context.TODO(), logIdKey, logId) |
| 317 | + kmsService := KmsService{ |
| 318 | + client: meta.(*TencentCloudClient).apiV3Conn, |
| 319 | + } |
| 320 | + |
| 321 | + keyId := d.Id() |
| 322 | + pendingDeleteWindowInDays := d.Get("pending_delete_window_in_days").(int) |
| 323 | + err := resource.Retry(writeRetryTimeout, func() *resource.RetryError { |
| 324 | + e := kmsService.DeleteKey(ctx, keyId, uint64(pendingDeleteWindowInDays)) |
| 325 | + if e != nil { |
| 326 | + return retryError(e) |
| 327 | + } |
| 328 | + return nil |
| 329 | + }) |
| 330 | + if err != nil { |
| 331 | + log.Printf("[CRITAL]%s delete KMS key failed, reason:%+v", logId, err) |
| 332 | + return err |
| 333 | + } |
| 334 | + |
| 335 | + return resourceTencentCloudKmsKeyRead(d, meta) |
| 336 | +} |
| 337 | + |
| 338 | +func updateKeyMaterial(ctx context.Context, kmsService KmsService, d *schema.ResourceData) error { |
| 339 | + param := make(map[string]interface{}) |
| 340 | + param["key_id"] = d.Id() |
| 341 | + param["algorithm"] = d.Get("wrapping_algorithm").(string) |
| 342 | + param["key_spec"] = KMS_WRAPPING_KEY_SPEC_RSA_2048 |
| 343 | + param["key_material_base64"] = d.Get("key_material_base64") |
| 344 | + param["valid_to"] = d.Get("valid_to").(int) |
| 345 | + |
| 346 | + var err error |
| 347 | + if param["key_material_base64"] == "" { |
| 348 | + err = resource.Retry(writeRetryTimeout, func() *resource.RetryError { |
| 349 | + e := kmsService.DeleteImportKeyMaterial(ctx, d.Id()) |
| 350 | + if e != nil { |
| 351 | + return retryError(e) |
| 352 | + } |
| 353 | + return nil |
| 354 | + }) |
| 355 | + } else { |
| 356 | + err = resource.Retry(writeRetryTimeout, func() *resource.RetryError { |
| 357 | + e := kmsService.ImportKeyMaterial(ctx, param) |
| 358 | + if e != nil { |
| 359 | + return retryError(e) |
| 360 | + } |
| 361 | + return nil |
| 362 | + }) |
| 363 | + } |
| 364 | + |
| 365 | + return err |
| 366 | +} |
0 commit comments