|
| 1 | +/* |
| 2 | +Provides a resource to create a ssm ssh key pair secret |
| 3 | +
|
| 4 | +Example Usage |
| 5 | +
|
| 6 | +```hcl |
| 7 | +data "tencentcloud_kms_keys" "kms" { |
| 8 | + key_state = 1 |
| 9 | +} |
| 10 | +
|
| 11 | +resource "tencentcloud_ssm_ssh_key_pair_secret" "ssh_key_pair_secret" { |
| 12 | + secret_name = "tf-ssh-key-secret" |
| 13 | + project_id = 0 |
| 14 | + description = "for tf test" |
| 15 | + kms_key_id = data.tencentcloud_kms_keys.kms.key_list.0.key_id |
| 16 | + ssh_key_name = "tf_ssh_test" |
| 17 | + status = "Disabled" |
| 18 | + tags = { |
| 19 | + "test" = "test" |
| 20 | + } |
| 21 | + clean_ssh_key = true |
| 22 | +} |
| 23 | +``` |
| 24 | +
|
| 25 | +Import |
| 26 | +
|
| 27 | +ssm ssh_key_pair_secret can be imported using the id, e.g. |
| 28 | +
|
| 29 | +``` |
| 30 | +terraform import tencentcloud_ssm_ssh_key_pair_secret.ssh_key_pair_secret ssh_key_pair_secret_name |
| 31 | +``` |
| 32 | +*/ |
| 33 | +package tencentcloud |
| 34 | + |
| 35 | +import ( |
| 36 | + "context" |
| 37 | + "fmt" |
| 38 | + "log" |
| 39 | + |
| 40 | + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" |
| 41 | + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" |
| 42 | + ssm "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssm/v20190923" |
| 43 | + "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/internal/helper" |
| 44 | +) |
| 45 | + |
| 46 | +func resourceTencentCloudSsmSshKeyPairSecret() *schema.Resource { |
| 47 | + return &schema.Resource{ |
| 48 | + Create: resourceTencentCloudSsmSshKeyPairSecretCreate, |
| 49 | + Read: resourceTencentCloudSsmSshKeyPairSecretRead, |
| 50 | + Update: resourceTencentCloudSsmSshKeyPairSecretUpdate, |
| 51 | + Delete: resourceTencentCloudSsmSshKeyPairSecretDelete, |
| 52 | + Importer: &schema.ResourceImporter{ |
| 53 | + State: schema.ImportStatePassthrough, |
| 54 | + }, |
| 55 | + Schema: map[string]*schema.Schema{ |
| 56 | + "secret_name": { |
| 57 | + Required: true, |
| 58 | + Type: schema.TypeString, |
| 59 | + ForceNew: true, |
| 60 | + Description: "Secret name, which must be unique in the same region. It can contain 128 bytes of letters, digits, hyphens and underscores and must begin with a letter or digit.", |
| 61 | + }, |
| 62 | + |
| 63 | + "project_id": { |
| 64 | + Required: true, |
| 65 | + Type: schema.TypeInt, |
| 66 | + Description: "ID of the project to which the created SSH key belongs.", |
| 67 | + }, |
| 68 | + |
| 69 | + "description": { |
| 70 | + Optional: true, |
| 71 | + Type: schema.TypeString, |
| 72 | + Description: "Description, such as what it is used for. It contains up to 2,048 bytes.", |
| 73 | + }, |
| 74 | + |
| 75 | + "kms_key_id": { |
| 76 | + Optional: true, |
| 77 | + Type: schema.TypeString, |
| 78 | + Description: "Specifies a KMS CMK to encrypt the secret.If this parameter is left empty, the CMK created by Secrets Manager by default will be used for encryption.You can also specify a custom KMS CMK created in the same region for encryption.", |
| 79 | + }, |
| 80 | + |
| 81 | + "ssh_key_name": { |
| 82 | + Optional: true, |
| 83 | + Type: schema.TypeString, |
| 84 | + Description: "Name of the SSH key pair, which only contains digits, letters and underscores and must start with a digit or letter. The maximum length is 25 characters.", |
| 85 | + }, |
| 86 | + |
| 87 | + "status": { |
| 88 | + Optional: true, |
| 89 | + Type: schema.TypeString, |
| 90 | + Computed: true, |
| 91 | + ValidateFunc: validateAllowedStringValue([]string{"Enabled", "Disabled"}), |
| 92 | + Description: "Enable or Disable Secret. Valid values is `Enabled` or `Disabled`. Default is `Enabled`.", |
| 93 | + }, |
| 94 | + |
| 95 | + "clean_ssh_key": { |
| 96 | + Optional: true, |
| 97 | + Type: schema.TypeBool, |
| 98 | + Description: "Specifies whether to delete the SSH key from both the secret and the SSH key list in the CVM console. This field is only take effect when delete SSH key secrets. Valid values: " + |
| 99 | + "`True`: deletes SSH key from both the secret and SSH key list in the CVM console. Note that the deletion will fail if the SSH key is already bound to a CVM instance." + |
| 100 | + "`False`: only deletes the SSH key information in the secret.", |
| 101 | + }, |
| 102 | + |
| 103 | + "create_time": { |
| 104 | + Type: schema.TypeInt, |
| 105 | + Computed: true, |
| 106 | + Description: "Credential creation time in UNIX timestamp format.", |
| 107 | + }, |
| 108 | + |
| 109 | + "secret_type": { |
| 110 | + Type: schema.TypeInt, |
| 111 | + Computed: true, |
| 112 | + Description: "`0`: user-defined secret. `1`: Tencent Cloud services secret. `2`: SSH key secret. `3`: Tencent Cloud API key secret. Note: this field may return `null`, indicating that no valid values can be obtained.", |
| 113 | + }, |
| 114 | + }, |
| 115 | + } |
| 116 | +} |
| 117 | + |
| 118 | +func resourceTencentCloudSsmSshKeyPairSecretCreate(d *schema.ResourceData, meta interface{}) error { |
| 119 | + defer logElapsed("resource.tencentcloud_ssm_ssh_key_pair_secret.create")() |
| 120 | + defer inconsistentCheck(d, meta)() |
| 121 | + |
| 122 | + logId := getLogId(contextNil) |
| 123 | + |
| 124 | + var ( |
| 125 | + request = ssm.NewCreateSSHKeyPairSecretRequest() |
| 126 | + response = ssm.NewCreateSSHKeyPairSecretResponse() |
| 127 | + secretName string |
| 128 | + ) |
| 129 | + if v, ok := d.GetOk("secret_name"); ok { |
| 130 | + request.SecretName = helper.String(v.(string)) |
| 131 | + } |
| 132 | + |
| 133 | + if v, ok := d.GetOkExists("project_id"); ok { |
| 134 | + request.ProjectId = helper.IntInt64(v.(int)) |
| 135 | + } |
| 136 | + |
| 137 | + if v, ok := d.GetOk("description"); ok { |
| 138 | + request.Description = helper.String(v.(string)) |
| 139 | + } |
| 140 | + |
| 141 | + if v, ok := d.GetOk("kms_key_id"); ok { |
| 142 | + request.KmsKeyId = helper.String(v.(string)) |
| 143 | + } |
| 144 | + |
| 145 | + if v, ok := d.GetOk("ssh_key_name"); ok { |
| 146 | + request.SSHKeyName = helper.String(v.(string)) |
| 147 | + } |
| 148 | + |
| 149 | + // Not support yet, because of can not query tags |
| 150 | + if v := helper.GetTags(d, "tags"); len(v) > 0 { |
| 151 | + for tagKey, tagValue := range v { |
| 152 | + tag := ssm.Tag{ |
| 153 | + TagKey: helper.String(tagKey), |
| 154 | + TagValue: helper.String(tagValue), |
| 155 | + } |
| 156 | + request.Tags = append(request.Tags, &tag) |
| 157 | + } |
| 158 | + } |
| 159 | + |
| 160 | + err := resource.Retry(writeRetryTimeout, func() *resource.RetryError { |
| 161 | + result, e := meta.(*TencentCloudClient).apiV3Conn.UseSsmClient().CreateSSHKeyPairSecret(request) |
| 162 | + if e != nil { |
| 163 | + return retryError(e) |
| 164 | + } else { |
| 165 | + log.Printf("[DEBUG]%s api[%s] success, request body [%s], response body [%s]\n", logId, request.GetAction(), request.ToJsonString(), result.ToJsonString()) |
| 166 | + } |
| 167 | + response = result |
| 168 | + return nil |
| 169 | + }) |
| 170 | + if err != nil { |
| 171 | + log.Printf("[CRITAL]%s create ssm sshKeyPairSecret failed, reason:%+v", logId, err) |
| 172 | + return err |
| 173 | + } |
| 174 | + |
| 175 | + secretName = *response.Response.SecretName |
| 176 | + d.SetId(secretName) |
| 177 | + |
| 178 | + // update status if disabled |
| 179 | + if v, ok := d.GetOk("status"); ok { |
| 180 | + status := v.(string) |
| 181 | + if status == "Disabled" { |
| 182 | + logId := getLogId(contextNil) |
| 183 | + ctx := context.WithValue(context.TODO(), logIdKey, logId) |
| 184 | + service := SsmService{client: meta.(*TencentCloudClient).apiV3Conn} |
| 185 | + err := service.DisableSecret(ctx, secretName) |
| 186 | + if err != nil { |
| 187 | + return err |
| 188 | + } |
| 189 | + } |
| 190 | + } |
| 191 | + |
| 192 | + return resourceTencentCloudSsmSshKeyPairSecretRead(d, meta) |
| 193 | +} |
| 194 | + |
| 195 | +func resourceTencentCloudSsmSshKeyPairSecretRead(d *schema.ResourceData, meta interface{}) error { |
| 196 | + defer logElapsed("resource.tencentcloud_ssm_ssh_key_pair_secret.read")() |
| 197 | + defer inconsistentCheck(d, meta)() |
| 198 | + |
| 199 | + logId := getLogId(contextNil) |
| 200 | + |
| 201 | + ctx := context.WithValue(context.TODO(), logIdKey, logId) |
| 202 | + |
| 203 | + service := SsmService{client: meta.(*TencentCloudClient).apiV3Conn} |
| 204 | + |
| 205 | + secretName := d.Id() |
| 206 | + |
| 207 | + sshKeyPairSecret, err := service.DescribeSecretById(ctx, secretName, 2) |
| 208 | + if err != nil { |
| 209 | + return err |
| 210 | + } |
| 211 | + |
| 212 | + if sshKeyPairSecret == nil { |
| 213 | + d.SetId("") |
| 214 | + log.Printf("[WARN]%s resource `SsmSshKeyPairSecret` [%s] not found, please check if it has been deleted.\n", logId, d.Id()) |
| 215 | + return nil |
| 216 | + } |
| 217 | + |
| 218 | + if sshKeyPairSecret.SecretName != nil { |
| 219 | + _ = d.Set("secret_name", sshKeyPairSecret.SecretName) |
| 220 | + } |
| 221 | + |
| 222 | + if sshKeyPairSecret.ProjectID != nil { |
| 223 | + _ = d.Set("project_id", sshKeyPairSecret.ProjectID) |
| 224 | + } |
| 225 | + |
| 226 | + if sshKeyPairSecret.Description != nil { |
| 227 | + _ = d.Set("description", sshKeyPairSecret.Description) |
| 228 | + } |
| 229 | + |
| 230 | + if sshKeyPairSecret.KmsKeyId != nil { |
| 231 | + _ = d.Set("kms_key_id", sshKeyPairSecret.KmsKeyId) |
| 232 | + } |
| 233 | + |
| 234 | + if sshKeyPairSecret.ResourceName != nil { |
| 235 | + _ = d.Set("ssh_key_name", sshKeyPairSecret.ResourceName) |
| 236 | + } |
| 237 | + |
| 238 | + if sshKeyPairSecret.Status != nil { |
| 239 | + _ = d.Set("status", sshKeyPairSecret.Status) |
| 240 | + } |
| 241 | + |
| 242 | + if sshKeyPairSecret.CreateTime != nil { |
| 243 | + _ = d.Set("create_time", sshKeyPairSecret.CreateTime) |
| 244 | + } |
| 245 | + |
| 246 | + if sshKeyPairSecret.SecretType != nil { |
| 247 | + _ = d.Set("secret_type", sshKeyPairSecret.SecretType) |
| 248 | + } |
| 249 | + |
| 250 | + return nil |
| 251 | +} |
| 252 | + |
| 253 | +func resourceTencentCloudSsmSshKeyPairSecretUpdate(d *schema.ResourceData, meta interface{}) error { |
| 254 | + defer logElapsed("resource.tencentcloud_ssm_ssh_key_pair_secret.update")() |
| 255 | + defer inconsistentCheck(d, meta)() |
| 256 | + |
| 257 | + logId := getLogId(contextNil) |
| 258 | + ctx := context.WithValue(context.TODO(), logIdKey, logId) |
| 259 | + |
| 260 | + secretName := d.Id() |
| 261 | + |
| 262 | + immutableArgs := []string{ |
| 263 | + "project_id", |
| 264 | + "kms_key_id", |
| 265 | + "ssh_key_name", |
| 266 | + } |
| 267 | + |
| 268 | + for _, v := range immutableArgs { |
| 269 | + if d.HasChange(v) { |
| 270 | + return fmt.Errorf("argument `%s` cannot be changed", v) |
| 271 | + } |
| 272 | + } |
| 273 | + |
| 274 | + if d.HasChange("description") { |
| 275 | + request := ssm.NewUpdateDescriptionRequest() |
| 276 | + request.SecretName = &secretName |
| 277 | + |
| 278 | + if v, ok := d.GetOk("description"); ok { |
| 279 | + request.Description = helper.String(v.(string)) |
| 280 | + } |
| 281 | + err := resource.Retry(writeRetryTimeout, func() *resource.RetryError { |
| 282 | + result, e := meta.(*TencentCloudClient).apiV3Conn.UseSsmClient().UpdateDescription(request) |
| 283 | + if e != nil { |
| 284 | + return retryError(e) |
| 285 | + } else { |
| 286 | + log.Printf("[DEBUG]%s api[%s] success, request body [%s], response body [%s]\n", logId, request.GetAction(), request.ToJsonString(), result.ToJsonString()) |
| 287 | + } |
| 288 | + return nil |
| 289 | + }) |
| 290 | + if err != nil { |
| 291 | + log.Printf("[CRITAL]%s update ssm sshKeyPairSecret failed, reason:%+v", logId, err) |
| 292 | + return err |
| 293 | + } |
| 294 | + } |
| 295 | + |
| 296 | + if d.HasChange("status") { |
| 297 | + service := SsmService{client: meta.(*TencentCloudClient).apiV3Conn} |
| 298 | + |
| 299 | + if v, ok := d.GetOk("status"); ok { |
| 300 | + status := v.(string) |
| 301 | + if status == "Disabled" { |
| 302 | + err := service.DisableSecret(ctx, secretName) |
| 303 | + if err != nil { |
| 304 | + return err |
| 305 | + } |
| 306 | + } else { |
| 307 | + err := service.EnableSecret(ctx, secretName) |
| 308 | + if err != nil { |
| 309 | + return err |
| 310 | + } |
| 311 | + } |
| 312 | + } |
| 313 | + } |
| 314 | + |
| 315 | + return resourceTencentCloudSsmSshKeyPairSecretRead(d, meta) |
| 316 | +} |
| 317 | + |
| 318 | +func resourceTencentCloudSsmSshKeyPairSecretDelete(d *schema.ResourceData, meta interface{}) error { |
| 319 | + defer logElapsed("resource.tencentcloud_ssm_ssh_key_pair_secret.delete")() |
| 320 | + defer inconsistentCheck(d, meta)() |
| 321 | + |
| 322 | + logId := getLogId(contextNil) |
| 323 | + ctx := context.WithValue(context.TODO(), logIdKey, logId) |
| 324 | + |
| 325 | + service := SsmService{client: meta.(*TencentCloudClient).apiV3Conn} |
| 326 | + secretName := d.Id() |
| 327 | + |
| 328 | + // disable before destroy |
| 329 | + err := service.DisableSecret(ctx, secretName) |
| 330 | + if err != nil { |
| 331 | + return err |
| 332 | + } |
| 333 | + |
| 334 | + var cleanSSHKey *bool |
| 335 | + |
| 336 | + if v, ok := d.GetOkExists("clean_ssh_key"); ok { |
| 337 | + cleanSSHKey = helper.Bool(v.(bool)) |
| 338 | + } |
| 339 | + |
| 340 | + if err := service.DeleteSsmSshKeyPairSecretById(ctx, secretName, cleanSSHKey); err != nil { |
| 341 | + return err |
| 342 | + } |
| 343 | + |
| 344 | + return nil |
| 345 | +} |
0 commit comments