diff --git a/api/targets/option.gen.go b/api/targets/option.gen.go index ea198ecde..2178a09b3 100644 --- a/api/targets/option.gen.go +++ b/api/targets/option.gen.go @@ -57,6 +57,18 @@ func DefaultAttributes() Option { } } +func WithConnectionIdleTimeoutDuration(inConnectionIdleTimeoutDuration uint32) Option { + return func(o *options) { + o.postMap["connection_idle_timeout_duration"] = inConnectionIdleTimeoutDuration + } +} + +func DefaultConnectionIdleTimeoutDuration() Option { + return func(o *options) { + o.postMap["connection_idle_timeout_duration"] = nil + } +} + func WithTcpTargetDefaultPort(inDefaultPort uint32) Option { return func(o *options) { raw, ok := o.postMap["attributes"] @@ -110,3 +122,27 @@ func DefaultName() Option { o.postMap["name"] = nil } } + +func WithSessionConnectionLimit(inSessionConnectionLimit uint32) Option { + return func(o *options) { + o.postMap["session_connection_limit"] = inSessionConnectionLimit + } +} + +func DefaultSessionConnectionLimit() Option { + return func(o *options) { + o.postMap["session_connection_limit"] = nil + } +} + +func WithSessionMaxDuration(inSessionMaxDuration uint32) Option { + return func(o *options) { + o.postMap["session_max_duration"] = inSessionMaxDuration + } +} + +func DefaultSessionMaxDuration() Option { + return func(o *options) { + o.postMap["session_max_duration"] = nil + } +} diff --git a/api/targets/target.gen.go b/api/targets/target.gen.go index 499beb73c..100bb7102 100644 --- a/api/targets/target.gen.go +++ b/api/targets/target.gen.go @@ -16,18 +16,21 @@ import ( ) type Target struct { - Id string `json:"id,omitempty"` - ScopeId string `json:"scope_id,omitempty"` - Scope *scopes.ScopeInfo `json:"scope,omitempty"` - Name string `json:"name,omitempty"` - Description string `json:"description,omitempty"` - CreatedTime time.Time `json:"created_time,omitempty"` - UpdatedTime time.Time `json:"updated_time,omitempty"` - Version uint32 `json:"version,omitempty"` - Type string `json:"type,omitempty"` - HostSetIds []string `json:"host_set_ids,omitempty"` - HostSets []*HostSet `json:"host_sets,omitempty"` - Attributes map[string]interface{} `json:"attributes,omitempty"` + Id string `json:"id,omitempty"` + ScopeId string `json:"scope_id,omitempty"` + Scope *scopes.ScopeInfo `json:"scope,omitempty"` + Name string `json:"name,omitempty"` + Description string `json:"description,omitempty"` + CreatedTime time.Time `json:"created_time,omitempty"` + UpdatedTime time.Time `json:"updated_time,omitempty"` + Version uint32 `json:"version,omitempty"` + Type string `json:"type,omitempty"` + HostSetIds []string `json:"host_set_ids,omitempty"` + HostSets []*HostSet `json:"host_sets,omitempty"` + SessionMaxDuration uint32 `json:"session_max_duration,omitempty"` + SessionConnectionLimit uint32 `json:"session_connection_limit,omitempty"` + ConnectionIdleTimeoutDuration uint32 `json:"connection_idle_timeout_duration,omitempty"` + Attributes map[string]interface{} `json:"attributes,omitempty"` responseBody *bytes.Buffer responseMap map[string]interface{} diff --git a/internal/auth/password/repository_account.go b/internal/auth/password/repository_account.go index 918de170a..7a8ed77be 100644 --- a/internal/auth/password/repository_account.go +++ b/internal/auth/password/repository_account.go @@ -251,6 +251,7 @@ func (r *Repository) UpdateAccount(ctx context.Context, scopeId string, a *Accou "LoginName": a.LoginName, }, fieldMaskPaths, + nil, ) if len(dbMask) == 0 && len(nullFields) == 0 { return nil, db.NoRowsAffected, fmt.Errorf("update: password account: %w", db.ErrEmptyFieldMask) diff --git a/internal/auth/password/repository_authmethod.go b/internal/auth/password/repository_authmethod.go index fa597b5c3..8be0608b6 100644 --- a/internal/auth/password/repository_authmethod.go +++ b/internal/auth/password/repository_authmethod.go @@ -209,6 +209,7 @@ func (r *Repository) UpdateAuthMethod(ctx context.Context, authMethod *AuthMetho "MinLoginNameLength": authMethod.MinLoginNameLength, }, fieldMaskPaths, + nil, ) if len(dbMask) == 0 && len(nullFields) == 0 { return nil, db.NoRowsAffected, fmt.Errorf("update: password auth method: %w", db.ErrEmptyFieldMask) diff --git a/internal/cmd/commands/targets/funcs.go b/internal/cmd/commands/targets/funcs.go index 833b67603..0c2e507b9 100644 --- a/internal/cmd/commands/targets/funcs.go +++ b/internal/cmd/commands/targets/funcs.go @@ -13,12 +13,15 @@ func generateTargetTableOutput(in *targets.Target) string { var ret []string nonAttributeMap := map[string]interface{}{ - "ID": in.Id, - "Scope ID": in.Scope.Id, - "Version": in.Version, - "Type": in.Type, - "Created Time": in.CreatedTime.Local().Format(time.RFC3339), - "Updated Time": in.UpdatedTime.Local().Format(time.RFC3339), + "ID": in.Id, + "Scope ID": in.Scope.Id, + "Version": in.Version, + "Type": in.Type, + "Created Time": in.CreatedTime.Local().Format(time.RFC3339), + "Updated Time": in.UpdatedTime.Local().Format(time.RFC3339), + "Connection Idle Timeout Duration (s)": in.ConnectionIdleTimeoutDuration, + "Session Connection Limit": in.SessionConnectionLimit, + "Session Max Duration (s)": in.SessionMaxDuration, } if in.Name != "" { diff --git a/internal/cmd/commands/targets/tcp.go b/internal/cmd/commands/targets/tcp.go index e5c5985c2..c0ab025df 100644 --- a/internal/cmd/commands/targets/tcp.go +++ b/internal/cmd/commands/targets/tcp.go @@ -4,6 +4,7 @@ import ( "fmt" "net/textproto" "strconv" + "time" "github.com/hashicorp/boundary/api" "github.com/hashicorp/boundary/api/targets" @@ -21,8 +22,11 @@ var _ cli.CommandAutocomplete = (*TcpCommand)(nil) type TcpCommand struct { *base.Command - Func string - flagDefaultPort string + Func string + flagDefaultPort string + flagSessionMaxDuration string + flagSessionConnectionLimit string + flagConnectionIdleTimeoutDuration string } func (c *TcpCommand) Synopsis() string { @@ -30,8 +34,8 @@ func (c *TcpCommand) Synopsis() string { } var tcpFlagsMap = map[string][]string{ - "create": {"scope-id", "name", "description", "default-port"}, - "update": {"id", "name", "description", "version", "default-port"}, + "create": {"scope-id", "name", "description", "default-port", "session-max-duration", "session-connection-limit", "connection-idle-timeout-duration"}, + "update": {"id", "name", "description", "version", "default-port", "session-max-duration", "session-connection-limit", "connection-idle-timeout-duration"}, } func (c *TcpCommand) Help() string { @@ -76,6 +80,24 @@ func (c *TcpCommand) Flags() *base.FlagSets { Target: &c.flagDefaultPort, Usage: "The default port to set on the target.", }) + case "session-max-duration": + f.StringVar(&base.StringVar{ + Name: "session-max-duration", + Target: &c.flagSessionMaxDuration, + Usage: `The maximum lifetime of the session, including all connections. Can be specified as an integer number of seconds or a duration string.`, + }) + case "session-connection-limit": + f.StringVar(&base.StringVar{ + Name: "session-connection-limit", + Target: &c.flagSessionConnectionLimit, + Usage: "The maximum number of connections allowed for a session. 0 means unlimited.", + }) + case "connection-idle-timeout-duration": + f.StringVar(&base.StringVar{ + Name: "connection-idle-timeout-duration", + Target: &c.flagConnectionIdleTimeoutDuration, + Usage: `Time period after which the connection will be disconnected if there is no network traffic. Can be specified as an integer number of seconds or a duration string. 0 means unlimited.`, + }) } } @@ -148,6 +170,59 @@ func (c *TcpCommand) Run(args []string) int { opts = append(opts, targets.WithTcpTargetDefaultPort(uint32(port))) } + switch c.flagSessionMaxDuration { + case "": + case "null": + opts = append(opts, targets.DefaultSessionMaxDuration()) + default: + var final uint32 + dur, err := strconv.ParseUint(c.flagSessionMaxDuration, 10, 32) + if err == nil { + final = uint32(dur) + } else { + dur, err := time.ParseDuration(c.flagSessionMaxDuration) + if err != nil { + c.UI.Error(fmt.Sprintf("Error parsing %q: %s", c.flagSessionMaxDuration, err)) + return 1 + } + final = uint32(dur.Seconds()) + } + opts = append(opts, targets.WithSessionMaxDuration(final)) + } + + switch c.flagSessionConnectionLimit { + case "": + case "null": + opts = append(opts, targets.DefaultSessionConnectionLimit()) + default: + limit, err := strconv.ParseUint(c.flagSessionConnectionLimit, 10, 32) + if err != nil { + c.UI.Error(fmt.Sprintf("Error parsing %q: %s", c.flagSessionConnectionLimit, err)) + return 1 + } + opts = append(opts, targets.WithSessionConnectionLimit(uint32(limit))) + } + + switch c.flagConnectionIdleTimeoutDuration { + case "": + case "null": + opts = append(opts, targets.DefaultConnectionIdleTimeoutDuration()) + default: + var final uint32 + dur, err := strconv.ParseUint(c.flagConnectionIdleTimeoutDuration, 10, 32) + if err == nil { + final = uint32(dur) + } else { + dur, err := time.ParseDuration(c.flagConnectionIdleTimeoutDuration) + if err != nil { + c.UI.Error(fmt.Sprintf("Error parsing %q: %s", c.flagConnectionIdleTimeoutDuration, err)) + return 1 + } + final = uint32(dur.Seconds()) + } + opts = append(opts, targets.WithConnectionIdleTimeoutDuration(final)) + } + targetClient := targets.NewClient(client) // Perform check-and-set when needed diff --git a/internal/db/common/update.go b/internal/db/common/update.go index 9aeb45148..fdde42ae7 100644 --- a/internal/db/common/update.go +++ b/internal/db/common/update.go @@ -142,16 +142,16 @@ func Intersection(av, bv []string) ([]string, map[string]string, map[string]stri return s, ah, bh, nil } -// BuildUpdatePaths takes a map of field names to field values and field masks -// and returns both a list of field names to udpate and a list of field names -// that should be set to null. -func BuildUpdatePaths(fieldValues map[string]interface{}, fieldMask []string) (masks []string, nulls []string) { +// BuildUpdatePaths takes a map of field names to field values, field masks, +// fields allowed to be zero value, and returns both a list of field names to +// udpate and a list of field names that should be set to null. +func BuildUpdatePaths(fieldValues map[string]interface{}, fieldMask []string, allowZeroFields []string) (masks []string, nulls []string) { for f, v := range fieldValues { if !contains(fieldMask, f) { continue } switch { - case isZero(v): + case isZero(v) && !contains(allowZeroFields, f): nulls = append(nulls, f) default: masks = append(masks, f) diff --git a/internal/db/migrations/postgres.gen.go b/internal/db/migrations/postgres.gen.go index ac9c8942b..78d049ff1 100644 --- a/internal/db/migrations/postgres.gen.go +++ b/internal/db/migrations/postgres.gen.go @@ -3153,14 +3153,14 @@ create table target_tcp ( description text, default_port int, -- default_port can be null -- max duration of the session in seconds. default of 0 equals no limit - session_duration_seconds int not null default 0 - check(session_duration_seconds >= 0), + session_max_duration int not null default 0 + check(session_max_duration >= 0), -- limit on number of session connections allowed. default of 0 equals no limit - connection_limit int not null default 1 - check(connection_limit >= 0), + session_connection_limit int not null default 1 + check(session_connection_limit >= 0), -- connection idle timout in seconds. default of 0 equals no limit - connection_idle_timeout_seconds int not null default 0 - check(connection_idle_timeout_seconds >= 0), + connection_idle_timeout_duration int not null default 0 + check(connection_idle_timeout_duration >= 0), create_time wt_timestamp, update_time wt_timestamp, version wt_version, @@ -3182,7 +3182,7 @@ create trigger immutable_columns before update on target_tcp - for each row execute procedure immutable_columns('public_id', 'scope_id', 'session_duration_seconds', 'connection_limit', 'connection_idle_timeout_seconds', 'create_time'); + for each row execute procedure immutable_columns('public_id', 'scope_id', 'create_time'); create trigger update_version_column @@ -3215,9 +3215,9 @@ select name, description, default_port, - session_duration_seconds, - connection_limit, - connection_idle_timeout_seconds, + session_max_duration, + session_connection_limit, + connection_idle_timeout_duration, version, create_time, update_time, @@ -3435,7 +3435,7 @@ begin; immutable_columns before update on session - for each row execute procedure immutable_columns('public_id', 'certificate', 'expiration_time', 'connection_limit', 'create_time', 'endpoint'); + for each row execute procedure immutable_columns('public_id', 'certificate', 'expiration_time', 'connection_limit', 'create_time', 'endpoint', 'connection_idle_timeout_seconds'); create trigger update_version_column diff --git a/internal/db/migrations/postgres/41_targets.up.sql b/internal/db/migrations/postgres/41_targets.up.sql index 774c4e540..659804c63 100644 --- a/internal/db/migrations/postgres/41_targets.up.sql +++ b/internal/db/migrations/postgres/41_targets.up.sql @@ -100,14 +100,14 @@ create table target_tcp ( description text, default_port int, -- default_port can be null -- max duration of the session in seconds. default of 0 equals no limit - session_duration_seconds int not null default 0 - check(session_duration_seconds >= 0), + session_max_duration int not null default 0 + check(session_max_duration >= 0), -- limit on number of session connections allowed. default of 0 equals no limit - connection_limit int not null default 1 - check(connection_limit >= 0), + session_connection_limit int not null default 1 + check(session_connection_limit >= 0), -- connection idle timout in seconds. default of 0 equals no limit - connection_idle_timeout_seconds int not null default 0 - check(connection_idle_timeout_seconds >= 0), + connection_idle_timeout_duration int not null default 0 + check(connection_idle_timeout_duration >= 0), create_time wt_timestamp, update_time wt_timestamp, version wt_version, @@ -129,7 +129,7 @@ create trigger immutable_columns before update on target_tcp - for each row execute procedure immutable_columns('public_id', 'scope_id', 'session_duration_seconds', 'connection_limit', 'connection_idle_timeout_seconds', 'create_time'); + for each row execute procedure immutable_columns('public_id', 'scope_id', 'create_time'); create trigger update_version_column @@ -162,9 +162,9 @@ select name, description, default_port, - session_duration_seconds, - connection_limit, - connection_idle_timeout_seconds, + session_max_duration, + session_connection_limit, + connection_idle_timeout_duration, version, create_time, update_time, diff --git a/internal/db/migrations/postgres/50_session.up.sql b/internal/db/migrations/postgres/50_session.up.sql index bbe164f09..b63ecd529 100644 --- a/internal/db/migrations/postgres/50_session.up.sql +++ b/internal/db/migrations/postgres/50_session.up.sql @@ -159,7 +159,7 @@ begin; immutable_columns before update on session - for each row execute procedure immutable_columns('public_id', 'certificate', 'expiration_time', 'connection_limit', 'create_time', 'endpoint'); + for each row execute procedure immutable_columns('public_id', 'certificate', 'expiration_time', 'connection_limit', 'create_time', 'endpoint', 'connection_idle_timeout_seconds'); create trigger update_version_column diff --git a/internal/gen/controller.swagger.json b/internal/gen/controller.swagger.json index d2e1226a9..dbf94e9a3 100644 --- a/internal/gen/controller.swagger.json +++ b/internal/gen/controller.swagger.json @@ -3004,6 +3004,21 @@ "description": "The host sets that make up this target.\nOutput only.", "readOnly": true }, + "session_max_duration": { + "type": "integer", + "format": "int64", + "title": "Maximum total lifetime of a created session, in seconds" + }, + "session_connection_limit": { + "type": "integer", + "format": "int64", + "title": "Maximum number of connections in a session" + }, + "connection_idle_timeout_duration": { + "type": "integer", + "format": "int64", + "title": "Idle timeout for a connection in the session, in seconds" + }, "attributes": { "type": "object", "description": "The attributes that are applied for the specific Target type." diff --git a/internal/gen/controller/api/resources/targets/target.pb.go b/internal/gen/controller/api/resources/targets/target.pb.go index b54417eab..90c65461f 100644 --- a/internal/gen/controller/api/resources/targets/target.pb.go +++ b/internal/gen/controller/api/resources/targets/target.pb.go @@ -119,8 +119,14 @@ type Target struct { // The host sets that make up this target. // Output only. HostSets []*HostSet `protobuf:"bytes,110,rep,name=host_sets,json=hostSets,proto3" json:"host_sets,omitempty"` + // Maximum total lifetime of a created session, in seconds + SessionMaxDuration *wrappers.UInt32Value `protobuf:"bytes,120,opt,name=session_max_duration,json=sessionMaxDuration,proto3" json:"session_max_duration,omitempty"` + // Maximum number of connections in a session + SessionConnectionLimit *wrappers.UInt32Value `protobuf:"bytes,130,opt,name=session_connection_limit,json=sessionConnectionLimit,proto3" json:"session_connection_limit,omitempty"` + // Idle timeout for a connection in the session, in seconds + ConnectionIdleTimeoutDuration *wrappers.UInt32Value `protobuf:"bytes,140,opt,name=connection_idle_timeout_duration,json=connectionIdleTimeoutDuration,proto3" json:"connection_idle_timeout_duration,omitempty"` // The attributes that are applied for the specific Target type. - Attributes *_struct.Struct `protobuf:"bytes,120,opt,name=attributes,proto3" json:"attributes,omitempty"` + Attributes *_struct.Struct `protobuf:"bytes,200,opt,name=attributes,proto3" json:"attributes,omitempty"` } func (x *Target) Reset() { @@ -232,6 +238,27 @@ func (x *Target) GetHostSets() []*HostSet { return nil } +func (x *Target) GetSessionMaxDuration() *wrappers.UInt32Value { + if x != nil { + return x.SessionMaxDuration + } + return nil +} + +func (x *Target) GetSessionConnectionLimit() *wrappers.UInt32Value { + if x != nil { + return x.SessionConnectionLimit + } + return nil +} + +func (x *Target) GetConnectionIdleTimeoutDuration() *wrappers.UInt32Value { + if x != nil { + return x.ConnectionIdleTimeoutDuration + } + return nil +} + func (x *Target) GetAttributes() *_struct.Struct { if x != nil { return x.Attributes @@ -587,7 +614,7 @@ var file_controller_api_resources_targets_v1_target_proto_rawDesc = []byte{ 0x02, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x26, 0x0a, 0x0f, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x68, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, - 0x6c, 0x6f, 0x67, 0x49, 0x64, 0x22, 0xff, 0x04, 0x0a, 0x06, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x6c, 0x6f, 0x67, 0x49, 0x64, 0x22, 0xcf, 0x08, 0x0a, 0x06, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x12, 0x43, 0x0a, 0x05, @@ -623,8 +650,37 @@ var file_controller_api_resources_targets_v1_target_proto_rawDesc = []byte{ 0x32, 0x2c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, 0x52, 0x08, - 0x68, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, 0x73, 0x12, 0x3d, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, - 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x78, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, + 0x68, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, 0x73, 0x12, 0x82, 0x01, 0x0a, 0x14, 0x73, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x78, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x32, 0xa0, 0xda, 0x29, 0x01, 0xc2, 0xdd, 0x29, 0x2a, 0x0a, + 0x14, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x64, 0x75, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x61, + 0x78, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x12, 0x73, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x4d, 0x61, 0x78, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x93, 0x01, + 0x0a, 0x18, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x82, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, + 0x3a, 0xa0, 0xda, 0x29, 0x01, 0xc2, 0xdd, 0x29, 0x32, 0x0a, 0x18, 0x73, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, + 0x6d, 0x69, 0x74, 0x12, 0x16, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x16, 0x73, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, + 0x6d, 0x69, 0x74, 0x12, 0xb1, 0x01, 0x0a, 0x20, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x6c, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, + 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x8c, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x49, 0xa0, + 0xda, 0x29, 0x01, 0xc2, 0xdd, 0x29, 0x41, 0x0a, 0x20, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x6c, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, + 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x43, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x6c, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, + 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x1d, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x6c, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x44, + 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, + 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0xc8, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x42, 0x04, 0xa0, 0xda, 0x29, 0x01, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x22, 0x86, 0x01, 0x0a, 0x13, 0x54, 0x63, 0x70, 0x54, @@ -713,8 +769,8 @@ var file_controller_api_resources_targets_v1_target_proto_goTypes = []interface{ (*scopes.ScopeInfo)(nil), // 6: controller.api.resources.scopes.v1.ScopeInfo (*wrappers.StringValue)(nil), // 7: google.protobuf.StringValue (*timestamp.Timestamp)(nil), // 8: google.protobuf.Timestamp - (*_struct.Struct)(nil), // 9: google.protobuf.Struct - (*wrappers.UInt32Value)(nil), // 10: google.protobuf.UInt32Value + (*wrappers.UInt32Value)(nil), // 9: google.protobuf.UInt32Value + (*_struct.Struct)(nil), // 10: google.protobuf.Struct } var file_controller_api_resources_targets_v1_target_proto_depIdxs = []int32{ 6, // 0: controller.api.resources.targets.v1.Target.scope:type_name -> controller.api.resources.scopes.v1.ScopeInfo @@ -723,18 +779,21 @@ var file_controller_api_resources_targets_v1_target_proto_depIdxs = []int32{ 8, // 3: controller.api.resources.targets.v1.Target.created_time:type_name -> google.protobuf.Timestamp 8, // 4: controller.api.resources.targets.v1.Target.updated_time:type_name -> google.protobuf.Timestamp 0, // 5: controller.api.resources.targets.v1.Target.host_sets:type_name -> controller.api.resources.targets.v1.HostSet - 9, // 6: controller.api.resources.targets.v1.Target.attributes:type_name -> google.protobuf.Struct - 10, // 7: controller.api.resources.targets.v1.TcpTargetAttributes.default_port:type_name -> google.protobuf.UInt32Value - 6, // 8: controller.api.resources.targets.v1.SessionAuthorizationData.scope:type_name -> controller.api.resources.scopes.v1.ScopeInfo - 8, // 9: controller.api.resources.targets.v1.SessionAuthorizationData.created_time:type_name -> google.protobuf.Timestamp - 3, // 10: controller.api.resources.targets.v1.SessionAuthorizationData.worker_info:type_name -> controller.api.resources.targets.v1.WorkerInfo - 6, // 11: controller.api.resources.targets.v1.SessionAuthorization.scope:type_name -> controller.api.resources.scopes.v1.ScopeInfo - 8, // 12: controller.api.resources.targets.v1.SessionAuthorization.created_time:type_name -> google.protobuf.Timestamp - 13, // [13:13] is the sub-list for method output_type - 13, // [13:13] is the sub-list for method input_type - 13, // [13:13] is the sub-list for extension type_name - 13, // [13:13] is the sub-list for extension extendee - 0, // [0:13] is the sub-list for field type_name + 9, // 6: controller.api.resources.targets.v1.Target.session_max_duration:type_name -> google.protobuf.UInt32Value + 9, // 7: controller.api.resources.targets.v1.Target.session_connection_limit:type_name -> google.protobuf.UInt32Value + 9, // 8: controller.api.resources.targets.v1.Target.connection_idle_timeout_duration:type_name -> google.protobuf.UInt32Value + 10, // 9: controller.api.resources.targets.v1.Target.attributes:type_name -> google.protobuf.Struct + 9, // 10: controller.api.resources.targets.v1.TcpTargetAttributes.default_port:type_name -> google.protobuf.UInt32Value + 6, // 11: controller.api.resources.targets.v1.SessionAuthorizationData.scope:type_name -> controller.api.resources.scopes.v1.ScopeInfo + 8, // 12: controller.api.resources.targets.v1.SessionAuthorizationData.created_time:type_name -> google.protobuf.Timestamp + 3, // 13: controller.api.resources.targets.v1.SessionAuthorizationData.worker_info:type_name -> controller.api.resources.targets.v1.WorkerInfo + 6, // 14: controller.api.resources.targets.v1.SessionAuthorization.scope:type_name -> controller.api.resources.scopes.v1.ScopeInfo + 8, // 15: controller.api.resources.targets.v1.SessionAuthorization.created_time:type_name -> google.protobuf.Timestamp + 16, // [16:16] is the sub-list for method output_type + 16, // [16:16] is the sub-list for method input_type + 16, // [16:16] is the sub-list for extension type_name + 16, // [16:16] is the sub-list for extension extendee + 0, // [0:16] is the sub-list for field type_name } func init() { file_controller_api_resources_targets_v1_target_proto_init() } diff --git a/internal/host/static/repository_host.go b/internal/host/static/repository_host.go index bcdccd7b7..8ac4228b0 100644 --- a/internal/host/static/repository_host.go +++ b/internal/host/static/repository_host.go @@ -126,6 +126,7 @@ func (r *Repository) UpdateHost(ctx context.Context, scopeId string, h *Host, ve "Address": h.Address, }, fieldMaskPaths, + nil, ) if len(dbMask) == 0 && len(nullFields) == 0 { return nil, db.NoRowsAffected, fmt.Errorf("update: static host: %w", db.ErrEmptyFieldMask) diff --git a/internal/host/static/repository_host_set.go b/internal/host/static/repository_host_set.go index ee26dcbee..a0201308a 100644 --- a/internal/host/static/repository_host_set.go +++ b/internal/host/static/repository_host_set.go @@ -112,6 +112,7 @@ func (r *Repository) UpdateSet(ctx context.Context, scopeId string, s *HostSet, "Description": s.Description, }, fieldMaskPaths, + nil, ) if len(dbMask) == 0 && len(nullFields) == 0 { return nil, nil, db.NoRowsAffected, fmt.Errorf("update: static host set: %w", db.ErrEmptyFieldMask) diff --git a/internal/iam/repository_group.go b/internal/iam/repository_group.go index b440990ad..2da07706c 100644 --- a/internal/iam/repository_group.go +++ b/internal/iam/repository_group.go @@ -73,6 +73,7 @@ func (r *Repository) UpdateGroup(ctx context.Context, group *Group, version uint "description": group.Description, }, fieldMaskPaths, + nil, ) if len(dbMask) == 0 && len(nullFields) == 0 { return nil, nil, db.NoRowsAffected, fmt.Errorf("update group: %w", db.ErrEmptyFieldMask) diff --git a/internal/iam/repository_role.go b/internal/iam/repository_role.go index b02e6db7c..a61e26898 100644 --- a/internal/iam/repository_role.go +++ b/internal/iam/repository_role.go @@ -74,6 +74,7 @@ func (r *Repository) UpdateRole(ctx context.Context, role *Role, version uint32, "GrantScopeId": role.GrantScopeId, }, fieldMaskPaths, + nil, ) if len(dbMask) == 0 && len(nullFields) == 0 { return nil, nil, nil, db.NoRowsAffected, fmt.Errorf("update role: %w", db.ErrEmptyFieldMask) diff --git a/internal/iam/repository_scope.go b/internal/iam/repository_scope.go index d60d29485..cb29bad31 100644 --- a/internal/iam/repository_scope.go +++ b/internal/iam/repository_scope.go @@ -255,6 +255,7 @@ func (r *Repository) UpdateScope(ctx context.Context, scope *Scope, version uint "description": scope.Description, }, fieldMaskPaths, + nil, ) // nada to update, so reload scope from db and return it if len(dbMask) == 0 && len(nullFields) == 0 { diff --git a/internal/iam/repository_user.go b/internal/iam/repository_user.go index 12b3d5304..e20caa322 100644 --- a/internal/iam/repository_user.go +++ b/internal/iam/repository_user.go @@ -64,6 +64,7 @@ func (r *Repository) UpdateUser(ctx context.Context, user *User, version uint32, "description": user.Description, }, fieldMaskPaths, + nil, ) if len(dbMask) == 0 && len(nullFields) == 0 { return nil, db.NoRowsAffected, fmt.Errorf("update user: %w", db.ErrEmptyFieldMask) diff --git a/internal/proto/local/controller/api/resources/targets/v1/target.proto b/internal/proto/local/controller/api/resources/targets/v1/target.proto index 040dfa31f..83ee89989 100644 --- a/internal/proto/local/controller/api/resources/targets/v1/target.proto +++ b/internal/proto/local/controller/api/resources/targets/v1/target.proto @@ -56,8 +56,17 @@ message Target { // Output only. repeated HostSet host_sets = 110; + // Maximum total lifetime of a created session, in seconds + google.protobuf.UInt32Value session_max_duration = 120 [(custom_options.v1.generate_sdk_option) = true, (custom_options.v1.mask_mapping) = {this:"session_max_duration" that: "SessionMaxDuration"}]; + + // Maximum number of connections in a session + google.protobuf.UInt32Value session_connection_limit = 130 [(custom_options.v1.generate_sdk_option) = true, (custom_options.v1.mask_mapping) = {this:"session_connection_limit" that: "SessionConnectionLimit"}]; + + // Idle timeout for a connection in the session, in seconds + google.protobuf.UInt32Value connection_idle_timeout_duration = 140 [(custom_options.v1.generate_sdk_option) = true, (custom_options.v1.mask_mapping) = {this:"connection_idle_timeout_duration" that: "ConnectionIdleTimeoutDuration"}]; + // The attributes that are applied for the specific Target type. - google.protobuf.Struct attributes = 120 [(custom_options.v1.generate_sdk_option) = true]; + google.protobuf.Struct attributes = 200 [(custom_options.v1.generate_sdk_option) = true]; } message TcpTargetAttributes { diff --git a/internal/proto/local/controller/storage/target/store/v1/target.proto b/internal/proto/local/controller/storage/target/store/v1/target.proto index 6332afcb0..a52cb8f7e 100644 --- a/internal/proto/local/controller/storage/target/store/v1/target.proto +++ b/internal/proto/local/controller/storage/target/store/v1/target.proto @@ -45,6 +45,18 @@ message TargetView { // default port of the Target // @inject_tag: `gorm:"default:null"` uint32 default_port = 90; + + // Maximum total lifetime of a created session, in seconds + // @inject_tag: `gorm:"default:null"` + uint32 session_max_duration = 100; + + // Maximum number of connections in a session + // @inject_tag: `gorm:"default:null"` + uint32 session_connection_limit = 110; + + // Idle timeout for a connection in the session, in seconds + // @inject_tag: `gorm:"default:null"` + uint32 connection_idle_timeout_duration = 120; } message TargetHostSet { @@ -102,4 +114,25 @@ message TcpTarget { this: "DefaultPort" that: "attributes.default_port" }]; + + // Maximum total lifetime of a created session, in seconds + // @inject_tag: `gorm:"default:null"` + uint32 session_max_duration = 100 [(custom_options.v1.mask_mapping) = { + this: "SessionMaxDuration" + that: "session_max_duration" + }]; + + // Maximum number of connections in a session + // @inject_tag: `gorm:"default:null"` + uint32 session_connection_limit = 110 [(custom_options.v1.mask_mapping) = { + this: "SessionConnectionLimit" + that: "session_connection_limit" + }]; + + // Idle timeout for a connection in the session, in seconds + // @inject_tag: `gorm:"default:null"` + uint32 connection_idle_timeout_duration = 120 [(custom_options.v1.mask_mapping) = { + this: "ConnectionIdleTimeoutDuration" + that: "connection_idle_timeout_duration" + }]; } \ No newline at end of file diff --git a/internal/servers/controller/handlers/targets/target_service.go b/internal/servers/controller/handlers/targets/target_service.go index 81ad17db6..2cffb7592 100644 --- a/internal/servers/controller/handlers/targets/target_service.go +++ b/internal/servers/controller/handlers/targets/target_service.go @@ -11,6 +11,7 @@ import ( "github.com/golang/protobuf/ptypes/wrappers" "github.com/hashicorp/boundary/internal/auth" "github.com/hashicorp/boundary/internal/db" + "github.com/hashicorp/boundary/internal/db/timestamp" pb "github.com/hashicorp/boundary/internal/gen/controller/api/resources/targets" pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services" "github.com/hashicorp/boundary/internal/host" @@ -27,6 +28,7 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/wrapperspb" ) @@ -348,14 +350,19 @@ HOST_GATHERING_DONE: endpointUrl.Host = endpointHost } + expTime := timestamppb.Now() + expTime.Seconds += int64(t.GetSessionMaxDuration()) sessionComposition := session.ComposedOf{ - UserId: authResults.UserId, - HostId: chosenId.hostId, - TargetId: t.GetPublicId(), - HostSetId: chosenId.hostSetId, - AuthTokenId: authResults.AuthTokenId, - ScopeId: authResults.Scope.Id, - Endpoint: endpointUrl.String(), + UserId: authResults.UserId, + HostId: chosenId.hostId, + TargetId: t.GetPublicId(), + HostSetId: chosenId.hostSetId, + AuthTokenId: authResults.AuthTokenId, + ScopeId: authResults.Scope.Id, + Endpoint: endpointUrl.String(), + ExpirationTime: ×tamp.Timestamp{Timestamp: expTime}, + ConnectionLimit: t.GetSessionConnectionLimit(), + ConnectionIdleTimeoutSeconds: t.GetConnectionIdleTimeoutDuration(), } sess, err := session.New(sessionComposition) @@ -428,6 +435,15 @@ func (s Service) createInRepo(ctx context.Context, item *pb.Target) (*pb.Target, if item.GetDescription() != nil { opts = append(opts, target.WithDescription(item.GetDescription().GetValue())) } + if item.GetSessionMaxDuration() != nil { + opts = append(opts, target.WithSessionMaxDuration(item.GetSessionMaxDuration().GetValue())) + } + if item.GetSessionConnectionLimit() != nil { + opts = append(opts, target.WithSessionConnectionLimit(item.GetSessionConnectionLimit().GetValue())) + } + if item.GetConnectionIdleTimeoutDuration() != nil { + opts = append(opts, target.WithConnectionIdleTimeoutDuration(item.GetConnectionIdleTimeoutDuration().GetValue())) + } tcpAttrs := &pb.TcpTargetAttributes{} if err := handlers.StructToProto(item.GetAttributes(), tcpAttrs); err != nil { return nil, status.Errorf(codes.InvalidArgument, "Provided attributes don't match expected format.") @@ -461,7 +477,15 @@ func (s Service) updateInRepo(ctx context.Context, scopeId, id string, mask []st if name := item.GetName(); name != nil { opts = append(opts, target.WithName(name.GetValue())) } - + if item.GetSessionMaxDuration() != nil { + opts = append(opts, target.WithSessionMaxDuration(item.GetSessionMaxDuration().GetValue())) + } + if item.GetSessionConnectionLimit() != nil { + opts = append(opts, target.WithSessionConnectionLimit(item.GetSessionConnectionLimit().GetValue())) + } + if item.GetConnectionIdleTimeoutDuration() != nil { + opts = append(opts, target.WithConnectionIdleTimeoutDuration(item.GetConnectionIdleTimeoutDuration().GetValue())) + } tcpAttrs := &pb.TcpTargetAttributes{} if err := handlers.StructToProto(item.GetAttributes(), tcpAttrs); err != nil { return nil, status.Errorf(codes.InvalidArgument, "Provided attributes don't match expected format.") @@ -628,12 +652,15 @@ func (s Service) authResult(ctx context.Context, id string, a action.Type) auth. func toProto(in target.Target, m []*target.TargetSet) (*pb.Target, error) { out := pb.Target{ - Id: in.GetPublicId(), - ScopeId: in.GetScopeId(), - CreatedTime: in.GetCreateTime().GetTimestamp(), - UpdatedTime: in.GetUpdateTime().GetTimestamp(), - Version: in.GetVersion(), - Type: target.TcpTargetType.String(), + Id: in.GetPublicId(), + ScopeId: in.GetScopeId(), + CreatedTime: in.GetCreateTime().GetTimestamp(), + UpdatedTime: in.GetUpdateTime().GetTimestamp(), + Version: in.GetVersion(), + Type: target.TcpTargetType.String(), + SessionMaxDuration: &wrapperspb.UInt32Value{Value: in.GetSessionMaxDuration()}, + SessionConnectionLimit: &wrapperspb.UInt32Value{Value: in.GetSessionConnectionLimit()}, + ConnectionIdleTimeoutDuration: &wrapperspb.UInt32Value{Value: in.GetConnectionIdleTimeoutDuration()}, } if in.GetDescription() != "" { out.Description = wrapperspb.String(in.GetDescription()) diff --git a/internal/servers/controller/handlers/targets/target_service_test.go b/internal/servers/controller/handlers/targets/target_service_test.go index 6a797368a..60fa5e539 100644 --- a/internal/servers/controller/handlers/targets/target_service_test.go +++ b/internal/servers/controller/handlers/targets/target_service_test.go @@ -68,15 +68,18 @@ func TestGet(t *testing.T) { tar := target.TestTcpTarget(t, conn, proj.GetPublicId(), "test", target.WithHostSets([]string{hs[0].GetPublicId(), hs[1].GetPublicId()})) pTar := &pb.Target{ - Id: tar.GetPublicId(), - ScopeId: proj.GetPublicId(), - Name: wrapperspb.String("test"), - CreatedTime: tar.CreateTime.GetTimestamp(), - UpdatedTime: tar.UpdateTime.GetTimestamp(), - Scope: &scopes.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()}, - Type: target.TcpTargetType.String(), - HostSetIds: []string{hs[0].GetPublicId(), hs[1].GetPublicId()}, - Attributes: new(structpb.Struct), + Id: tar.GetPublicId(), + ScopeId: proj.GetPublicId(), + Name: wrapperspb.String("test"), + CreatedTime: tar.CreateTime.GetTimestamp(), + UpdatedTime: tar.UpdateTime.GetTimestamp(), + Scope: &scopes.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()}, + Type: target.TcpTargetType.String(), + HostSetIds: []string{hs[0].GetPublicId(), hs[1].GetPublicId()}, + Attributes: new(structpb.Struct), + SessionMaxDuration: &wrapperspb.UInt32Value{Value: 28800}, + ConnectionIdleTimeoutDuration: &wrapperspb.UInt32Value{Value: 3600}, + SessionConnectionLimit: &wrapperspb.UInt32Value{Value: 1}, } for _, ihs := range hs { pTar.HostSets = append(pTar.HostSets, &pb.HostSet{Id: ihs.GetPublicId(), HostCatalogId: ihs.GetCatalogId()}) @@ -146,15 +149,18 @@ func TestList(t *testing.T) { name := fmt.Sprintf("tar%d", i) tar := target.TestTcpTarget(t, conn, proj.GetPublicId(), name, target.WithHostSets([]string{hss[0].GetPublicId(), hss[1].GetPublicId()})) wantTars = append(wantTars, &pb.Target{ - Id: tar.GetPublicId(), - ScopeId: proj.GetPublicId(), - Name: wrapperspb.String(name), - Scope: &scopes.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()}, - CreatedTime: tar.GetCreateTime().GetTimestamp(), - UpdatedTime: tar.GetUpdateTime().GetTimestamp(), - Version: tar.GetVersion(), - Type: target.TcpTargetType.String(), - Attributes: new(structpb.Struct), + Id: tar.GetPublicId(), + ScopeId: proj.GetPublicId(), + Name: wrapperspb.String(name), + Scope: &scopes.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()}, + CreatedTime: tar.GetCreateTime().GetTimestamp(), + UpdatedTime: tar.GetUpdateTime().GetTimestamp(), + Version: tar.GetVersion(), + Type: target.TcpTargetType.String(), + Attributes: new(structpb.Struct), + SessionMaxDuration: &wrapperspb.UInt32Value{Value: 28800}, + ConnectionIdleTimeoutDuration: &wrapperspb.UInt32Value{Value: 3600}, + SessionConnectionLimit: &wrapperspb.UInt32Value{Value: 1}, }) } @@ -304,6 +310,9 @@ func TestCreate(t *testing.T) { Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{ "default_port": structpb.NewNumberValue(2), }}, + SessionMaxDuration: &wrapperspb.UInt32Value{Value: 28800}, + ConnectionIdleTimeoutDuration: &wrapperspb.UInt32Value{Value: 3600}, + SessionConnectionLimit: &wrapperspb.UInt32Value{Value: 1}, }, }, errCode: codes.OK, @@ -446,11 +455,14 @@ func TestUpdate(t *testing.T) { name: "Update an Existing Target", req: &pbs.UpdateTargetRequest{ UpdateMask: &field_mask.FieldMask{ - Paths: []string{"name", "description"}, + Paths: []string{"name", "description", "session_max_duration", "connection_idle_timeout_duration", "session_connection_limit"}, }, Item: &pb.Target{ - Name: wrapperspb.String("name"), - Description: wrapperspb.String("desc"), + Name: wrapperspb.String("name"), + Description: wrapperspb.String("desc"), + SessionMaxDuration: wrapperspb.UInt32(3600), + ConnectionIdleTimeoutDuration: wrapperspb.UInt32(180), + SessionConnectionLimit: wrapperspb.UInt32(5), }, }, res: &pbs.UpdateTargetResponse{ @@ -464,9 +476,12 @@ func TestUpdate(t *testing.T) { Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{ "default_port": structpb.NewNumberValue(2), }}, - CreatedTime: tar.GetCreateTime().GetTimestamp(), - HostSetIds: hsIds, - HostSets: hostSets, + CreatedTime: tar.GetCreateTime().GetTimestamp(), + HostSetIds: hsIds, + HostSets: hostSets, + SessionMaxDuration: wrapperspb.UInt32(3600), + ConnectionIdleTimeoutDuration: wrapperspb.UInt32(180), + SessionConnectionLimit: wrapperspb.UInt32(5), }, }, errCode: codes.OK, @@ -494,8 +509,11 @@ func TestUpdate(t *testing.T) { Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{ "default_port": structpb.NewNumberValue(2), }}, - HostSetIds: hsIds, - HostSets: hostSets, + HostSetIds: hsIds, + HostSets: hostSets, + SessionMaxDuration: wrapperspb.UInt32(3600), + ConnectionIdleTimeoutDuration: wrapperspb.UInt32(180), + SessionConnectionLimit: wrapperspb.UInt32(5), }, }, errCode: codes.OK, @@ -577,8 +595,11 @@ func TestUpdate(t *testing.T) { Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{ "default_port": structpb.NewNumberValue(2), }}, - HostSetIds: hsIds, - HostSets: hostSets, + HostSetIds: hsIds, + HostSets: hostSets, + SessionMaxDuration: wrapperspb.UInt32(3600), + ConnectionIdleTimeoutDuration: wrapperspb.UInt32(180), + SessionConnectionLimit: wrapperspb.UInt32(5), }, }, errCode: codes.OK, @@ -606,8 +627,11 @@ func TestUpdate(t *testing.T) { Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{ "default_port": structpb.NewNumberValue(2), }}, - HostSetIds: hsIds, - HostSets: hostSets, + HostSetIds: hsIds, + HostSets: hostSets, + SessionMaxDuration: wrapperspb.UInt32(3600), + ConnectionIdleTimeoutDuration: wrapperspb.UInt32(180), + SessionConnectionLimit: wrapperspb.UInt32(5), }, }, errCode: codes.OK, @@ -634,9 +658,12 @@ func TestUpdate(t *testing.T) { Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{ "default_port": structpb.NewNumberValue(2), }}, - Type: target.TcpTargetType.String(), - HostSetIds: hsIds, - HostSets: hostSets, + Type: target.TcpTargetType.String(), + HostSetIds: hsIds, + HostSets: hostSets, + SessionMaxDuration: wrapperspb.UInt32(3600), + ConnectionIdleTimeoutDuration: wrapperspb.UInt32(180), + SessionConnectionLimit: wrapperspb.UInt32(5), }, }, errCode: codes.OK, diff --git a/internal/servers/controller/handlers/verifiers.go b/internal/servers/controller/handlers/verifiers.go index 8f8f18e78..fddbce5ee 100644 --- a/internal/servers/controller/handlers/verifiers.go +++ b/internal/servers/controller/handlers/verifiers.go @@ -29,6 +29,12 @@ func ValidateCreateRequest(i ApiResource, fn CustomValidatorFunc) error { if i.GetId() != "" { badFields["id"] = "This is a read only field." } + if i.GetName() != nil { + i.GetName().Value = strings.TrimSpace(i.GetName().GetValue()) + } + if i.GetDescription() != nil { + i.GetDescription().Value = strings.TrimSpace(i.GetDescription().GetValue()) + } if i.GetCreatedTime() != nil { badFields["created_time"] = "This is a read only field." } @@ -66,6 +72,22 @@ func ValidateUpdateRequest(prefix string, r UpdateRequest, i ApiResource, fn Cus // the mask will be marked as unset. return nil } + if i.GetName() != nil { + trimmed := strings.TrimSpace(i.GetName().GetValue()) + if trimmed == "" { + badFields["name"] = "Cannot set empty string as name" + } else { + i.GetName().Value = trimmed + } + } + if i.GetDescription() != nil { + trimmed := strings.TrimSpace(i.GetDescription().GetValue()) + if trimmed == "" { + badFields["name"] = "Cannot set empty string as description" + } else { + i.GetDescription().Value = trimmed + } + } if i.GetVersion() == 0 { badFields["version"] = "Existing resource version is required for an update." } diff --git a/internal/session/repository_session.go b/internal/session/repository_session.go index fa9eea4e5..b729be984 100644 --- a/internal/session/repository_session.go +++ b/internal/session/repository_session.go @@ -57,13 +57,16 @@ func (r *Repository) CreateSession(ctx context.Context, sessionWrapper wrapping. if newSession.TofuToken != nil { return nil, nil, nil, fmt.Errorf("create session: tofu token must be empty: %w", db.ErrInvalidParameter) } + if newSession.ExpirationTime == nil || newSession.ExpirationTime.Timestamp.AsTime().IsZero() { + return nil, nil, nil, fmt.Errorf("create session: expiration is empty: %w", db.ErrInvalidParameter) + } id, err := newId() if err != nil { return nil, nil, nil, fmt.Errorf("create session: %w", err) } - privKey, certBytes, err := newCert(sessionWrapper, newSession.UserId, id) + privKey, certBytes, err := newCert(sessionWrapper, newSession.UserId, id, newSession.ExpirationTime.Timestamp.AsTime()) if err != nil { return nil, nil, nil, fmt.Errorf("create session: %w", err) } diff --git a/internal/session/repository_session_test.go b/internal/session/repository_session_test.go index 08fca0a4a..72a41fbfe 100644 --- a/internal/session/repository_session_test.go +++ b/internal/session/repository_session_test.go @@ -237,13 +237,16 @@ func TestRepository_CreateSession(t *testing.T) { t.Run(tt.name, func(t *testing.T) { assert, require := assert.New(t), require.New(t) s := &Session{ - UserId: tt.args.composedOf.UserId, - HostId: tt.args.composedOf.HostId, - TargetId: tt.args.composedOf.TargetId, - HostSetId: tt.args.composedOf.HostSetId, - AuthTokenId: tt.args.composedOf.AuthTokenId, - ScopeId: tt.args.composedOf.ScopeId, - Endpoint: "tcp://127.0.0.1:22", + UserId: tt.args.composedOf.UserId, + HostId: tt.args.composedOf.HostId, + TargetId: tt.args.composedOf.TargetId, + HostSetId: tt.args.composedOf.HostSetId, + AuthTokenId: tt.args.composedOf.AuthTokenId, + ScopeId: tt.args.composedOf.ScopeId, + Endpoint: "tcp://127.0.0.1:22", + ExpirationTime: tt.args.composedOf.ExpirationTime, + ConnectionLimit: tt.args.composedOf.ConnectionLimit, + ConnectionIdleTimeoutSeconds: tt.args.composedOf.ConnectionIdleTimeoutSeconds, } ses, st, privKey, err := repo.CreateSession(context.Background(), wrapper, s) if tt.wantErr { @@ -264,6 +267,11 @@ func TestRepository_CreateSession(t *testing.T) { assert.Equal(st.Status, StatusPending.String()) foundSession, foundStates, err := repo.LookupSession(context.Background(), ses.PublicId) assert.NoError(err) + + // Account for slight offsets in nanos + assert.True(foundSession.ExpirationTime.Timestamp.AsTime().Sub(ses.ExpirationTime.Timestamp.AsTime()) < time.Second) + ses.ExpirationTime = foundSession.ExpirationTime + assert.Equal(foundSession, ses) err = db.TestVerifyOplog(t, rw, ses.PublicId, db.WithOperation(oplog.OpType_OP_TYPE_CREATE), db.WithCreateNotBefore(10*time.Second)) diff --git a/internal/session/session.go b/internal/session/session.go index f6b8745cc..100f3d2b4 100644 --- a/internal/session/session.go +++ b/internal/session/session.go @@ -40,6 +40,12 @@ type ComposedOf struct { // warehouse as the worker may need to e.g. resolve DNS. This is to round // trip the information to the worker when it validates a session. Endpoint string + // Expiration time for the session + ExpirationTime *timestamp.Timestamp + // Max connections for the session + ConnectionLimit uint32 + // Idle timeout for each connection in the session + ConnectionIdleTimeoutSeconds uint32 } // Session contains information about a user's session with a target @@ -82,6 +88,10 @@ type Session struct { Version uint32 `json:"version,omitempty" gorm:"default:null"` // Endpoint Endpoint string `json:"-" gorm:"default:null"` + // Maximum number of connections in a session + ConnectionLimit uint32 `json:"connection_limit,omitempty" gorm:"default:null"` + // Time after which a connection idles out + ConnectionIdleTimeoutSeconds uint32 `json:"connection_idle_timeout_seconds,omitempty" gorm:"default:null"` // key_id is the key ID that was used for the encryption operation. It can be // used to identify a specific version of the key needed to decrypt the value, @@ -99,20 +109,19 @@ func (s *Session) GetPublicId() string { var _ Cloneable = (*Session)(nil) var _ db.VetForWriter = (*Session)(nil) -// New creates a new in memory session. WithExpirationTime option is support to -// set the session's expiration time. +// New creates a new in memory session. func New(c ComposedOf, opt ...Option) (*Session, error) { - opts := getOpts(opt...) - s := Session{ - UserId: c.UserId, - HostId: c.HostId, - TargetId: c.TargetId, - HostSetId: c.HostSetId, - AuthTokenId: c.AuthTokenId, - ScopeId: c.ScopeId, - Endpoint: c.Endpoint, - ExpirationTime: opts.withExpirationTime, + UserId: c.UserId, + HostId: c.HostId, + TargetId: c.TargetId, + HostSetId: c.HostSetId, + AuthTokenId: c.AuthTokenId, + ScopeId: c.ScopeId, + Endpoint: c.Endpoint, + ExpirationTime: c.ExpirationTime, + ConnectionLimit: c.ConnectionLimit, + ConnectionIdleTimeoutSeconds: c.ConnectionIdleTimeoutSeconds, } if err := s.validateNewSession("new session:"); err != nil { return nil, err @@ -128,18 +137,20 @@ func AllocSession() Session { // Clone creates a clone of the Session func (s *Session) Clone() interface{} { clone := &Session{ - PublicId: s.PublicId, - UserId: s.UserId, - HostId: s.HostId, - ServerId: s.ServerId, - ServerType: s.ServerType, - TargetId: s.TargetId, - HostSetId: s.HostSetId, - AuthTokenId: s.AuthTokenId, - ScopeId: s.ScopeId, - TerminationReason: s.TerminationReason, - Version: s.Version, - Endpoint: s.Endpoint, + PublicId: s.PublicId, + UserId: s.UserId, + HostId: s.HostId, + ServerId: s.ServerId, + ServerType: s.ServerType, + TargetId: s.TargetId, + HostSetId: s.HostSetId, + AuthTokenId: s.AuthTokenId, + ScopeId: s.ScopeId, + TerminationReason: s.TerminationReason, + Version: s.Version, + Endpoint: s.Endpoint, + ConnectionLimit: s.ConnectionLimit, + ConnectionIdleTimeoutSeconds: s.ConnectionIdleTimeoutSeconds, } if s.TofuToken != nil { clone.TofuToken = make([]byte, len(s.TofuToken)) @@ -217,6 +228,12 @@ func (s *Session) VetForWrite(ctx context.Context, r db.Reader, opType db.OpType return fmt.Errorf("session vet for write: update time is immutable: %w", db.ErrInvalidParameter) case contains(opts.WithFieldMaskPaths, "Endpoint"): return fmt.Errorf("session vet for write: endpoint is immutable: %w", db.ErrInvalidParameter) + case contains(opts.WithFieldMaskPaths, "ExpirationTime"): + return fmt.Errorf("session vet for write: expiration time is immutable: %w", db.ErrInvalidParameter) + case contains(opts.WithFieldMaskPaths, "ConnectionLimit"): + return fmt.Errorf("session vet for write: connection limit is immutable: %w", db.ErrInvalidParameter) + case contains(opts.WithFieldMaskPaths, "ConnectionIdleTimeoutSeconds"): + return fmt.Errorf("session vet for write: connection idle timeout seconds is immutable: %w", db.ErrInvalidParameter) case contains(opts.WithFieldMaskPaths, "TerminationReason"): if _, err := convertToReason(s.TerminationReason); err != nil { return fmt.Errorf("session vet for write: termination reason '%s' is invalid: %w", s.TerminationReason, db.ErrInvalidParameter) @@ -264,6 +281,9 @@ func (s *Session) validateNewSession(errorPrefix string) error { if s.Endpoint == "" { return fmt.Errorf("%s missing endpoint: %w", errorPrefix, db.ErrInvalidParameter) } + if s.ExpirationTime.GetTimestamp().AsTime().IsZero() { + return fmt.Errorf("%s missing expiration time: %w", errorPrefix, db.ErrInvalidParameter) + } if s.TerminationReason != "" { return fmt.Errorf("%s termination reason must be empty: %w", errorPrefix, db.ErrInvalidParameter) } @@ -291,7 +311,7 @@ func contains(ss []string, t string) bool { return false } -func newCert(wrapper wrapping.Wrapper, userId, jobId string) (ed25519.PrivateKey, []byte, error) { +func newCert(wrapper wrapping.Wrapper, userId, jobId string, exp time.Time) (ed25519.PrivateKey, []byte, error) { if wrapper == nil { return nil, nil, fmt.Errorf("new session cert: missing wrapper: %w", db.ErrInvalidParameter) } @@ -314,7 +334,7 @@ func newCert(wrapper wrapping.Wrapper, userId, jobId string) (ed25519.PrivateKey KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageKeyAgreement | x509.KeyUsageCertSign, SerialNumber: big.NewInt(mathrand.Int63()), NotBefore: time.Now().Add(-1 * time.Minute), - NotAfter: time.Now().Add(5 * time.Minute), + NotAfter: exp, BasicConstraintsValid: true, IsCA: true, } diff --git a/internal/session/session_test.go b/internal/session/session_test.go index b98c15b96..8e0575171 100644 --- a/internal/session/session_test.go +++ b/internal/session/session_test.go @@ -45,13 +45,16 @@ func TestSession_Create(t *testing.T) { opt: []Option{WithExpirationTime(exp)}, }, want: &Session{ - UserId: composedOf.UserId, - HostId: composedOf.HostId, - TargetId: composedOf.TargetId, - HostSetId: composedOf.HostSetId, - AuthTokenId: composedOf.AuthTokenId, - ScopeId: composedOf.ScopeId, - Endpoint: "tcp://127.0.0.1:22", + UserId: composedOf.UserId, + HostId: composedOf.HostId, + TargetId: composedOf.TargetId, + HostSetId: composedOf.HostSetId, + AuthTokenId: composedOf.AuthTokenId, + ScopeId: composedOf.ScopeId, + Endpoint: "tcp://127.0.0.1:22", + ExpirationTime: composedOf.ExpirationTime, + ConnectionLimit: composedOf.ConnectionLimit, + ConnectionIdleTimeoutSeconds: composedOf.ConnectionIdleTimeoutSeconds, }, create: true, }, @@ -143,7 +146,7 @@ func TestSession_Create(t *testing.T) { id, err := db.NewPublicId(SessionPrefix) require.NoError(err) got.PublicId = id - _, certBytes, err := newCert(wrapper, got.UserId, id) + _, certBytes, err := newCert(wrapper, got.UserId, id, composedOf.ExpirationTime.Timestamp.AsTime()) require.NoError(err) got.Certificate = certBytes err = db.New(conn).Create(context.Background(), got) diff --git a/internal/session/testing.go b/internal/session/testing.go index dcb7e4465..e7c9ea2d5 100644 --- a/internal/session/testing.go +++ b/internal/session/testing.go @@ -21,6 +21,7 @@ import ( "github.com/hashicorp/vault/sdk/helper/base62" "github.com/jinzhu/gorm" "github.com/stretchr/testify/require" + "google.golang.org/protobuf/types/known/timestamppb" ) // TestConnection creates a test connection for the sessionId in the repository. @@ -72,7 +73,7 @@ func TestSession(t *testing.T, conn *gorm.DB, wrapper wrapping.Wrapper, c Compos id, err := newId() require.NoError(err) s.PublicId = id - _, certBytes, err := newCert(wrapper, c.UserId, id) + _, certBytes, err := newCert(wrapper, c.UserId, id, c.ExpirationTime.Timestamp.AsTime()) require.NoError(err) s.Certificate = certBytes err = rw.Create(context.Background(), s) @@ -126,14 +127,19 @@ func TestSessionParams(t *testing.T, conn *gorm.DB, wrapper wrapping.Wrapper, ia at, err := authTokenRepo.CreateAuthToken(ctx, user, acct.GetPublicId()) require.NoError(err) + expTime := timestamppb.Now() + expTime.Seconds += int64(tcpTarget.GetSessionMaxDuration()) return ComposedOf{ - UserId: user.PublicId, - HostId: hosts[0].PublicId, - TargetId: tcpTarget.PublicId, - HostSetId: sets[0].PublicId, - AuthTokenId: at.PublicId, - ScopeId: tcpTarget.ScopeId, - Endpoint: "tcp://127.0.0.1:22", + UserId: user.PublicId, + HostId: hosts[0].PublicId, + TargetId: tcpTarget.PublicId, + HostSetId: sets[0].PublicId, + AuthTokenId: at.PublicId, + ScopeId: tcpTarget.ScopeId, + Endpoint: "tcp://127.0.0.1:22", + ExpirationTime: ×tamp.Timestamp{Timestamp: expTime}, + ConnectionLimit: tcpTarget.GetSessionConnectionLimit(), + ConnectionIdleTimeoutSeconds: tcpTarget.GetConnectionIdleTimeoutDuration(), } } @@ -170,5 +176,5 @@ func TestWorker(t *testing.T, conn *gorm.DB, wrapper wrapping.Wrapper) *servers. // as a parameter. It's currently used in controller.jobTestingHandler() and // should be deprecated once that function is refactored to use sessions properly. func TestCert(wrapper wrapping.Wrapper, userId, jobId string) (ed25519.PrivateKey, []byte, error) { - return newCert(wrapper, userId, jobId) + return newCert(wrapper, userId, jobId, time.Now().Add(5*time.Minute)) } diff --git a/internal/target/options.go b/internal/target/options.go index 82140d8c0..274697db0 100644 --- a/internal/target/options.go +++ b/internal/target/options.go @@ -1,5 +1,7 @@ package target +import "time" + // getOpts - iterate the inbound Options and return a struct func getOpts(opt ...Option) options { opts := getDefaultOptions() @@ -14,26 +16,32 @@ type Option func(*options) // options = how options are represented type options struct { - withName string - withDescription string - withDefaultPort uint32 - withLimit int - withScopeId string - withUserId string - withTargetType *TargetType - withHostSets []string + withName string + withDescription string + withDefaultPort uint32 + withLimit int + withScopeId string + withUserId string + withTargetType *TargetType + withHostSets []string + withSessionMaxDuration uint32 + withSessionConnectionLimit uint32 + withConnectionIdleTimeoutDuration uint32 } func getDefaultOptions() options { return options{ - withName: "", - withDescription: "", - withLimit: 0, - withDefaultPort: 0, - withScopeId: "", - withUserId: "", - withTargetType: nil, - withHostSets: nil, + withName: "", + withDescription: "", + withLimit: 0, + withDefaultPort: 0, + withScopeId: "", + withUserId: "", + withTargetType: nil, + withHostSets: nil, + withSessionMaxDuration: uint32((8 * time.Hour).Seconds()), + withSessionConnectionLimit: 1, + withConnectionIdleTimeoutDuration: uint32((1 * time.Hour).Seconds()), } } @@ -94,3 +102,21 @@ func WithHostSets(hs []string) Option { o.withHostSets = hs } } + +func WithSessionMaxDuration(dur uint32) Option { + return func(o *options) { + o.withSessionMaxDuration = dur + } +} + +func WithSessionConnectionLimit(limit uint32) Option { + return func(o *options) { + o.withSessionConnectionLimit = limit + } +} + +func WithConnectionIdleTimeoutDuration(dur uint32) Option { + return func(o *options) { + o.withConnectionIdleTimeoutDuration = dur + } +} diff --git a/internal/target/repository_tcp_target.go b/internal/target/repository_tcp_target.go index 5eb40c88b..a80427dae 100644 --- a/internal/target/repository_tcp_target.go +++ b/internal/target/repository_tcp_target.go @@ -115,6 +115,9 @@ func (r *Repository) UpdateTcpTarget(ctx context.Context, target *TcpTarget, ver case strings.EqualFold("name", f): case strings.EqualFold("description", f): case strings.EqualFold("defaultport", f): + case strings.EqualFold("sessionmaxduration", f): + case strings.EqualFold("sessionconnectionlimit", f): + case strings.EqualFold("connectionidletimeoutduration", f): default: return nil, nil, db.NoRowsAffected, fmt.Errorf("update tcp target: field: %s: %w", f, db.ErrInvalidFieldMask) } @@ -122,11 +125,15 @@ func (r *Repository) UpdateTcpTarget(ctx context.Context, target *TcpTarget, ver var dbMask, nullFields []string dbMask, nullFields = dbcommon.BuildUpdatePaths( map[string]interface{}{ - "Name": target.Name, - "Description": target.Description, - "DefaultPort": target.DefaultPort, + "Name": target.Name, + "Description": target.Description, + "DefaultPort": target.DefaultPort, + "SessionMaxDuration": target.SessionMaxDuration, + "SessionConnectionLimit": target.SessionConnectionLimit, + "ConnectionIdleTimeoutDuration": target.ConnectionIdleTimeoutDuration, }, fieldMaskPaths, + []string{"SessionMaxDuration", "SessionConnectionLimit", "ConnectionIdleTimeoutDuration"}, ) if len(dbMask) == 0 && len(nullFields) == 0 { return nil, nil, db.NoRowsAffected, fmt.Errorf("update tcp target: %w", db.ErrEmptyFieldMask) diff --git a/internal/target/store/target.pb.go b/internal/target/store/target.pb.go index ceb700e26..094f948ac 100644 --- a/internal/target/store/target.pb.go +++ b/internal/target/store/target.pb.go @@ -62,6 +62,15 @@ type TargetView struct { // default port of the Target // @inject_tag: `gorm:"default:null"` DefaultPort uint32 `protobuf:"varint,90,opt,name=default_port,json=defaultPort,proto3" json:"default_port,omitempty" gorm:"default:null"` + // Maximum total lifetime of a created session, in seconds + // @inject_tag: `gorm:"default:null"` + SessionMaxDuration uint32 `protobuf:"varint,100,opt,name=session_max_duration,json=sessionMaxDuration,proto3" json:"session_max_duration,omitempty" gorm:"default:null"` + // Maximum number of connections in a session + // @inject_tag: `gorm:"default:null"` + SessionConnectionLimit uint32 `protobuf:"varint,110,opt,name=session_connection_limit,json=sessionConnectionLimit,proto3" json:"session_connection_limit,omitempty" gorm:"default:null"` + // Idle timeout for a connection in the session, in seconds + // @inject_tag: `gorm:"default:null"` + ConnectionIdleTimeoutDuration uint32 `protobuf:"varint,120,opt,name=connection_idle_timeout_duration,json=connectionIdleTimeoutDuration,proto3" json:"connection_idle_timeout_duration,omitempty" gorm:"default:null"` } func (x *TargetView) Reset() { @@ -159,6 +168,27 @@ func (x *TargetView) GetDefaultPort() uint32 { return 0 } +func (x *TargetView) GetSessionMaxDuration() uint32 { + if x != nil { + return x.SessionMaxDuration + } + return 0 +} + +func (x *TargetView) GetSessionConnectionLimit() uint32 { + if x != nil { + return x.SessionConnectionLimit + } + return 0 +} + +func (x *TargetView) GetConnectionIdleTimeoutDuration() uint32 { + if x != nil { + return x.ConnectionIdleTimeoutDuration + } + return 0 +} + type TargetHostSet struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -259,6 +289,15 @@ type TcpTarget struct { // default port of the TargetTcp // @inject_tag: `gorm:"default:null"` DefaultPort uint32 `protobuf:"varint,80,opt,name=default_port,json=defaultPort,proto3" json:"default_port,omitempty" gorm:"default:null"` + // Maximum total lifetime of a created session, in seconds + // @inject_tag: `gorm:"default:null"` + SessionMaxDuration uint32 `protobuf:"varint,100,opt,name=session_max_duration,json=sessionMaxDuration,proto3" json:"session_max_duration,omitempty" gorm:"default:null"` + // Maximum number of connections in a session + // @inject_tag: `gorm:"default:null"` + SessionConnectionLimit uint32 `protobuf:"varint,110,opt,name=session_connection_limit,json=sessionConnectionLimit,proto3" json:"session_connection_limit,omitempty" gorm:"default:null"` + // Idle timeout for a connection in the session, in seconds + // @inject_tag: `gorm:"default:null"` + ConnectionIdleTimeoutDuration uint32 `protobuf:"varint,120,opt,name=connection_idle_timeout_duration,json=connectionIdleTimeoutDuration,proto3" json:"connection_idle_timeout_duration,omitempty" gorm:"default:null"` } func (x *TcpTarget) Reset() { @@ -349,6 +388,27 @@ func (x *TcpTarget) GetDefaultPort() uint32 { return 0 } +func (x *TcpTarget) GetSessionMaxDuration() uint32 { + if x != nil { + return x.SessionMaxDuration + } + return 0 +} + +func (x *TcpTarget) GetSessionConnectionLimit() uint32 { + if x != nil { + return x.SessionConnectionLimit + } + return 0 +} + +func (x *TcpTarget) GetConnectionIdleTimeoutDuration() uint32 { + if x != nil { + return x.ConnectionIdleTimeoutDuration + } + return 0 +} + var File_controller_storage_target_store_v1_target_proto protoreflect.FileDescriptor var file_controller_storage_target_store_v1_target_proto_rawDesc = []byte{ @@ -363,7 +423,7 @@ var file_controller_storage_target_store_v1_target_proto_rawDesc = []byte{ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2a, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x22, 0xe5, 0x02, 0x0a, 0x0a, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x56, 0x69, 0x65, + 0x74, 0x6f, 0x22, 0x9a, 0x04, 0x0a, 0x0a, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x56, 0x69, 0x65, 0x77, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, @@ -385,48 +445,82 @@ var file_controller_storage_target_store_v1_target_proto_rawDesc = []byte{ 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x50, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x5a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x64, - 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x22, 0x99, 0x01, 0x0a, 0x0d, 0x54, - 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, 0x12, 0x1b, 0x0a, 0x09, - 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x0b, 0x68, 0x6f, 0x73, - 0x74, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, - 0x68, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, 0x49, 0x64, 0x12, 0x4b, 0x0a, 0x0b, 0x63, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, + 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x30, 0x0a, 0x14, 0x73, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x4d, 0x61, 0x78, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x18, + 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x6e, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x16, + 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x47, 0x0a, 0x20, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x6c, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, + 0x74, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x78, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x1d, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x6c, 0x65, + 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, + 0x99, 0x01, 0x0a, 0x0d, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x65, + 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x64, 0x12, 0x1e, + 0x0a, 0x0b, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x68, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, 0x49, 0x64, 0x12, 0x4b, + 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x1e, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, + 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, + 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x93, 0x06, 0x0a, 0x09, + 0x54, 0x63, 0x70, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x75, 0x62, + 0x6c, 0x69, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x75, + 0x62, 0x6c, 0x69, 0x63, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, + 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x49, + 0x64, 0x12, 0x24, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x10, 0xc2, 0xdd, 0x29, 0x0c, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x40, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x28, 0x20, 0x01, 0x28, 0x09, 0x42, 0x1e, 0xc2, 0xdd, + 0x29, 0x1a, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4b, 0x0a, 0x0b, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x32, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xae, 0x03, 0x0a, 0x09, 0x54, 0x63, 0x70, 0x54, 0x61, - 0x72, 0x67, 0x65, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x69, - 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, - 0x64, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x42, 0x10, 0xc2, 0xdd, 0x29, 0x0c, - 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x12, 0x40, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x28, 0x20, 0x01, 0x28, 0x09, 0x42, 0x1e, 0xc2, 0xdd, 0x29, 0x1a, 0x0a, 0x0b, 0x64, - 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0b, 0x64, 0x65, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4b, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, - 0x69, 0x6d, 0x65, 0x18, 0x32, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, - 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, - 0x65, 0x12, 0x4b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, - 0x18, 0x3c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, - 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x18, - 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x46, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x4d, 0x0a, 0x0c, 0x64, 0x65, 0x66, 0x61, - 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x50, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x2a, - 0xc2, 0xdd, 0x29, 0x26, 0x0a, 0x0b, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x6f, 0x72, - 0x74, 0x12, 0x17, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x64, 0x65, - 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x0b, 0x64, 0x65, 0x66, 0x61, - 0x75, 0x6c, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, - 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, - 0x6c, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x3b, 0x73, - 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x4b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x3c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, + 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, + 0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x46, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x4d, 0x0a, + 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x50, 0x20, + 0x01, 0x28, 0x0d, 0x42, 0x2a, 0xc2, 0xdd, 0x29, 0x26, 0x0a, 0x0b, 0x44, 0x65, 0x66, 0x61, 0x75, + 0x6c, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x17, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, + 0x65, 0x73, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x52, + 0x0b, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x60, 0x0a, 0x14, + 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x64, 0x75, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x2e, 0xc2, 0xdd, 0x29, 0x2a, + 0x0a, 0x12, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x78, 0x44, 0x75, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, + 0x78, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x12, 0x73, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x78, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x70, + 0x0a, 0x18, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x6e, 0x20, 0x01, 0x28, 0x0d, + 0x42, 0x36, 0xc2, 0xdd, 0x29, 0x32, 0x0a, 0x16, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x18, + 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x16, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x6d, 0x69, 0x74, + 0x12, 0x8e, 0x01, 0x0a, 0x20, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x69, 0x64, 0x6c, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x64, 0x75, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x78, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x45, 0xc2, 0xdd, 0x29, + 0x41, 0x0a, 0x1d, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x6c, + 0x65, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x20, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x6c, + 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x1d, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, + 0x6c, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, + 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x61, 0x72, 0x67, + 0x65, 0x74, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x3b, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/internal/target/target.go b/internal/target/target.go index 4d6146b2c..d3fab3500 100644 --- a/internal/target/target.go +++ b/internal/target/target.go @@ -19,6 +19,9 @@ type Target interface { GetType() string GetCreateTime() *timestamp.Timestamp GetUpdateTime() *timestamp.Timestamp + GetSessionMaxDuration() uint32 + GetSessionConnectionLimit() uint32 + GetConnectionIdleTimeoutDuration() uint32 oplog(op oplog.OpType) oplog.Metadata } @@ -88,6 +91,9 @@ func (t *targetView) targetSubType() (Target, error) { tcpTarget.CreateTime = t.CreateTime tcpTarget.UpdateTime = t.UpdateTime tcpTarget.Version = t.Version + tcpTarget.SessionMaxDuration = t.SessionMaxDuration + tcpTarget.SessionConnectionLimit = t.SessionConnectionLimit + tcpTarget.ConnectionIdleTimeoutDuration = t.ConnectionIdleTimeoutDuration return &tcpTarget, nil } return nil, fmt.Errorf("%s is an unknown target subtype of %s", t.PublicId, t.Type) diff --git a/internal/target/tcp_target.go b/internal/target/tcp_target.go index 2f08bdfb7..d0a422d28 100644 --- a/internal/target/tcp_target.go +++ b/internal/target/tcp_target.go @@ -32,10 +32,13 @@ func NewTcpTarget(scopeId string, opt ...Option) (*TcpTarget, error) { } t := &TcpTarget{ TcpTarget: &store.TcpTarget{ - ScopeId: scopeId, - Name: opts.withName, - Description: opts.withDescription, - DefaultPort: opts.withDefaultPort, + ScopeId: scopeId, + Name: opts.withName, + Description: opts.withDescription, + DefaultPort: opts.withDefaultPort, + ConnectionIdleTimeoutDuration: opts.withConnectionIdleTimeoutDuration, + SessionConnectionLimit: opts.withSessionConnectionLimit, + SessionMaxDuration: opts.withSessionMaxDuration, }, } return t, nil diff --git a/internal/target/tcp_target_test.go b/internal/target/tcp_target_test.go index 97c930249..b5d195274 100644 --- a/internal/target/tcp_target_test.go +++ b/internal/target/tcp_target_test.go @@ -49,6 +49,9 @@ func TestTcpTarget_Create(t *testing.T) { t := allocTcpTarget() t.ScopeId = prj.PublicId t.Name = "valid-proj-scope" + t.SessionMaxDuration = uint32((8 * time.Hour).Seconds()) + t.SessionConnectionLimit = 1 + t.ConnectionIdleTimeoutDuration = uint32((1 * time.Hour).Seconds()) return &t }(), create: true,