feat: add target resource session recording support (#421)

* feat: add target session recording support

- add new optional `enable_session_recording` field for enabling or disabling session recording
- add new optional `storage_bucket_id` field for setting the storage bucket for the target
- These new fields are applicable to Boundary HCP/ENT

### Considerations
- There is no test coverage yet until we add support for testing enterprise only features. Manually tested the changes
This commit is contained in:
Elim Tsiagbey authored and GitHub committed 2023-06-30 13:11:15 -04:00
1 parent 9186304d5d
commit 605d124d51
4 files changed
+143 -1

No files matched your search

+2
View File
@@ -8,6 +8,8 @@ Canonical reference for changes, improvements, and bugfixes for the Boundary Ter
* Add support for a storage bucket as a resource * Add support for a storage bucket as a resource
([PR](https://github.com/hashicorp/terraform-provider-boundary/pull/417)) ([PR](https://github.com/hashicorp/terraform-provider-boundary/pull/417))
* Add option to enable session recording on a target resource
([PR](https://github.com/hashicorp/terraform-provider-boundary/pull/421))
## 1.1.8 (June 13, 2023) ## 1.1.8 (June 13, 2023)
+32
View File
@@ -84,6 +84,20 @@ resource "boundary_host_set" "foo" {
] ]
} }
resource "boundary_storage_bucket" "aws_example" {
name = "My aws storage bucket"
description = "My first storage bucket!"
scope_id = boundary_scope.org.id
plugin_name = "aws"
bucket_name = "mybucket"
attributes_json = jsonencode({ "region" = "us-east-1" })
secrets_json = jsonencode({
"access_key_id" = "aws_access_key_id_value",
"secret_access_key" = "aws_secret_access_key_value"
})
worker_filter = "\"pki\" in \"/tags/type\""
}
resource "boundary_target" "foo" { resource "boundary_target" "foo" {
name = "foo" name = "foo"
description = "Foo target" description = "Foo target"
@@ -112,6 +126,22 @@ resource "boundary_target" "ssh_foo" {
] ]
} }
resource "boundary_target" "ssh_session_recording_foo" {
name = "ssh_foo"
description = "Ssh target"
type = "ssh"
default_port = "22"
scope_id = boundary_scope.project.id
host_source_ids = [
boundary_host_set.foo.id
]
injected_application_credential_source_ids = [
boundary_credential_library_vault.foo.id
]
enable_session_recording = true
storage_bucket_id = boundary_storage_bucket.aws_example
}
resource "boundary_target" "address_foo" { resource "boundary_target" "address_foo" {
name = "address_foo" name = "address_foo"
description = "Foo target with an address" description = "Foo target with an address"
@@ -138,12 +168,14 @@ resource "boundary_target" "address_foo" {
- `default_port` (Number) The default port for this target. - `default_port` (Number) The default port for this target.
- `description` (String) The target description. - `description` (String) The target description.
- `egress_worker_filter` (String) Boolean expression to filter the workers used to access this target - `egress_worker_filter` (String) Boolean expression to filter the workers used to access this target
- `enable_session_recording` (Boolean) HCP/Ent Only. Enable sessions recording for this target. Only applicable for SSH targets.
- `host_source_ids` (Set of String) A list of host source ID's. Cannot be used alongside address. - `host_source_ids` (Set of String) A list of host source ID's. Cannot be used alongside address.
- `ingress_worker_filter` (String) HCP Only. Boolean expression to filter the workers a user will connect to when initiating a session against this target - `ingress_worker_filter` (String) HCP Only. Boolean expression to filter the workers a user will connect to when initiating a session against this target
- `injected_application_credential_source_ids` (Set of String) A list of injected application credential source ID's. - `injected_application_credential_source_ids` (Set of String) A list of injected application credential source ID's.
- `name` (String) The target name. Defaults to the resource name. - `name` (String) The target name. Defaults to the resource name.
- `session_connection_limit` (Number) - `session_connection_limit` (Number)
- `session_max_seconds` (Number) - `session_max_seconds` (Number)
- `storage_bucket_id` (String) HCP/Ent Only. Storage bucket for this target. Only applicable for SSH targets.
- `worker_filter` (String, Deprecated) Boolean expression to filter the workers for this target - `worker_filter` (String, Deprecated) Boolean expression to filter the workers for this target
### Read-Only ### Read-Only
@@ -69,6 +69,20 @@ resource "boundary_host_set" "foo" {
] ]
} }
resource "boundary_storage_bucket" "aws_example" {
name = "My aws storage bucket"
description = "My first storage bucket!"
scope_id = boundary_scope.org.id
plugin_name = "aws"
bucket_name = "mybucket"
attributes_json = jsonencode({ "region" = "us-east-1" })
secrets_json = jsonencode({
"access_key_id" = "aws_access_key_id_value",
"secret_access_key" = "aws_secret_access_key_value"
})
worker_filter = "\"pki\" in \"/tags/type\""
}
resource "boundary_target" "foo" { resource "boundary_target" "foo" {
name = "foo" name = "foo"
description = "Foo target" description = "Foo target"
@@ -97,6 +111,22 @@ resource "boundary_target" "ssh_foo" {
] ]
} }
resource "boundary_target" "ssh_session_recording_foo" {
name = "ssh_foo"
description = "Ssh target"
type = "ssh"
default_port = "22"
scope_id = boundary_scope.project.id
host_source_ids = [
boundary_host_set.foo.id
]
injected_application_credential_source_ids = [
boundary_credential_library_vault.foo.id
]
enable_session_recording = true
storage_bucket_id = boundary_storage_bucket.aws_example
}
resource "boundary_target" "address_foo" { resource "boundary_target" "address_foo" {
name = "address_foo" name = "address_foo"
description = "Foo target with an address" description = "Foo target with an address"
+79 -1
View File
@@ -21,8 +21,10 @@ const (
targetInjectedAppCredentialSourceIdsKey = "injected_application_credential_source_ids" targetInjectedAppCredentialSourceIdsKey = "injected_application_credential_source_ids"
targetDefaultPortKey = "default_port" targetDefaultPortKey = "default_port"
targetDefaultClientPortKey = "default_client_port" targetDefaultClientPortKey = "default_client_port"
targetEnableSessionRecordingKey = "enable_session_recording"
targetSessionMaxSecondsKey = "session_max_seconds" targetSessionMaxSecondsKey = "session_max_seconds"
targetSessionConnectionLimitKey = "session_connection_limit" targetSessionConnectionLimitKey = "session_connection_limit"
targetStorageBucketIdKey = "storage_bucket_id"
targetWorkerFilterKey = "worker_filter" targetWorkerFilterKey = "worker_filter"
targetWorkerEgressFilterKey = "egress_worker_filter" targetWorkerEgressFilterKey = "egress_worker_filter"
targetWorkerIngressFilterKey = "ingress_worker_filter" targetWorkerIngressFilterKey = "ingress_worker_filter"
@@ -133,6 +135,16 @@ func resourceTarget() *schema.Resource {
Optional: true, Optional: true,
ConflictsWith: []string{targetHostSourceIdsKey}, ConflictsWith: []string{targetHostSourceIdsKey},
}, },
targetEnableSessionRecordingKey: {
Description: "HCP/Ent Only. Enable sessions recording for this target. Only applicable for SSH targets.",
Type: schema.TypeBool,
Optional: true,
},
targetStorageBucketIdKey: {
Description: "HCP/Ent Only. Storage bucket for this target. Only applicable for SSH targets.",
Type: schema.TypeString,
Optional: true,
},
}, },
} }
} }
@@ -178,7 +190,9 @@ func setFromTargetResponseMap(d *schema.ResourceData, raw map[string]interface{}
return err return err
} }
switch raw["type"].(string) { typeStr := raw["type"].(string)
switch typeStr {
case targetTypeTcp, targetTypeSsh: case targetTypeTcp, targetTypeSsh:
if attrsVal, ok := raw["attributes"]; ok { if attrsVal, ok := raw["attributes"]; ok {
attrs := attrsVal.(map[string]interface{}) attrs := attrsVal.(map[string]interface{})
@@ -194,6 +208,20 @@ func setFromTargetResponseMap(d *schema.ResourceData, raw map[string]interface{}
return err return err
} }
} }
// SSH only features
if typeStr == targetTypeSsh {
if sessionRecordingVal, ok := attrs[targetEnableSessionRecordingKey].(bool); ok {
if err := d.Set(targetEnableSessionRecordingKey, sessionRecordingVal); err != nil {
return err
}
}
if targetStorageBucketIdVal, ok := attrs[targetStorageBucketIdKey]; ok {
if err := d.Set(targetStorageBucketIdKey, targetStorageBucketIdVal); err != nil {
return err
}
}
}
} }
} }
@@ -264,6 +292,18 @@ func resourceTargetCreate(ctx context.Context, d *schema.ResourceData, meta inte
} }
} }
enableSessionRecordingVal, ok := d.GetOk(targetEnableSessionRecordingKey)
if ok {
enableSessionRecordingBool := enableSessionRecordingVal.(bool)
opts = append(opts, targets.WithSshTargetEnableSessionRecording(enableSessionRecordingBool))
}
storageBucketIdVal, ok := d.GetOk(targetStorageBucketIdKey)
if ok {
storageBucketIdStr := storageBucketIdVal.(string)
opts = append(opts, targets.WithSshTargetStorageBucketId(storageBucketIdStr))
}
sessionMaxSecondsVal, ok := d.GetOk(targetSessionMaxSecondsKey) sessionMaxSecondsVal, ok := d.GetOk(targetSessionMaxSecondsKey)
if ok { if ok {
sessionMaxSecondsInt := sessionMaxSecondsVal.(int) sessionMaxSecondsInt := sessionMaxSecondsVal.(int)
@@ -443,6 +483,34 @@ func resourceTargetUpdate(ctx context.Context, d *schema.ResourceData, meta inte
} }
} }
var enableSessionRecording *bool
if d.HasChange(targetEnableSessionRecordingKey) {
switch typeStr {
case targetTypeSsh:
opts = append(opts, targets.WithSshTargetEnableSessionRecording(false))
enableSessionRecordingVal, ok := d.GetOk(targetEnableSessionRecordingKey)
if ok {
enableSessionRecordingBool := enableSessionRecordingVal.(bool)
enableSessionRecording = &enableSessionRecordingBool
opts = append(opts, targets.WithSshTargetEnableSessionRecording(enableSessionRecordingBool))
}
}
}
var storageBucket *string
if d.HasChange(targetStorageBucketIdKey) {
switch typeStr {
case targetTypeSsh:
opts = append(opts, targets.DefaultSshTargetStorageBucketId())
storageBucketVal, ok := d.GetOk(targetStorageBucketIdKey)
if ok {
storageBucketStr := storageBucketVal.(string)
storageBucket = &storageBucketStr
opts = append(opts, targets.WithSshTargetStorageBucketId(storageBucketStr))
}
}
}
var defaultPort *int var defaultPort *int
if d.HasChange(targetDefaultPortKey) { if d.HasChange(targetDefaultPortKey) {
switch typeStr { switch typeStr {
@@ -631,6 +699,16 @@ func resourceTargetUpdate(ctx context.Context, d *schema.ResourceData, meta inte
return diag.FromErr(err) return diag.FromErr(err)
} }
} }
if d.HasChange(targetEnableSessionRecordingKey) {
if err := d.Set(targetEnableSessionRecordingKey, enableSessionRecording); err != nil {
return diag.FromErr(err)
}
}
if d.HasChange(targetStorageBucketIdKey) {
if err := d.Set(targetStorageBucketIdKey, storageBucket); err != nil {
return diag.FromErr(err)
}
}
// The above call may not actually happen, so we use d.Id() and automatic // The above call may not actually happen, so we use d.Id() and automatic
// versioning here // versioning here