diff --git a/README.md b/README.md index 54d49844..c9ba7c9f 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ $ terraform apply ## Useful Links -* Documentation: [terraform strongDM provider](https://strongdm.github.io/terraform-provider-sdm/) +* Documentation: [terraform strongDM provider](https://registry.terraform.io/providers/strongdm/sdm/latest/docs) * Examples: [GitHub - strongdm/terraform-provider-sdm-examples](https://github.com/strongdm/terraform-provider-sdm-examples) 1. [Managing Resources](https://github.com/strongdm/terraform-provider-sdm-examples/tree/master/1_managing_resources) 2. [Managing Gateways](https://github.com/strongdm/terraform-provider-sdm-examples/tree/master/4_managing_gateways) diff --git a/docs/data-sources/resource.md b/docs/data-sources/resource.md index 04bcc5f0..0150c05f 100644 --- a/docs/data-sources/resource.md +++ b/docs/data-sources/resource.md @@ -541,6 +541,17 @@ In addition to provided arguments above, the following attributes are returned b * `port` - * `port_forwarding` - * `allow_deprecated_key_exchanges` - + * ssh_customer_key: + * `id` - Unique identifier of the Resource. + * `name` - Unique human-readable name of the Resource. + * `tags` - Tags is a map of key, value pairs. + * `secret_store_id` - ID of the secret store containing credentials for this resource, if any. + * `hostname` - + * `username` - + * `port` - + * `private_key` - + * `port_forwarding` - + * `allow_deprecated_key_exchanges` - * sybase: * `id` - Unique identifier of the Resource. * `name` - Unique human-readable name of the Resource. diff --git a/docs/index.md b/docs/index.md index e76a0b06..598334a2 100644 --- a/docs/index.md +++ b/docs/index.md @@ -56,10 +56,3 @@ resource "sdm_node" "gateway" { * `api_access_key` - (Required) Your strongDM API access key. It can also be sourced from the `SDM_API_ACCESS_KEY` environment variable. * `api_secret_key` - (Required) Your strongDM API secret key. It can also be sourced from the `SDM_API_SECRET_KEY` environment variable. - -## Documentation - -* [Guides](./guides/) -* [Data Sources](./data-sources/) -* [Resources](./resources/) - diff --git a/docs/resources/resource.md b/docs/resources/resource.md index 1da9a176..6836df82 100644 --- a/docs/resources/resource.md +++ b/docs/resources/resource.md @@ -603,6 +603,19 @@ The following arguments are supported by the Resource resource: * `port` - (Required) * `port_forwarding` - (Optional) * `allow_deprecated_key_exchanges` - (Optional) +* ssh_customer_key: + * `name` - (Required) Unique human-readable name of the Resource. + * `secret_store_id` - (Optional) ID of the secret store containing credentials for this resource, if any. + * `hostname` - (Required) + * `username` - (Optional) + * `secret_store_username_path` - (Optional) + * `secret_store_username_key` - (Optional) + * `port` - (Required) + * `private_key` - (Optional) + * `secret_store_private_key_path` - (Optional) + * `secret_store_private_key_key` - (Optional) + * `port_forwarding` - (Optional) + * `allow_deprecated_key_exchanges` - (Optional) * sybase: * `name` - (Required) Unique human-readable name of the Resource. * `secret_store_id` - (Optional) ID of the secret store containing credentials for this resource, if any. diff --git a/sdm/data_source_resource.go b/sdm/data_source_resource.go index be4fecaf..19e029a5 100644 --- a/sdm/data_source_resource.go +++ b/sdm/data_source_resource.go @@ -3027,6 +3027,70 @@ func dataSourceResource() *schema.Resource { }, }, }, + "ssh_customer_key": { + Type: schema.TypeList, + Computed: true, + Description: "", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Optional: true, + Description: "Unique identifier of the Resource.", + }, + "name": { + Type: schema.TypeString, + Optional: true, + Description: "Unique human-readable name of the Resource.", + }, + "tags": { + Type: schema.TypeMap, + + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Optional: true, + Description: "Tags is a map of key, value pairs.", + }, + "secret_store_id": { + Type: schema.TypeString, + Optional: true, + Description: "ID of the secret store containing credentials for this resource, if any.", + }, + "hostname": { + Type: schema.TypeString, + Optional: true, + Description: "", + }, + "username": { + Type: schema.TypeString, + Optional: true, + Description: "", + }, + "port": { + Type: schema.TypeInt, + Optional: true, + Description: "", + }, + "private_key": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + Description: "", + }, + "port_forwarding": { + Type: schema.TypeBool, + Optional: true, + Description: "", + }, + "allow_deprecated_key_exchanges": { + Type: schema.TypeBool, + Optional: true, + Description: "", + }, + }, + }, + }, "sybase": { Type: schema.TypeList, Computed: true, @@ -3865,6 +3929,19 @@ func dataSourceResourceList(d *schema.ResourceData, cc *sdm.Client) error { "port_forwarding": (v.PortForwarding), "allow_deprecated_key_exchanges": (v.AllowDeprecatedKeyExchanges), }) + case *sdm.SSHCustomerKey: + output[0]["ssh_customer_key"] = append(output[0]["ssh_customer_key"], entity{ + "id": (v.ID), + "name": (v.Name), + "tags": convertTagsToMap(v.Tags), + "secret_store_id": (v.SecretStoreID), + "hostname": (v.Hostname), + "username": (v.Username), + "port": (v.Port), + "private_key": (v.PrivateKey), + "port_forwarding": (v.PortForwarding), + "allow_deprecated_key_exchanges": (v.AllowDeprecatedKeyExchanges), + }) case *sdm.Sybase: output[0]["sybase"] = append(output[0]["sybase"], entity{ "id": (v.ID), diff --git a/sdm/resource_resource.go b/sdm/resource_resource.go index a868675d..7ad11e25 100644 --- a/sdm/resource_resource.go +++ b/sdm/resource_resource.go @@ -3505,6 +3505,81 @@ func resourceResource() *schema.Resource { }, }, }, + "ssh_customer_key": { + Type: schema.TypeList, + Optional: true, + Description: "", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + Description: "Unique human-readable name of the Resource.", + }, + "tags": { + Type: schema.TypeMap, + + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Optional: true, + Description: "Tags is a map of key, value pairs.", + }, + "secret_store_id": { + Type: schema.TypeString, + Optional: true, + Description: "ID of the secret store containing credentials for this resource, if any.", + }, + "hostname": { + Type: schema.TypeString, + Required: true, + Description: "", + }, + "username": { + Type: schema.TypeString, + Optional: true, + Description: "", + }, + "secret_store_username_path": { + Type: schema.TypeString, + Optional: true, + }, + "secret_store_username_key": { + Type: schema.TypeString, + Optional: true, + }, + "port": { + Type: schema.TypeInt, + Required: true, + Description: "", + }, + "private_key": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + Description: "", + }, + "secret_store_private_key_path": { + Type: schema.TypeString, + Optional: true, + }, + "secret_store_private_key_key": { + Type: schema.TypeString, + Optional: true, + }, + "port_forwarding": { + Type: schema.TypeBool, + Optional: true, + Description: "", + }, + "allow_deprecated_key_exchanges": { + Type: schema.TypeBool, + Optional: true, + Description: "", + }, + }, + }, + }, "sybase": { Type: schema.TypeList, Optional: true, @@ -5422,6 +5497,43 @@ func secretStoreValuesForResource(d *schema.ResourceData) (map[string]string, er "secret_store_username_key": convertStringFromMap(raw, "secret_store_username_key"), }, nil } + if list := d.Get("ssh_customer_key").([]interface{}); len(list) > 0 { + raw, ok := list[0].(map[string]interface{}) + if !ok { + return map[string]string{}, nil + } + _ = raw + if seID := raw["secret_store_id"]; seID != nil && seID.(string) != "" { + if v := raw["username"]; v != nil && v.(string) != "" { + return nil, fmt.Errorf("raw credential username cannot be combined with secret_store_id") + } + if v := raw["private_key"]; v != nil && v.(string) != "" { + return nil, fmt.Errorf("raw credential private_key cannot be combined with secret_store_id") + } + } else { + if v := raw["secret_store_username_path"]; v != nil && v.(string) != "" { + return nil, fmt.Errorf("secret store credential secret_store_username_path must be combined with secret_store_id") + } + if v := raw["secret_store_username_key"]; v != nil && v.(string) != "" { + return nil, fmt.Errorf("secret store credential secret_store_username_key must be combined with secret_store_id") + } + if v := raw["secret_store_private_key_path"]; v != nil && v.(string) != "" { + return nil, fmt.Errorf("secret store credential secret_store_private_key_path must be combined with secret_store_id") + } + if v := raw["secret_store_private_key_key"]; v != nil && v.(string) != "" { + return nil, fmt.Errorf("secret store credential secret_store_private_key_key must be combined with secret_store_id") + } + } + + return map[string]string{ + "username": convertStringFromMap(raw, "username"), + "secret_store_username_path": convertStringFromMap(raw, "secret_store_username_path"), + "secret_store_username_key": convertStringFromMap(raw, "secret_store_username_key"), + "private_key": convertStringFromMap(raw, "private_key"), + "secret_store_private_key_path": convertStringFromMap(raw, "secret_store_private_key_path"), + "secret_store_private_key_key": convertStringFromMap(raw, "secret_store_private_key_key"), + }, nil + } if list := d.Get("sybase").([]interface{}); len(list) > 0 { raw, ok := list[0].(map[string]interface{}) if !ok { @@ -6819,6 +6931,31 @@ func convertResourceFromResourceData(d *schema.ResourceData) sdm.Resource { } return out } + if list := d.Get("ssh_customer_key").([]interface{}); len(list) > 0 { + raw, ok := list[0].(map[string]interface{}) + if !ok { + return &sdm.SSHCustomerKey{} + } + out := &sdm.SSHCustomerKey{ + ID: d.Id(), + Name: convertStringFromMap(raw, "name"), + Tags: convertTagsFromMap(raw, "tags"), + SecretStoreID: convertStringFromMap(raw, "secret_store_id"), + Hostname: convertStringFromMap(raw, "hostname"), + Username: convertStringFromMap(raw, "username"), + Port: convertInt32FromMap(raw, "port"), + PrivateKey: convertStringFromMap(raw, "private_key"), + PortForwarding: convertBoolFromMap(raw, "port_forwarding"), + AllowDeprecatedKeyExchanges: convertBoolFromMap(raw, "allow_deprecated_key_exchanges"), + } + if out.Username == "" { + out.Username = fullSecretStorePath(raw, "username") + } + if out.PrivateKey == "" { + out.PrivateKey = fullSecretStorePath(raw, "private_key") + } + return out + } if list := d.Get("sybase").([]interface{}); len(list) > 0 { raw, ok := list[0].(map[string]interface{}) if !ok { @@ -7847,6 +7984,26 @@ func resourceResourceCreate(d *schema.ResourceData, cc *sdm.Client) error { "allow_deprecated_key_exchanges": (v.AllowDeprecatedKeyExchanges), }, }) + case *sdm.SSHCustomerKey: + localV, _ := localVersion.(*sdm.SSHCustomerKey) + _ = localV + d.Set("ssh_customer_key", []map[string]interface{}{ + { + "name": (v.Name), + "tags": convertTagsToMap(v.Tags), + "secret_store_id": (v.SecretStoreID), + "hostname": (v.Hostname), + "username": seValues["username"], + "secret_store_username_path": seValues["secret_store_username_path"], + "secret_store_username_key": seValues["secret_store_username_key"], + "port": (v.Port), + "private_key": seValues["private_key"], + "secret_store_private_key_path": seValues["secret_store_private_key_path"], + "secret_store_private_key_key": seValues["secret_store_private_key_key"], + "port_forwarding": (v.PortForwarding), + "allow_deprecated_key_exchanges": (v.AllowDeprecatedKeyExchanges), + }, + }) case *sdm.Sybase: localV, _ := localVersion.(*sdm.Sybase) _ = localV @@ -8991,6 +9148,29 @@ func resourceResourceRead(d *schema.ResourceData, cc *sdm.Client) error { "allow_deprecated_key_exchanges": (v.AllowDeprecatedKeyExchanges), }, }) + case *sdm.SSHCustomerKey: + localV, ok := localVersion.(*sdm.SSHCustomerKey) + if !ok { + localV = &sdm.SSHCustomerKey{} + } + _ = localV + d.Set("ssh_customer_key", []map[string]interface{}{ + { + "name": (v.Name), + "tags": convertTagsToMap(v.Tags), + "secret_store_id": (v.SecretStoreID), + "hostname": (v.Hostname), + "username": seValues["username"], + "secret_store_username_path": seValues["secret_store_username_path"], + "secret_store_username_key": seValues["secret_store_username_key"], + "port": (v.Port), + "private_key": seValues["private_key"], + "secret_store_private_key_path": seValues["secret_store_private_key_path"], + "secret_store_private_key_key": seValues["secret_store_private_key_key"], + "port_forwarding": (v.PortForwarding), + "allow_deprecated_key_exchanges": (v.AllowDeprecatedKeyExchanges), + }, + }) case *sdm.Sybase: localV, ok := localVersion.(*sdm.Sybase) if !ok {