Skip to content

Commit

Permalink
feat: add target resource session recording support (#421)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
elimt authored Jun 30, 2023
1 parent 9186304 commit 605d124
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 1 deletion.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ Canonical reference for changes, improvements, and bugfixes for the Boundary Ter

* Add support for a storage bucket as a resource
([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)

Expand Down
32 changes: 32 additions & 0 deletions docs/resources/target.md
Original file line number Diff line number Diff line change
Expand Up @@ -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" {
name = "foo"
description = "Foo target"
Expand Down Expand Up @@ -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" {
name = "address_foo"
description = "Foo target with an address"
Expand All @@ -138,12 +168,14 @@ resource "boundary_target" "address_foo" {
- `default_port` (Number) The default port for this target.
- `description` (String) The target description.
- `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.
- `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.
- `name` (String) The target name. Defaults to the resource name.
- `session_connection_limit` (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

### Read-Only
Expand Down
30 changes: 30 additions & 0 deletions examples/resources/boundary_target/resource.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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" {
name = "foo"
description = "Foo target"
Expand Down Expand Up @@ -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" {
name = "address_foo"
description = "Foo target with an address"
Expand Down
80 changes: 79 additions & 1 deletion internal/provider/resource_target.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ const (
targetInjectedAppCredentialSourceIdsKey = "injected_application_credential_source_ids"
targetDefaultPortKey = "default_port"
targetDefaultClientPortKey = "default_client_port"
targetEnableSessionRecordingKey = "enable_session_recording"
targetSessionMaxSecondsKey = "session_max_seconds"
targetSessionConnectionLimitKey = "session_connection_limit"
targetStorageBucketIdKey = "storage_bucket_id"
targetWorkerFilterKey = "worker_filter"
targetWorkerEgressFilterKey = "egress_worker_filter"
targetWorkerIngressFilterKey = "ingress_worker_filter"
Expand Down Expand Up @@ -133,6 +135,16 @@ func resourceTarget() *schema.Resource {
Optional: true,
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,
},
},
}
}
Expand Down Expand Up @@ -178,7 +190,9 @@ func setFromTargetResponseMap(d *schema.ResourceData, raw map[string]interface{}
return err
}

switch raw["type"].(string) {
typeStr := raw["type"].(string)

switch typeStr {
case targetTypeTcp, targetTypeSsh:
if attrsVal, ok := raw["attributes"]; ok {
attrs := attrsVal.(map[string]interface{})
Expand All @@ -194,6 +208,20 @@ func setFromTargetResponseMap(d *schema.ResourceData, raw map[string]interface{}
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
}
}
}
}
}

Expand Down Expand Up @@ -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)
if ok {
sessionMaxSecondsInt := sessionMaxSecondsVal.(int)
Expand Down Expand Up @@ -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
if d.HasChange(targetDefaultPortKey) {
switch typeStr {
Expand Down Expand Up @@ -631,6 +699,16 @@ func resourceTargetUpdate(ctx context.Context, d *schema.ResourceData, meta inte
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
// versioning here
Expand Down

0 comments on commit 605d124

Please sign in to comment.