diff --git a/.github/ISSUE_TEMPLATE/webtestplan.md b/.github/ISSUE_TEMPLATE/webtestplan.md index 2f905c9f3ec68..bcdac7b26219d 100644 --- a/.github/ISSUE_TEMPLATE/webtestplan.md +++ b/.github/ISSUE_TEMPLATE/webtestplan.md @@ -175,11 +175,14 @@ All actions should require re-authn with a webauthn device. Use Discover Wizard to enroll new resources and access them: -- [ ] SSH Server (teleport service, singular EC2, SSM agent) +- [ ] SSH Server using Teleport Service - [ ] Self-Hosted PostgreSQL and Mongo -- [ ] AWS RDS (singular RDS, auto discover with ECS) - [ ] Kubernetes -- [ ] AWS EKS cluster +- [ ] Using an AWS OIDC Integration + - [ ] EC2 Auto Enrollment (SSM) + - [ ] RDS flow: single database + - [ ] RDS flow: Auto Enrollment (by VPC) + - [ ] EKS Clusters - [ ] Non-guided cards link out to correct docs #### Access Lists diff --git a/api/gen/proto/go/teleport/autoupdate/v1/autoupdate.pb.go b/api/gen/proto/go/teleport/autoupdate/v1/autoupdate.pb.go index 6213401019f87..e01283cc82414 100644 --- a/api/gen/proto/go/teleport/autoupdate/v1/autoupdate.pb.go +++ b/api/gen/proto/go/teleport/autoupdate/v1/autoupdate.pb.go @@ -186,7 +186,8 @@ type AutoUpdateConfigSpec struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Tools *AutoUpdateConfigSpecTools `protobuf:"bytes,2,opt,name=tools,proto3" json:"tools,omitempty"` + Tools *AutoUpdateConfigSpecTools `protobuf:"bytes,2,opt,name=tools,proto3" json:"tools,omitempty"` + Agents *AutoUpdateConfigSpecAgents `protobuf:"bytes,3,opt,name=agents,proto3" json:"agents,omitempty"` } func (x *AutoUpdateConfigSpec) Reset() { @@ -226,6 +227,13 @@ func (x *AutoUpdateConfigSpec) GetTools() *AutoUpdateConfigSpecTools { return nil } +func (x *AutoUpdateConfigSpec) GetAgents() *AutoUpdateConfigSpecAgents { + if x != nil { + return x.Agents + } + return nil +} + // AutoUpdateConfigSpecTools encodes the parameters for client tools auto updates. type AutoUpdateConfigSpecTools struct { state protoimpl.MessageState @@ -287,8 +295,8 @@ type AutoUpdateConfigSpecAgents struct { // Once the window is over, the group transitions to the done state. Existing agents won't be updated until the next // maintenance window. MaintenanceWindowDuration *durationpb.Duration `protobuf:"bytes,3,opt,name=maintenance_window_duration,json=maintenanceWindowDuration,proto3" json:"maintenance_window_duration,omitempty"` - // agent_schedules specifies schedules for updates of grouped agents. - AgentSchedules *AgentAutoUpdateSchedules `protobuf:"bytes,5,opt,name=agent_schedules,json=agentSchedules,proto3" json:"agent_schedules,omitempty"` + // schedules specifies schedules for updates of grouped agents. + Schedules *AgentAutoUpdateSchedules `protobuf:"bytes,6,opt,name=schedules,proto3" json:"schedules,omitempty"` } func (x *AutoUpdateConfigSpecAgents) Reset() { @@ -342,9 +350,9 @@ func (x *AutoUpdateConfigSpecAgents) GetMaintenanceWindowDuration() *durationpb. return nil } -func (x *AutoUpdateConfigSpecAgents) GetAgentSchedules() *AgentAutoUpdateSchedules { +func (x *AutoUpdateConfigSpecAgents) GetSchedules() *AgentAutoUpdateSchedules { if x != nil { - return x.AgentSchedules + return x.Schedules } return nil } @@ -1068,167 +1076,173 @@ var file_teleport_autoupdate_v1_autoupdate_proto_rawDesc = []byte{ 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x70, 0x65, 0x63, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, 0x22, - 0x77, 0x0a, 0x14, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x53, 0x70, 0x65, 0x63, 0x12, 0x47, 0x0a, 0x05, 0x74, 0x6f, 0x6f, 0x6c, 0x73, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, - 0x74, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x53, 0x70, 0x65, 0x63, 0x54, 0x6f, 0x6f, 0x6c, 0x73, 0x52, 0x05, 0x74, 0x6f, 0x6f, 0x6c, 0x73, - 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x52, 0x10, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x5f, 0x61, 0x75, - 0x74, 0x6f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x22, 0x2f, 0x0a, 0x19, 0x41, 0x75, 0x74, 0x6f, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x70, 0x65, 0x63, - 0x54, 0x6f, 0x6f, 0x6c, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0x82, 0x02, 0x0a, 0x1a, 0x41, 0x75, - 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x70, - 0x65, 0x63, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x0a, 0x08, - 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x59, 0x0a, 0x1b, 0x6d, 0x61, 0x69, 0x6e, - 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x5f, 0x64, - 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x19, 0x6d, 0x61, 0x69, 0x6e, 0x74, 0x65, - 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x44, 0x75, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x59, 0x0a, 0x0f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x63, 0x68, - 0x65, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x74, - 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x75, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x41, 0x75, 0x74, 0x6f, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x52, 0x0e, - 0x61, 0x67, 0x65, 0x6e, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x62, - 0x0a, 0x18, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x46, 0x0a, 0x07, 0x72, 0x65, - 0x67, 0x75, 0x6c, 0x61, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x74, 0x65, - 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x75, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x07, 0x72, 0x65, 0x67, 0x75, 0x6c, - 0x61, 0x72, 0x22, 0x7a, 0x0a, 0x14, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x41, 0x75, 0x74, 0x6f, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, - 0x0a, 0x04, 0x64, 0x61, 0x79, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, - 0x79, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x68, 0x6f, 0x75, 0x72, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x48, 0x6f, 0x75, - 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x77, 0x61, 0x69, 0x74, 0x5f, 0x64, 0x61, 0x79, 0x73, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x77, 0x61, 0x69, 0x74, 0x44, 0x61, 0x79, 0x73, 0x22, 0xd9, - 0x01, 0x0a, 0x11, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x75, 0x62, 0x5f, - 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x4b, - 0x69, 0x6e, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x0a, - 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, - 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x41, 0x0a, 0x04, 0x73, 0x70, 0x65, 0x63, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, - 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, - 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x53, 0x70, 0x65, 0x63, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, 0x22, 0xc3, 0x01, 0x0a, 0x15, 0x41, - 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x53, 0x70, 0x65, 0x63, 0x12, 0x48, 0x0a, 0x05, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, - 0x75, 0x74, 0x6f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, - 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x70, - 0x65, 0x63, 0x54, 0x6f, 0x6f, 0x6c, 0x73, 0x52, 0x05, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x12, 0x4b, - 0x0a, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, + 0xc3, 0x01, 0x0a, 0x14, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x53, 0x70, 0x65, 0x63, 0x12, 0x47, 0x0a, 0x05, 0x74, 0x6f, 0x6f, 0x6c, + 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x53, 0x70, 0x65, 0x63, 0x54, 0x6f, 0x6f, 0x6c, 0x73, 0x52, 0x05, 0x74, 0x6f, 0x6f, 0x6c, + 0x73, 0x12, 0x4a, 0x0a, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x32, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x75, 0x74, + 0x6f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x70, 0x65, 0x63, 0x41, + 0x67, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x4a, 0x04, 0x08, + 0x01, 0x10, 0x02, 0x52, 0x10, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x75, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x22, 0x2f, 0x0a, 0x19, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x70, 0x65, 0x63, 0x54, 0x6f, 0x6f, + 0x6c, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0x8e, 0x02, 0x0a, 0x1a, 0x41, 0x75, 0x74, 0x6f, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x70, 0x65, 0x63, 0x41, + 0x67, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x74, 0x72, + 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x74, 0x72, + 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x59, 0x0a, 0x1b, 0x6d, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x6e, + 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x5f, 0x64, 0x75, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x19, 0x6d, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x61, 0x6e, + 0x63, 0x65, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x4e, 0x0a, 0x09, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, + 0x75, 0x74, 0x6f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x67, 0x65, + 0x6e, 0x74, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, + 0x64, 0x75, 0x6c, 0x65, 0x73, 0x52, 0x09, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x73, + 0x4a, 0x04, 0x08, 0x05, 0x10, 0x06, 0x52, 0x0f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x63, + 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x62, 0x0a, 0x18, 0x41, 0x67, 0x65, 0x6e, 0x74, + 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, + 0x6c, 0x65, 0x73, 0x12, 0x46, 0x0a, 0x07, 0x72, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, + 0x61, 0x75, 0x74, 0x6f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x67, + 0x65, 0x6e, 0x74, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x52, 0x07, 0x72, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x22, 0x7a, 0x0a, 0x14, 0x41, + 0x67, 0x65, 0x6e, 0x74, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x47, 0x72, + 0x6f, 0x75, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x79, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x79, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x73, + 0x74, 0x61, 0x72, 0x74, 0x5f, 0x68, 0x6f, 0x75, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x48, 0x6f, 0x75, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x77, 0x61, + 0x69, 0x74, 0x5f, 0x64, 0x61, 0x79, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x77, + 0x61, 0x69, 0x74, 0x44, 0x61, 0x79, 0x73, 0x22, 0xd9, 0x01, 0x0a, 0x11, 0x41, 0x75, 0x74, 0x6f, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, + 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, + 0x64, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x75, 0x62, 0x5f, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x18, 0x0a, 0x07, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x12, 0x41, 0x0a, 0x04, 0x73, 0x70, 0x65, 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x70, 0x65, 0x63, 0x41, 0x67, 0x65, - 0x6e, 0x74, 0x73, 0x52, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x4a, 0x04, 0x08, 0x01, 0x10, - 0x02, 0x52, 0x0d, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x22, 0x43, 0x0a, 0x1a, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x56, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x70, 0x65, 0x63, 0x54, 0x6f, 0x6f, 0x6c, 0x73, 0x12, 0x25, - 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x56, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x99, 0x01, 0x0a, 0x1b, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x70, 0x65, 0x63, 0x41, - 0x67, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x74, - 0x61, 0x72, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x61, - 0x72, 0x67, 0x65, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0d, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, - 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x6f, 0x64, - 0x65, 0x22, 0xb1, 0x02, 0x0a, 0x16, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x6f, 0x75, 0x74, 0x12, 0x12, 0x0a, 0x04, - 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, - 0x12, 0x19, 0x0a, 0x08, 0x73, 0x75, 0x62, 0x5f, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, - 0x72, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, - 0x46, 0x0a, 0x04, 0x73, 0x70, 0x65, 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, - 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x75, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x6f, 0x75, 0x74, 0x53, 0x70, 0x65, - 0x63, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, 0x12, 0x4c, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, + 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x70, 0x65, 0x63, 0x52, 0x04, 0x73, + 0x70, 0x65, 0x63, 0x22, 0xc3, 0x01, 0x0a, 0x15, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x70, 0x65, 0x63, 0x12, 0x48, 0x0a, + 0x05, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x74, + 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x75, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x70, 0x65, 0x63, 0x54, 0x6f, 0x6f, 0x6c, 0x73, + 0x52, 0x05, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x12, 0x4b, 0x0a, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x74, + 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, - 0x52, 0x6f, 0x6c, 0x6c, 0x6f, 0x75, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xc9, 0x01, 0x0a, 0x1a, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, + 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x53, 0x70, 0x65, 0x63, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x06, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x73, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x52, 0x0d, 0x74, 0x6f, 0x6f, 0x6c, + 0x73, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x43, 0x0a, 0x1a, 0x41, 0x75, 0x74, + 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x70, + 0x65, 0x63, 0x54, 0x6f, 0x6f, 0x6c, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, + 0x74, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0d, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x99, + 0x01, 0x0a, 0x1b, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x70, 0x65, 0x63, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x23, + 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x74, 0x61, 0x72, 0x74, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x63, + 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x63, + 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0xb1, 0x02, 0x0a, 0x16, 0x41, + 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x6f, + 0x6c, 0x6c, 0x6f, 0x75, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x75, 0x62, + 0x5f, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, + 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x38, + 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, + 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, + 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x46, 0x0a, 0x04, 0x73, 0x70, 0x65, 0x63, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, + 0x6f, 0x6c, 0x6c, 0x6f, 0x75, 0x74, 0x53, 0x70, 0x65, 0x63, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, + 0x12, 0x4c, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x34, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x75, 0x74, 0x6f, + 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x6f, 0x75, 0x74, - 0x53, 0x70, 0x65, 0x63, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x74, 0x61, - 0x72, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x61, 0x72, - 0x67, 0x65, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0d, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x27, 0x0a, 0x0f, - 0x61, 0x75, 0x74, 0x6f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x61, 0x75, 0x74, 0x6f, 0x75, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, - 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, - 0x79, 0x22, 0x71, 0x0a, 0x1c, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, - 0x67, 0x65, 0x6e, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x6f, 0x75, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x12, 0x51, 0x0a, 0x06, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x39, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x75, 0x74, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xc9, + 0x01, 0x0a, 0x1a, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, + 0x6e, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x6f, 0x75, 0x74, 0x53, 0x70, 0x65, 0x63, 0x12, 0x23, 0x0a, + 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x74, 0x61, 0x72, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x61, 0x72, 0x67, + 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x63, 0x68, + 0x65, 0x64, 0x75, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x63, 0x68, + 0x65, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x61, 0x75, 0x74, 0x6f, 0x75, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, + 0x61, 0x75, 0x74, 0x6f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x1a, + 0x0a, 0x08, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x22, 0x71, 0x0a, 0x1c, 0x41, 0x75, + 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x6f, 0x6c, + 0x6c, 0x6f, 0x75, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x51, 0x0a, 0x06, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x74, 0x65, 0x6c, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x67, + 0x65, 0x6e, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x6f, 0x75, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x06, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x22, 0xaf, 0x02, + 0x0a, 0x21, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, + 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x6f, 0x75, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x47, 0x72, + 0x6f, 0x75, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, + 0x6d, 0x65, 0x12, 0x47, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x31, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x6f, 0x75, - 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x06, 0x67, 0x72, - 0x6f, 0x75, 0x70, 0x73, 0x22, 0xaf, 0x02, 0x0a, 0x21, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x6f, 0x75, 0x74, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x39, - 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, - 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x47, 0x0a, 0x05, 0x73, 0x74, 0x61, - 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x31, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, - 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, - 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, - 0x74, 0x65, 0x12, 0x44, 0x0a, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0e, 0x6c, 0x61, 0x73, 0x74, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x6c, 0x61, 0x73, 0x74, - 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x2a, 0xf7, 0x01, 0x0a, 0x19, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, - 0x74, 0x61, 0x74, 0x65, 0x12, 0x2d, 0x0a, 0x29, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x55, 0x50, 0x44, - 0x41, 0x54, 0x45, 0x5f, 0x41, 0x47, 0x45, 0x4e, 0x54, 0x5f, 0x47, 0x52, 0x4f, 0x55, 0x50, 0x5f, - 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, - 0x44, 0x10, 0x00, 0x12, 0x2b, 0x0a, 0x27, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x55, 0x50, 0x44, 0x41, + 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x44, 0x0a, 0x10, 0x6c, + 0x61, 0x73, 0x74, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x52, 0x0e, 0x6c, 0x61, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, + 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x6c, + 0x61, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x2a, + 0xf7, 0x01, 0x0a, 0x19, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x67, + 0x65, 0x6e, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2d, 0x0a, + 0x29, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x41, 0x47, 0x45, + 0x4e, 0x54, 0x5f, 0x47, 0x52, 0x4f, 0x55, 0x50, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, + 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x2b, 0x0a, 0x27, + 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x41, 0x47, 0x45, 0x4e, + 0x54, 0x5f, 0x47, 0x52, 0x4f, 0x55, 0x50, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, + 0x53, 0x54, 0x41, 0x52, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x28, 0x0a, 0x24, 0x41, 0x55, 0x54, + 0x4f, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x41, 0x47, 0x45, 0x4e, 0x54, 0x5f, 0x47, + 0x52, 0x4f, 0x55, 0x50, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x56, + 0x45, 0x10, 0x02, 0x12, 0x26, 0x0a, 0x22, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x41, 0x47, 0x45, 0x4e, 0x54, 0x5f, 0x47, 0x52, 0x4f, 0x55, 0x50, 0x5f, 0x53, - 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x54, 0x41, 0x52, 0x54, 0x45, 0x44, 0x10, 0x01, - 0x12, 0x28, 0x0a, 0x24, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, - 0x41, 0x47, 0x45, 0x4e, 0x54, 0x5f, 0x47, 0x52, 0x4f, 0x55, 0x50, 0x5f, 0x53, 0x54, 0x41, 0x54, - 0x45, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x02, 0x12, 0x26, 0x0a, 0x22, 0x41, 0x55, - 0x54, 0x4f, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x41, 0x47, 0x45, 0x4e, 0x54, 0x5f, - 0x47, 0x52, 0x4f, 0x55, 0x50, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x44, 0x4f, 0x4e, 0x45, - 0x10, 0x03, 0x12, 0x2c, 0x0a, 0x28, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, - 0x45, 0x5f, 0x41, 0x47, 0x45, 0x4e, 0x54, 0x5f, 0x47, 0x52, 0x4f, 0x55, 0x50, 0x5f, 0x53, 0x54, - 0x41, 0x54, 0x45, 0x5f, 0x52, 0x4f, 0x4c, 0x4c, 0x45, 0x44, 0x42, 0x41, 0x43, 0x4b, 0x10, 0x04, - 0x42, 0x56, 0x5a, 0x54, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, - 0x72, 0x61, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, - 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, - 0x61, 0x75, 0x74, 0x6f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x61, 0x75, - 0x74, 0x6f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x54, 0x41, 0x54, 0x45, 0x5f, 0x44, 0x4f, 0x4e, 0x45, 0x10, 0x03, 0x12, 0x2c, 0x0a, 0x28, 0x41, + 0x55, 0x54, 0x4f, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x41, 0x47, 0x45, 0x4e, 0x54, + 0x5f, 0x47, 0x52, 0x4f, 0x55, 0x50, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x52, 0x4f, 0x4c, + 0x4c, 0x45, 0x44, 0x42, 0x41, 0x43, 0x4b, 0x10, 0x04, 0x42, 0x56, 0x5a, 0x54, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x61, + 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, + 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x61, 0x75, 0x74, 0x6f, 0x75, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x61, 0x75, 0x74, 0x6f, 0x75, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1269,25 +1283,26 @@ var file_teleport_autoupdate_v1_autoupdate_proto_depIdxs = []int32{ 15, // 0: teleport.autoupdate.v1.AutoUpdateConfig.metadata:type_name -> teleport.header.v1.Metadata 2, // 1: teleport.autoupdate.v1.AutoUpdateConfig.spec:type_name -> teleport.autoupdate.v1.AutoUpdateConfigSpec 3, // 2: teleport.autoupdate.v1.AutoUpdateConfigSpec.tools:type_name -> teleport.autoupdate.v1.AutoUpdateConfigSpecTools - 16, // 3: teleport.autoupdate.v1.AutoUpdateConfigSpecAgents.maintenance_window_duration:type_name -> google.protobuf.Duration - 5, // 4: teleport.autoupdate.v1.AutoUpdateConfigSpecAgents.agent_schedules:type_name -> teleport.autoupdate.v1.AgentAutoUpdateSchedules - 6, // 5: teleport.autoupdate.v1.AgentAutoUpdateSchedules.regular:type_name -> teleport.autoupdate.v1.AgentAutoUpdateGroup - 15, // 6: teleport.autoupdate.v1.AutoUpdateVersion.metadata:type_name -> teleport.header.v1.Metadata - 8, // 7: teleport.autoupdate.v1.AutoUpdateVersion.spec:type_name -> teleport.autoupdate.v1.AutoUpdateVersionSpec - 9, // 8: teleport.autoupdate.v1.AutoUpdateVersionSpec.tools:type_name -> teleport.autoupdate.v1.AutoUpdateVersionSpecTools - 10, // 9: teleport.autoupdate.v1.AutoUpdateVersionSpec.agents:type_name -> teleport.autoupdate.v1.AutoUpdateVersionSpecAgents - 15, // 10: teleport.autoupdate.v1.AutoUpdateAgentRollout.metadata:type_name -> teleport.header.v1.Metadata - 12, // 11: teleport.autoupdate.v1.AutoUpdateAgentRollout.spec:type_name -> teleport.autoupdate.v1.AutoUpdateAgentRolloutSpec - 13, // 12: teleport.autoupdate.v1.AutoUpdateAgentRollout.status:type_name -> teleport.autoupdate.v1.AutoUpdateAgentRolloutStatus - 14, // 13: teleport.autoupdate.v1.AutoUpdateAgentRolloutStatus.groups:type_name -> teleport.autoupdate.v1.AutoUpdateAgentRolloutStatusGroup - 17, // 14: teleport.autoupdate.v1.AutoUpdateAgentRolloutStatusGroup.start_time:type_name -> google.protobuf.Timestamp - 0, // 15: teleport.autoupdate.v1.AutoUpdateAgentRolloutStatusGroup.state:type_name -> teleport.autoupdate.v1.AutoUpdateAgentGroupState - 17, // 16: teleport.autoupdate.v1.AutoUpdateAgentRolloutStatusGroup.last_update_time:type_name -> google.protobuf.Timestamp - 17, // [17:17] is the sub-list for method output_type - 17, // [17:17] is the sub-list for method input_type - 17, // [17:17] is the sub-list for extension type_name - 17, // [17:17] is the sub-list for extension extendee - 0, // [0:17] is the sub-list for field type_name + 4, // 3: teleport.autoupdate.v1.AutoUpdateConfigSpec.agents:type_name -> teleport.autoupdate.v1.AutoUpdateConfigSpecAgents + 16, // 4: teleport.autoupdate.v1.AutoUpdateConfigSpecAgents.maintenance_window_duration:type_name -> google.protobuf.Duration + 5, // 5: teleport.autoupdate.v1.AutoUpdateConfigSpecAgents.schedules:type_name -> teleport.autoupdate.v1.AgentAutoUpdateSchedules + 6, // 6: teleport.autoupdate.v1.AgentAutoUpdateSchedules.regular:type_name -> teleport.autoupdate.v1.AgentAutoUpdateGroup + 15, // 7: teleport.autoupdate.v1.AutoUpdateVersion.metadata:type_name -> teleport.header.v1.Metadata + 8, // 8: teleport.autoupdate.v1.AutoUpdateVersion.spec:type_name -> teleport.autoupdate.v1.AutoUpdateVersionSpec + 9, // 9: teleport.autoupdate.v1.AutoUpdateVersionSpec.tools:type_name -> teleport.autoupdate.v1.AutoUpdateVersionSpecTools + 10, // 10: teleport.autoupdate.v1.AutoUpdateVersionSpec.agents:type_name -> teleport.autoupdate.v1.AutoUpdateVersionSpecAgents + 15, // 11: teleport.autoupdate.v1.AutoUpdateAgentRollout.metadata:type_name -> teleport.header.v1.Metadata + 12, // 12: teleport.autoupdate.v1.AutoUpdateAgentRollout.spec:type_name -> teleport.autoupdate.v1.AutoUpdateAgentRolloutSpec + 13, // 13: teleport.autoupdate.v1.AutoUpdateAgentRollout.status:type_name -> teleport.autoupdate.v1.AutoUpdateAgentRolloutStatus + 14, // 14: teleport.autoupdate.v1.AutoUpdateAgentRolloutStatus.groups:type_name -> teleport.autoupdate.v1.AutoUpdateAgentRolloutStatusGroup + 17, // 15: teleport.autoupdate.v1.AutoUpdateAgentRolloutStatusGroup.start_time:type_name -> google.protobuf.Timestamp + 0, // 16: teleport.autoupdate.v1.AutoUpdateAgentRolloutStatusGroup.state:type_name -> teleport.autoupdate.v1.AutoUpdateAgentGroupState + 17, // 17: teleport.autoupdate.v1.AutoUpdateAgentRolloutStatusGroup.last_update_time:type_name -> google.protobuf.Timestamp + 18, // [18:18] is the sub-list for method output_type + 18, // [18:18] is the sub-list for method input_type + 18, // [18:18] is the sub-list for extension type_name + 18, // [18:18] is the sub-list for extension extendee + 0, // [0:18] is the sub-list for field type_name } func init() { file_teleport_autoupdate_v1_autoupdate_proto_init() } diff --git a/api/gen/proto/go/teleport/provisioning/v1/provisioning.pb.go b/api/gen/proto/go/teleport/provisioning/v1/provisioning.pb.go index 1c6cdf10aa8bd..910d748d230ea 100644 --- a/api/gen/proto/go/teleport/provisioning/v1/provisioning.pb.go +++ b/api/gen/proto/go/teleport/provisioning/v1/provisioning.pb.go @@ -328,6 +328,16 @@ type PrincipalStateStatus struct { LastProvisioned *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=last_provisioned,json=lastProvisioned,proto3" json:"last_provisioned,omitempty"` // Error holds a description of the last provisioing error, if any. Error string `protobuf:"bytes,4,opt,name=error,proto3" json:"error,omitempty"` + // Revision holds the revision of the principal record provisioned into the + // downstream system. Used to assert that the latest revision of the principal + // is provisioned downstream and detect changes in the principal that require + // re-provisoning. + ProvisionedPrincipalRevision string `protobuf:"bytes,6,opt,name=provisioned_principal_revision,json=provisionedPrincipalRevision,proto3" json:"provisioned_principal_revision,omitempty"` + // ActiveLocks holds the list of known active locks on the principal. Used to + // store the lock state across restarts of Teleport in order to detect state + // changes that may happen while Teleport is not running (e.g. a storage + // backend deleting an expired lock record while Teleport is offline) + ActiveLocks []string `protobuf:"bytes,7,rep,name=active_locks,json=activeLocks,proto3" json:"active_locks,omitempty"` } func (x *PrincipalStateStatus) Reset() { @@ -388,6 +398,20 @@ func (x *PrincipalStateStatus) GetError() string { return "" } +func (x *PrincipalStateStatus) GetProvisionedPrincipalRevision() string { + if x != nil { + return x.ProvisionedPrincipalRevision + } + return "" +} + +func (x *PrincipalStateStatus) GetActiveLocks() []string { + if x != nil { + return x.ActiveLocks + } + return nil +} + var File_teleport_provisioning_v1_provisioning_proto protoreflect.FileDescriptor var file_teleport_provisioning_v1_provisioning_proto_rawDesc = []byte{ @@ -428,7 +452,7 @@ var file_teleport_provisioning_v1_provisioning_proto_rawDesc = []byte{ 0x69, 0x70, 0x61, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0d, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, - 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x49, 0x64, 0x22, 0xfe, 0x01, 0x0a, 0x14, 0x50, + 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x49, 0x64, 0x22, 0xe7, 0x02, 0x0a, 0x14, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x5a, 0x0a, 0x12, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, @@ -443,31 +467,37 @@ var file_teleport_provisioning_v1_provisioning_proto_rawDesc = []byte{ 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0f, 0x6c, 0x61, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4a, 0x04, 0x08, - 0x01, 0x10, 0x02, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2a, 0x99, 0x01, 0x0a, 0x11, - 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, - 0x65, 0x12, 0x22, 0x0a, 0x1e, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x53, 0x49, 0x4f, 0x4e, 0x49, 0x4e, - 0x47, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, - 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1c, 0x0a, 0x18, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x53, 0x49, - 0x4f, 0x4e, 0x49, 0x4e, 0x47, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x4c, - 0x45, 0x10, 0x01, 0x12, 0x22, 0x0a, 0x1e, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x53, 0x49, 0x4f, 0x4e, - 0x49, 0x4e, 0x47, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x53, - 0x49, 0x4f, 0x4e, 0x45, 0x44, 0x10, 0x02, 0x12, 0x1e, 0x0a, 0x1a, 0x50, 0x52, 0x4f, 0x56, 0x49, - 0x53, 0x49, 0x4f, 0x4e, 0x49, 0x4e, 0x47, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x44, 0x45, - 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x03, 0x2a, 0x68, 0x0a, 0x0d, 0x50, 0x72, 0x69, 0x6e, 0x63, - 0x69, 0x70, 0x61, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1e, 0x0a, 0x1a, 0x50, 0x52, 0x49, 0x4e, - 0x43, 0x49, 0x50, 0x41, 0x4c, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, - 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x17, 0x0a, 0x13, 0x50, 0x52, 0x49, 0x4e, - 0x43, 0x49, 0x50, 0x41, 0x4c, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x53, 0x45, 0x52, 0x10, - 0x01, 0x12, 0x1e, 0x0a, 0x1a, 0x50, 0x52, 0x49, 0x4e, 0x43, 0x49, 0x50, 0x41, 0x4c, 0x5f, 0x54, - 0x59, 0x50, 0x45, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x10, - 0x02, 0x42, 0x5c, 0x5a, 0x5a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, - 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, - 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x2f, 0x76, 0x31, - 0x3b, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x76, 0x31, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x44, 0x0a, + 0x1e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x5f, 0x70, 0x72, 0x69, + 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x5f, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1c, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, + 0x65, 0x64, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x52, 0x65, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x6c, 0x6f, + 0x63, 0x6b, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x63, 0x74, 0x69, 0x76, + 0x65, 0x4c, 0x6f, 0x63, 0x6b, 0x73, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x52, 0x06, 0x73, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x2a, 0x99, 0x01, 0x0a, 0x11, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x22, 0x0a, 0x1e, 0x50, 0x52, + 0x4f, 0x56, 0x49, 0x53, 0x49, 0x4f, 0x4e, 0x49, 0x4e, 0x47, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, + 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1c, + 0x0a, 0x18, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x53, 0x49, 0x4f, 0x4e, 0x49, 0x4e, 0x47, 0x5f, 0x53, + 0x54, 0x41, 0x54, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x22, 0x0a, 0x1e, + 0x50, 0x52, 0x4f, 0x56, 0x49, 0x53, 0x49, 0x4f, 0x4e, 0x49, 0x4e, 0x47, 0x5f, 0x53, 0x54, 0x41, + 0x54, 0x45, 0x5f, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x53, 0x49, 0x4f, 0x4e, 0x45, 0x44, 0x10, 0x02, + 0x12, 0x1e, 0x0a, 0x1a, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x53, 0x49, 0x4f, 0x4e, 0x49, 0x4e, 0x47, + 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x03, + 0x2a, 0x68, 0x0a, 0x0d, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x1e, 0x0a, 0x1a, 0x50, 0x52, 0x49, 0x4e, 0x43, 0x49, 0x50, 0x41, 0x4c, 0x5f, 0x54, + 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, + 0x00, 0x12, 0x17, 0x0a, 0x13, 0x50, 0x52, 0x49, 0x4e, 0x43, 0x49, 0x50, 0x41, 0x4c, 0x5f, 0x54, + 0x59, 0x50, 0x45, 0x5f, 0x55, 0x53, 0x45, 0x52, 0x10, 0x01, 0x12, 0x1e, 0x0a, 0x1a, 0x50, 0x52, + 0x49, 0x4e, 0x43, 0x49, 0x50, 0x41, 0x4c, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x41, 0x43, 0x43, + 0x45, 0x53, 0x53, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x10, 0x02, 0x42, 0x5c, 0x5a, 0x5a, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, + 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, + 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x2f, 0x76, 0x31, 0x3b, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/api/proto/teleport/autoupdate/v1/autoupdate.proto b/api/proto/teleport/autoupdate/v1/autoupdate.proto index 8bd11fd8cdeec..5c7527d0177cf 100644 --- a/api/proto/teleport/autoupdate/v1/autoupdate.proto +++ b/api/proto/teleport/autoupdate/v1/autoupdate.proto @@ -38,6 +38,7 @@ message AutoUpdateConfigSpec { reserved 1; reserved "tools_autoupdate"; // ToolsAutoupdate is replaced by tools.mode. AutoUpdateConfigSpecTools tools = 2; + AutoUpdateConfigSpecAgents agents = 3; } // AutoUpdateConfigSpecTools encodes the parameters for client tools auto updates. @@ -48,6 +49,8 @@ message AutoUpdateConfigSpecTools { // AutoUpdateConfigSpecAgents encodes the parameters of automatic agent updates. message AutoUpdateConfigSpecAgents { + reserved 5; + reserved "agent_schedules"; // mode specifies whether agent autoupdates are enabled, disabled, or paused. string mode = 1; // strategy to use for updating the agents. @@ -56,8 +59,8 @@ message AutoUpdateConfigSpecAgents { // Once the window is over, the group transitions to the done state. Existing agents won't be updated until the next // maintenance window. google.protobuf.Duration maintenance_window_duration = 3; - // agent_schedules specifies schedules for updates of grouped agents. - AgentAutoUpdateSchedules agent_schedules = 5; + // schedules specifies schedules for updates of grouped agents. + AgentAutoUpdateSchedules schedules = 6; } // AgentAutoUpdateSchedules specifies update scheduled for grouped agents. diff --git a/api/proto/teleport/provisioning/v1/provisioning.proto b/api/proto/teleport/provisioning/v1/provisioning.proto index c0501fc8e55c1..4f1e8e0686d70 100644 --- a/api/proto/teleport/provisioning/v1/provisioning.proto +++ b/api/proto/teleport/provisioning/v1/provisioning.proto @@ -104,4 +104,16 @@ message PrincipalStateStatus { // Error holds a description of the last provisioing error, if any. string error = 4; + + // Revision holds the revision of the principal record provisioned into the + // downstream system. Used to assert that the latest revision of the principal + // is provisioned downstream and detect changes in the principal that require + // re-provisoning. + string provisioned_principal_revision = 6; + + // ActiveLocks holds the list of known active locks on the principal. Used to + // store the lock state across restarts of Teleport in order to detect state + // changes that may happen while Teleport is not running (e.g. a storage + // backend deleting an expired lock record while Teleport is offline) + repeated string active_locks = 7; } diff --git a/api/types/autoupdate/config.go b/api/types/autoupdate/config.go index d61c35eccf0c2..32ae056195b64 100644 --- a/api/types/autoupdate/config.go +++ b/api/types/autoupdate/config.go @@ -1,24 +1,24 @@ /* - * Teleport - * Copyright (C) 2024 Gravitational, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ +Copyright 2024 Gravitational, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ package autoupdate import ( + "time" + "github.com/gravitational/trace" "github.com/gravitational/teleport/api/gen/proto/go/teleport/autoupdate/v1" @@ -26,13 +26,6 @@ import ( "github.com/gravitational/teleport/api/types" ) -const ( - // ToolsUpdateModeEnabled enables client tools automatic updates. - ToolsUpdateModeEnabled = "enabled" - // ToolsUpdateModeDisabled disables client tools automatic updates. - ToolsUpdateModeDisabled = "disabled" -) - // NewAutoUpdateConfig creates a new auto update configuration resource. func NewAutoUpdateConfig(spec *autoupdate.AutoUpdateConfigSpec) (*autoupdate.AutoUpdateConfig, error) { config := &autoupdate.AutoUpdateConfig{ @@ -66,10 +59,41 @@ func ValidateAutoUpdateConfig(c *autoupdate.AutoUpdateConfig) error { return trace.BadParameter("Spec is nil") } if c.Spec.Tools != nil { - if c.Spec.Tools.Mode != ToolsUpdateModeDisabled && c.Spec.Tools.Mode != ToolsUpdateModeEnabled { - return trace.BadParameter("ToolsMode is not valid") + if err := checkToolsMode(c.Spec.Tools.Mode); err != nil { + return trace.Wrap(err, "validating spec.tools.mode") + } + } + if c.Spec.Agents != nil { + if err := checkAgentsMode(c.Spec.Agents.Mode); err != nil { + return trace.Wrap(err, "validating spec.agents.mode") + } + if err := checkAgentsStrategy(c.Spec.Agents.Strategy); err != nil { + return trace.Wrap(err, "validating spec.agents.strategy") } + + windowDuration := c.Spec.Agents.MaintenanceWindowDuration.AsDuration() + if c.Spec.Agents.Strategy == AgentsStrategyHaltOnError && windowDuration != 0 { + return trace.BadParameter("spec.agents.maintenance_window_duration must be zero when the strategy is %q", c.Spec.Agents.Strategy) + } + if c.Spec.Agents.Strategy == AgentsStrategyTimeBased && windowDuration < 10*time.Minute { + return trace.BadParameter("spec.agents.maintenance_window_duration must be greater than 10 minutes when the strategy is %q", c.Spec.Agents.Strategy) + } + + if err := checkAgentSchedules(c.Spec.Agents.Schedules); err != nil { + return trace.Wrap(err, "validating spec.agents.schedules") + } + } return nil } + +func checkAgentSchedules(schedules *autoupdate.AgentAutoUpdateSchedules) error { + // TODO: change this logic when we implement group support. + // Currently we reject any non-nil schedule + // When we'll implement schedule support, we'll treat an empty schedule as the default schedule. + if schedules == nil { + return nil + } + return trace.NotImplemented("agent schedules are not implemented yet") +} diff --git a/api/types/autoupdate/config_test.go b/api/types/autoupdate/config_test.go index 443d6f246fa56..f6b6a87aa6bd8 100644 --- a/api/types/autoupdate/config_test.go +++ b/api/types/autoupdate/config_test.go @@ -1,29 +1,29 @@ /* - * Teleport - * Copyright (C) 2024 Gravitational, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ +Copyright 2024 Gravitational, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ package autoupdate import ( "testing" + "time" "github.com/google/go-cmp/cmp" "github.com/stretchr/testify/require" "google.golang.org/protobuf/testing/protocmp" + "google.golang.org/protobuf/types/known/durationpb" "github.com/gravitational/teleport/api/gen/proto/go/teleport/autoupdate/v1" headerv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1" @@ -99,7 +99,121 @@ func TestNewAutoUpdateConfig(t *testing.T) { }, }, assertErr: func(t *testing.T, err error, a ...any) { - require.ErrorContains(t, err, "ToolsMode is not valid") + require.ErrorContains(t, err, "unsupported tools mode: \"invalid-mode\"") + }, + }, + { + name: "invalid agents mode", + spec: &autoupdate.AutoUpdateConfigSpec{ + Agents: &autoupdate.AutoUpdateConfigSpecAgents{ + Mode: "invalid-mode", + Strategy: AgentsStrategyHaltOnError, + }, + }, + assertErr: func(t *testing.T, err error, a ...any) { + require.ErrorContains(t, err, "unsupported agents mode: \"invalid-mode\"") + }, + }, + { + name: "invalid agents strategy", + spec: &autoupdate.AutoUpdateConfigSpec{ + Agents: &autoupdate.AutoUpdateConfigSpecAgents{ + Mode: AgentsUpdateModeEnabled, + Strategy: "invalid-strategy", + }, + }, + assertErr: func(t *testing.T, err error, a ...any) { + require.ErrorContains(t, err, "unsupported agents strategy: \"invalid-strategy\"") + }, + }, + { + name: "invalid agents non-nil maintenance window with halt-on-error", + spec: &autoupdate.AutoUpdateConfigSpec{ + Agents: &autoupdate.AutoUpdateConfigSpecAgents{ + Mode: AgentsUpdateModeEnabled, + Strategy: AgentsStrategyHaltOnError, + MaintenanceWindowDuration: durationpb.New(time.Hour), + }, + }, + assertErr: func(t *testing.T, err error, a ...any) { + require.ErrorContains(t, err, "maintenance_window_duration must be zero") + }, + }, + { + name: "invalid agents nil maintenance window with time-based strategy", + spec: &autoupdate.AutoUpdateConfigSpec{ + Agents: &autoupdate.AutoUpdateConfigSpecAgents{ + Mode: AgentsUpdateModeEnabled, + Strategy: AgentsStrategyTimeBased, + }, + }, + assertErr: func(t *testing.T, err error, a ...any) { + require.ErrorContains(t, err, "maintenance_window_duration must be greater than 10 minutes") + }, + }, + { + name: "invalid agents short maintenance window", + spec: &autoupdate.AutoUpdateConfigSpec{ + Agents: &autoupdate.AutoUpdateConfigSpecAgents{ + Mode: AgentsUpdateModeEnabled, + Strategy: AgentsStrategyTimeBased, + MaintenanceWindowDuration: durationpb.New(time.Minute), + }, + }, + assertErr: func(t *testing.T, err error, a ...any) { + require.ErrorContains(t, err, "maintenance_window_duration must be greater than 10 minutes") + }, + }, + { + name: "success agents autoupdate halt-on-failure", + spec: &autoupdate.AutoUpdateConfigSpec{ + Agents: &autoupdate.AutoUpdateConfigSpecAgents{ + Mode: AgentsUpdateModeEnabled, + Strategy: AgentsStrategyHaltOnError, + }, + }, + assertErr: func(t *testing.T, err error, a ...any) { + require.NoError(t, err) + }, + want: &autoupdate.AutoUpdateConfig{ + Kind: types.KindAutoUpdateConfig, + Version: types.V1, + Metadata: &headerv1.Metadata{ + Name: types.MetaNameAutoUpdateConfig, + }, + Spec: &autoupdate.AutoUpdateConfigSpec{ + Agents: &autoupdate.AutoUpdateConfigSpecAgents{ + Mode: AgentsUpdateModeEnabled, + Strategy: AgentsStrategyHaltOnError, + }, + }, + }, + }, + { + name: "success agents autoupdate time-based", + spec: &autoupdate.AutoUpdateConfigSpec{ + Agents: &autoupdate.AutoUpdateConfigSpecAgents{ + Mode: AgentsUpdateModeEnabled, + Strategy: AgentsStrategyTimeBased, + MaintenanceWindowDuration: durationpb.New(time.Hour), + }, + }, + assertErr: func(t *testing.T, err error, a ...any) { + require.NoError(t, err) + }, + want: &autoupdate.AutoUpdateConfig{ + Kind: types.KindAutoUpdateConfig, + Version: types.V1, + Metadata: &headerv1.Metadata{ + Name: types.MetaNameAutoUpdateConfig, + }, + Spec: &autoupdate.AutoUpdateConfigSpec{ + Agents: &autoupdate.AutoUpdateConfigSpecAgents{ + Mode: AgentsUpdateModeEnabled, + Strategy: AgentsStrategyTimeBased, + MaintenanceWindowDuration: durationpb.New(time.Hour), + }, + }, }, }, } diff --git a/api/types/autoupdate/constants.go b/api/types/autoupdate/constants.go new file mode 100644 index 0000000000000..deed5168fb21f --- /dev/null +++ b/api/types/autoupdate/constants.go @@ -0,0 +1,46 @@ +/* +Copyright 2024 Gravitational, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package autoupdate + +const ( + // ToolsUpdateModeEnabled enables client tools automatic updates. + ToolsUpdateModeEnabled = "enabled" + // ToolsUpdateModeDisabled disables client tools automatic updates. + ToolsUpdateModeDisabled = "disabled" + + // AgentsUpdateModeEnabled enabled agent automatic updates. + AgentsUpdateModeEnabled = "enabled" + // AgentsUpdateModeDisabled disables agent automatic updates. + AgentsUpdateModeDisabled = "disabled" + // AgentsUpdateModeSuspended temporarily suspends agent automatic updates. + AgentsUpdateModeSuspended = "suspended" + + // AgentsScheduleRegular is the regular agent update schedule. + AgentsScheduleRegular = "regular" + // AgentsScheduleImmediate is the immediate agent update schedule. + // Every agent must update immediately if it's not already running the target version. + // This can be used to recover agents in case of major incident or actively exploited vulnerability. + AgentsScheduleImmediate = "immediate" + + // AgentsStrategyHaltOnError is the agent update strategy that updates groups sequentially + // according to their order in the schedule. The previous groups must succeed. + AgentsStrategyHaltOnError = "halt-on-error" + // AgentsStrategyTimeBased is the agent update strategy that updates groups solely based on their + // maintenance window. There is no dependency between groups. Agents won't be instructed to update + // if the window is over. + AgentsStrategyTimeBased = "time-based" +) diff --git a/api/types/autoupdate/rollout.go b/api/types/autoupdate/rollout.go new file mode 100644 index 0000000000000..814d71313d3ed --- /dev/null +++ b/api/types/autoupdate/rollout.go @@ -0,0 +1,76 @@ +/* +Copyright 2024 Gravitational, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package autoupdate + +import ( + "github.com/gravitational/trace" + + "github.com/gravitational/teleport/api/gen/proto/go/teleport/autoupdate/v1" + headerv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1" + "github.com/gravitational/teleport/api/types" +) + +// NewAutoUpdateAgentRollout creates a new auto update version resource. +func NewAutoUpdateAgentRollout(spec *autoupdate.AutoUpdateAgentRolloutSpec) (*autoupdate.AutoUpdateAgentRollout, error) { + version := &autoupdate.AutoUpdateAgentRollout{ + Kind: types.KindAutoUpdateAgentRollout, + Version: types.V1, + Metadata: &headerv1.Metadata{ + Name: types.MetaNameAutoUpdateAgentRollout, + }, + Spec: spec, + } + if err := ValidateAutoUpdateAgentRollout(version); err != nil { + return nil, trace.Wrap(err) + } + + return version, nil +} + +// ValidateAutoUpdateAgentRollout checks that required parameters are set +// for the specified AutoUpdateAgentRollout. +func ValidateAutoUpdateAgentRollout(v *autoupdate.AutoUpdateAgentRollout) error { + if v == nil { + return trace.BadParameter("AutoUpdateAgentRollout is nil") + } + if v.Metadata == nil { + return trace.BadParameter("Metadata is nil") + } + if v.Metadata.Name != types.MetaNameAutoUpdateAgentRollout { + return trace.BadParameter("Name is not valid") + } + if v.Spec == nil { + return trace.BadParameter("Spec is nil") + } + if err := checkVersion(v.Spec.StartVersion); err != nil { + return trace.Wrap(err, "validating spec.start_version") + } + if err := checkVersion(v.Spec.TargetVersion); err != nil { + return trace.Wrap(err, "validating spec.target_version") + } + if err := checkAgentsMode(v.Spec.AutoupdateMode); err != nil { + return trace.Wrap(err, "validating spec.autoupdate_mode") + } + if err := checkScheduleName(v.Spec.Schedule); err != nil { + return trace.Wrap(err, "validating spec.schedule") + } + if err := checkAgentsStrategy(v.Spec.Strategy); err != nil { + return trace.Wrap(err, "validating spec.strategy") + } + + return nil +} diff --git a/api/types/autoupdate/rollout_test.go b/api/types/autoupdate/rollout_test.go new file mode 100644 index 0000000000000..cce4dc8495d83 --- /dev/null +++ b/api/types/autoupdate/rollout_test.go @@ -0,0 +1,145 @@ +/* +Copyright 2024 Gravitational, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package autoupdate + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/testing/protocmp" + + "github.com/gravitational/teleport/api/gen/proto/go/teleport/autoupdate/v1" + headerv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1" + "github.com/gravitational/teleport/api/types" +) + +// TestNewAutoUpdateConfig verifies validation for AutoUpdateConfig resource. +func TestNewAutoUpdateAgentRollout(t *testing.T) { + tests := []struct { + name string + spec *autoupdate.AutoUpdateAgentRolloutSpec + want *autoupdate.AutoUpdateAgentRollout + assertErr func(*testing.T, error, ...any) + }{ + { + name: "success valid rollout", + spec: &autoupdate.AutoUpdateAgentRolloutSpec{ + StartVersion: "1.2.3", + TargetVersion: "2.3.4-dev", + Schedule: AgentsScheduleRegular, + AutoupdateMode: AgentsUpdateModeEnabled, + Strategy: AgentsStrategyHaltOnError, + }, + assertErr: func(t *testing.T, err error, a ...any) { + require.NoError(t, err) + }, + want: &autoupdate.AutoUpdateAgentRollout{ + Kind: types.KindAutoUpdateAgentRollout, + Version: types.V1, + Metadata: &headerv1.Metadata{ + Name: types.MetaNameAutoUpdateAgentRollout, + }, + Spec: &autoupdate.AutoUpdateAgentRolloutSpec{ + StartVersion: "1.2.3", + TargetVersion: "2.3.4-dev", + Schedule: AgentsScheduleRegular, + AutoupdateMode: AgentsUpdateModeEnabled, + Strategy: AgentsStrategyHaltOnError, + }, + }, + }, + { + name: "missing spec", + spec: nil, + assertErr: func(t *testing.T, err error, a ...any) { + require.ErrorContains(t, err, "Spec is nil") + }, + }, + { + name: "missing start version", + spec: &autoupdate.AutoUpdateAgentRolloutSpec{ + TargetVersion: "2.3.4-dev", + Schedule: AgentsScheduleRegular, + AutoupdateMode: AgentsUpdateModeEnabled, + Strategy: AgentsStrategyHaltOnError, + }, + assertErr: func(t *testing.T, err error, a ...any) { + require.ErrorContains(t, err, "start_version\n\tversion is unset") + }, + }, + { + name: "invalid target version", + spec: &autoupdate.AutoUpdateAgentRolloutSpec{ + StartVersion: "1.2.3", + TargetVersion: "2-3-4", + Schedule: AgentsScheduleRegular, + AutoupdateMode: AgentsUpdateModeEnabled, + Strategy: AgentsStrategyHaltOnError, + }, + assertErr: func(t *testing.T, err error, a ...any) { + require.ErrorContains(t, err, "target_version\n\tversion \"2-3-4\" is not a valid semantic version") + }, + }, + { + name: "invalid autoupdate mode", + spec: &autoupdate.AutoUpdateAgentRolloutSpec{ + StartVersion: "1.2.3", + TargetVersion: "2.3.4-dev", + Schedule: AgentsScheduleRegular, + AutoupdateMode: "invalid-mode", + Strategy: AgentsStrategyHaltOnError, + }, + assertErr: func(t *testing.T, err error, a ...any) { + require.ErrorContains(t, err, "unsupported agents mode: \"invalid-mode\"") + }, + }, + { + name: "invalid schedule name", + spec: &autoupdate.AutoUpdateAgentRolloutSpec{ + StartVersion: "1.2.3", + TargetVersion: "2.3.4-dev", + Schedule: "invalid-schedule", + AutoupdateMode: AgentsUpdateModeEnabled, + Strategy: AgentsStrategyHaltOnError, + }, + assertErr: func(t *testing.T, err error, a ...any) { + require.ErrorContains(t, err, "unsupported schedule type: \"invalid-schedule\"") + }, + }, + { + name: "invalid strategy", + spec: &autoupdate.AutoUpdateAgentRolloutSpec{ + StartVersion: "1.2.3", + TargetVersion: "2.3.4-dev", + Schedule: AgentsScheduleRegular, + AutoupdateMode: AgentsUpdateModeEnabled, + Strategy: "invalid-strategy", + }, + assertErr: func(t *testing.T, err error, a ...any) { + require.ErrorContains(t, err, "unsupported agents strategy: \"invalid-strategy\"") + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := NewAutoUpdateAgentRollout(tt.spec) + tt.assertErr(t, err) + require.Empty(t, cmp.Diff(got, tt.want, protocmp.Transform())) + }) + } +} diff --git a/api/types/autoupdate/utils.go b/api/types/autoupdate/utils.go new file mode 100644 index 0000000000000..4772ff8a94411 --- /dev/null +++ b/api/types/autoupdate/utils.go @@ -0,0 +1,68 @@ +/* +Copyright 2024 Gravitational, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package autoupdate + +import ( + "github.com/coreos/go-semver/semver" + "github.com/gravitational/trace" +) + +func checkVersion(version string) error { + if version == "" { + return trace.BadParameter("version is unset") + } + if _, err := semver.NewVersion(version); err != nil { + return trace.BadParameter("version %q is not a valid semantic version", version) + } + return nil +} + +func checkAgentsMode(mode string) error { + switch mode { + case AgentsUpdateModeEnabled, AgentsUpdateModeDisabled, AgentsUpdateModeSuspended: + return nil + default: + return trace.BadParameter("unsupported agents mode: %q", mode) + } +} + +func checkToolsMode(mode string) error { + switch mode { + case ToolsUpdateModeEnabled, ToolsUpdateModeDisabled: + return nil + default: + return trace.BadParameter("unsupported tools mode: %q", mode) + } +} + +func checkScheduleName(schedule string) error { + switch schedule { + case AgentsScheduleRegular, AgentsScheduleImmediate: + return nil + default: + return trace.BadParameter("unsupported schedule type: %q", schedule) + } +} + +func checkAgentsStrategy(strategy string) error { + switch strategy { + case AgentsStrategyHaltOnError, AgentsStrategyTimeBased: + return nil + default: + return trace.BadParameter("unsupported agents strategy: %q", strategy) + } +} diff --git a/api/types/autoupdate/version.go b/api/types/autoupdate/version.go index ad2d12f265949..4bfe14c53fc1f 100644 --- a/api/types/autoupdate/version.go +++ b/api/types/autoupdate/version.go @@ -1,25 +1,22 @@ /* - * Teleport - * Copyright (C) 2024 Gravitational, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ +Copyright 2024 Gravitational, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ package autoupdate import ( - "github.com/coreos/go-semver/semver" "github.com/gravitational/trace" "github.com/gravitational/teleport/api/gen/proto/go/teleport/autoupdate/v1" @@ -61,11 +58,22 @@ func ValidateAutoUpdateVersion(v *autoupdate.AutoUpdateVersion) error { } if v.Spec.Tools != nil { - if v.Spec.Tools.TargetVersion == "" { - return trace.BadParameter("TargetVersion is unset") + if err := checkVersion(v.Spec.Tools.TargetVersion); err != nil { + return trace.Wrap(err, "validating spec.tools.target_version") + } + } + if v.Spec.Agents != nil { + if err := checkVersion(v.Spec.Agents.StartVersion); err != nil { + return trace.Wrap(err, "validating spec.agents.start_version") + } + if err := checkVersion(v.Spec.Agents.TargetVersion); err != nil { + return trace.Wrap(err, "validating spec.agents.target_version") + } + if err := checkAgentsMode(v.Spec.Agents.Mode); err != nil { + return trace.Wrap(err, "validating spec.agents.mode") } - if _, err := semver.NewVersion(v.Spec.Tools.TargetVersion); err != nil { - return trace.BadParameter("TargetVersion is not a valid semantic version") + if err := checkScheduleName(v.Spec.Agents.Schedule); err != nil { + return trace.Wrap(err, "validating spec.agents.schedule") } } diff --git a/api/types/autoupdate/version_test.go b/api/types/autoupdate/version_test.go index 70790a204b219..a59a4f6fe6c22 100644 --- a/api/types/autoupdate/version_test.go +++ b/api/types/autoupdate/version_test.go @@ -1,20 +1,18 @@ /* - * Teleport - * Copyright (C) 2024 Gravitational, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ +Copyright 2024 Gravitational, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ package autoupdate @@ -69,7 +67,7 @@ func TestNewAutoUpdateVersion(t *testing.T) { }, }, assertErr: func(t *testing.T, err error, a ...any) { - require.ErrorContains(t, err, "TargetVersion is unset") + require.ErrorContains(t, err, "target_version\n\tversion is unset") }, }, { @@ -80,7 +78,7 @@ func TestNewAutoUpdateVersion(t *testing.T) { }, }, assertErr: func(t *testing.T, err error, a ...any) { - require.ErrorContains(t, err, "TargetVersion is not a valid semantic version") + require.ErrorContains(t, err, "target_version\n\tversion \"17-0-0\" is not a valid semantic version") }, }, { @@ -90,6 +88,91 @@ func TestNewAutoUpdateVersion(t *testing.T) { require.ErrorContains(t, err, "Spec is nil") }, }, + { + name: "success agents autoupdate version", + spec: &autoupdate.AutoUpdateVersionSpec{ + Agents: &autoupdate.AutoUpdateVersionSpecAgents{ + StartVersion: "1.2.3-dev.1", + TargetVersion: "1.2.3-dev.2", + Schedule: AgentsScheduleRegular, + Mode: AgentsUpdateModeEnabled, + }, + }, + assertErr: func(t *testing.T, err error, a ...any) { + require.NoError(t, err) + }, + want: &autoupdate.AutoUpdateVersion{ + Kind: types.KindAutoUpdateVersion, + Version: types.V1, + Metadata: &headerv1.Metadata{ + Name: types.MetaNameAutoUpdateVersion, + }, + Spec: &autoupdate.AutoUpdateVersionSpec{ + Agents: &autoupdate.AutoUpdateVersionSpecAgents{ + StartVersion: "1.2.3-dev.1", + TargetVersion: "1.2.3-dev.2", + Schedule: AgentsScheduleRegular, + Mode: AgentsUpdateModeEnabled, + }, + }, + }, + }, + { + name: "invalid empty agents start version", + spec: &autoupdate.AutoUpdateVersionSpec{ + Agents: &autoupdate.AutoUpdateVersionSpecAgents{ + StartVersion: "", + TargetVersion: "1.2.3", + Mode: AgentsUpdateModeEnabled, + Schedule: AgentsScheduleRegular, + }, + }, + assertErr: func(t *testing.T, err error, a ...any) { + require.ErrorContains(t, err, "start_version\n\tversion is unset") + }, + }, + { + name: "invalid empty agents target version", + spec: &autoupdate.AutoUpdateVersionSpec{ + Agents: &autoupdate.AutoUpdateVersionSpecAgents{ + StartVersion: "1.2.3-dev", + TargetVersion: "", + Mode: AgentsUpdateModeEnabled, + Schedule: AgentsScheduleRegular, + }, + }, + assertErr: func(t *testing.T, err error, a ...any) { + require.ErrorContains(t, err, "target_version\n\tversion is unset") + }, + }, + { + name: "invalid semantic agents start version", + spec: &autoupdate.AutoUpdateVersionSpec{ + Agents: &autoupdate.AutoUpdateVersionSpecAgents{ + StartVersion: "17-0-0", + TargetVersion: "1.2.3", + Mode: AgentsUpdateModeEnabled, + Schedule: AgentsScheduleRegular, + }, + }, + assertErr: func(t *testing.T, err error, a ...any) { + require.ErrorContains(t, err, "start_version\n\tversion \"17-0-0\" is not a valid semantic version") + }, + }, + { + name: "invalid semantic agents target version", + spec: &autoupdate.AutoUpdateVersionSpec{ + Agents: &autoupdate.AutoUpdateVersionSpecAgents{ + StartVersion: "1.2.3", + TargetVersion: "17-0-0", + Mode: AgentsUpdateModeEnabled, + Schedule: AgentsScheduleRegular, + }, + }, + assertErr: func(t *testing.T, err error, a ...any) { + require.ErrorContains(t, err, "target_version\n\tversion \"17-0-0\" is not a valid semantic version") + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/api/types/constants.go b/api/types/constants.go index 87c0335586bf6..b50b91c480aad 100644 --- a/api/types/constants.go +++ b/api/types/constants.go @@ -331,12 +331,18 @@ const ( // KindAutoUpdateVersion is the resource with autoupdate versions. KindAutoUpdateVersion = "autoupdate_version" + // KindAutoUpdateAgentRollout is the resource that controls and tracks agent rollouts. + KindAutoUpdateAgentRollout = "autoupdate_agent_rollout" + // MetaNameAutoUpdateConfig is the name of a configuration resource for autoupdate config. MetaNameAutoUpdateConfig = "autoupdate-config" // MetaNameAutoUpdateVersion is the name of a resource for autoupdate version. MetaNameAutoUpdateVersion = "autoupdate-version" + // MetaNameAutoUpdateAgentRollout is the name of the autoupdate agent rollout resource. + MetaNameAutoUpdateAgentRollout = "autoupdate-agent-rollout" + // KindClusterAuditConfig is the resource that holds cluster audit configuration. KindClusterAuditConfig = "cluster_audit_config" diff --git a/api/utils/keys/cliprompt.go b/api/utils/keys/cliprompt.go index 8ac27790efe41..7dce20d211a7c 100644 --- a/api/utils/keys/cliprompt.go +++ b/api/utils/keys/cliprompt.go @@ -29,7 +29,11 @@ import ( type cliPrompt struct{} -func (c *cliPrompt) AskPIN(ctx context.Context, message string) (string, error) { +func (c *cliPrompt) AskPIN(ctx context.Context, requirement PINPromptRequirement) (string, error) { + message := "Enter your YubiKey PIV PIN" + if requirement == PINOptional { + message = "Enter your YubiKey PIV PIN [blank to use default PIN]" + } password, err := prompt.Password(ctx, os.Stderr, prompt.Stdin(), message) return password, trace.Wrap(err) } diff --git a/api/utils/keys/yubikey.go b/api/utils/keys/yubikey.go index 790d9a2a626b4..15e12bfc7e3f6 100644 --- a/api/utils/keys/yubikey.go +++ b/api/utils/keys/yubikey.go @@ -374,7 +374,7 @@ func (y *YubiKeyPrivateKey) sign(ctx context.Context, rand io.Reader, digest []b defer touchPromptDelayTimer.Reset(signTouchPromptDelay) } } - pass, err := y.prompt.AskPIN(ctx, "Enter your YubiKey PIV PIN") + pass, err := y.prompt.AskPIN(ctx, PINRequired) return pass, trace.Wrap(err) } @@ -666,7 +666,7 @@ func (y *YubiKey) SetPIN(oldPin, newPin string) error { // If the user provides the default PIN, they will be prompted to set a // non-default PIN and PUK before continuing. func (y *YubiKey) checkOrSetPIN(ctx context.Context) error { - pin, err := y.prompt.AskPIN(ctx, "Enter your YubiKey PIV PIN [blank to use default PIN]") + pin, err := y.prompt.AskPIN(ctx, PINOptional) if err != nil { return trace.Wrap(err) } diff --git a/api/utils/keys/yubikey_common.go b/api/utils/keys/yubikey_common.go index 78ffd1f86c918..5ed36f814580d 100644 --- a/api/utils/keys/yubikey_common.go +++ b/api/utils/keys/yubikey_common.go @@ -22,7 +22,8 @@ import ( // HardwareKeyPrompt provides methods to interact with a YubiKey hardware key. type HardwareKeyPrompt interface { // AskPIN prompts the user for a PIN. - AskPIN(ctx context.Context, message string) (string, error) + // The requirement tells if the PIN is required or optional. + AskPIN(ctx context.Context, requirement PINPromptRequirement) (string, error) // Touch prompts the user to touch the hardware key. Touch(ctx context.Context) error // ChangePIN asks for a new PIN. @@ -35,6 +36,16 @@ type HardwareKeyPrompt interface { ConfirmSlotOverwrite(ctx context.Context, message string) (bool, error) } +// PINPromptRequirement specifies whether a PIN is required. +type PINPromptRequirement int + +const ( + // PINOptional allows the user to proceed without entering a PIN. + PINOptional PINPromptRequirement = iota + // PINRequired enforces that a PIN must be entered to proceed. + PINRequired +) + // PINAndPUK describes a response returned from HardwareKeyPrompt.ChangePIN. type PINAndPUK struct { // New PIN set by the user. diff --git a/e_imports.go b/e_imports.go index a6b1fc2125622..8e6190cab8917 100644 --- a/e_imports.go +++ b/e_imports.go @@ -57,7 +57,10 @@ import ( _ "github.com/aws/aws-sdk-go-v2/service/athena" _ "github.com/aws/aws-sdk-go-v2/service/athena/types" _ "github.com/aws/aws-sdk-go-v2/service/glue" + _ "github.com/aws/aws-sdk-go-v2/service/identitystore" + _ "github.com/aws/aws-sdk-go-v2/service/organizations" _ "github.com/aws/aws-sdk-go-v2/service/s3" + _ "github.com/aws/aws-sdk-go-v2/service/ssoadmin" _ "github.com/aws/aws-sdk-go-v2/service/sts" _ "github.com/aws/aws-sdk-go-v2/service/sts/types" _ "github.com/beevik/etree" diff --git a/gen/proto/go/teleport/lib/teleterm/v1/tshd_events_service.pb.go b/gen/proto/go/teleport/lib/teleterm/v1/tshd_events_service.pb.go index 4056f12e2433d..d9d0ce6c4cf5b 100644 --- a/gen/proto/go/teleport/lib/teleterm/v1/tshd_events_service.pb.go +++ b/gen/proto/go/teleport/lib/teleterm/v1/tshd_events_service.pb.go @@ -742,6 +742,405 @@ func (x *PromptMFAResponse) GetTotpCode() string { return "" } +// Request for PromptHardwareKeyPIN. +type PromptHardwareKeyPINRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RootClusterUri string `protobuf:"bytes,1,opt,name=root_cluster_uri,json=rootClusterUri,proto3" json:"root_cluster_uri,omitempty"` + // Specifies if a PIN is optional, allowing the user to set it up if left empty. + PinOptional bool `protobuf:"varint,2,opt,name=pin_optional,json=pinOptional,proto3" json:"pin_optional,omitempty"` +} + +func (x *PromptHardwareKeyPINRequest) Reset() { + *x = PromptHardwareKeyPINRequest{} + mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PromptHardwareKeyPINRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PromptHardwareKeyPINRequest) ProtoMessage() {} + +func (x *PromptHardwareKeyPINRequest) ProtoReflect() protoreflect.Message { + mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PromptHardwareKeyPINRequest.ProtoReflect.Descriptor instead. +func (*PromptHardwareKeyPINRequest) Descriptor() ([]byte, []int) { + return file_teleport_lib_teleterm_v1_tshd_events_service_proto_rawDescGZIP(), []int{12} +} + +func (x *PromptHardwareKeyPINRequest) GetRootClusterUri() string { + if x != nil { + return x.RootClusterUri + } + return "" +} + +func (x *PromptHardwareKeyPINRequest) GetPinOptional() bool { + if x != nil { + return x.PinOptional + } + return false +} + +// Response for PromptHardwareKeyPIN. +type PromptHardwareKeyPINResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // pin as inputted by the user in the Electron app. + Pin string `protobuf:"bytes,1,opt,name=pin,proto3" json:"pin,omitempty"` +} + +func (x *PromptHardwareKeyPINResponse) Reset() { + *x = PromptHardwareKeyPINResponse{} + mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PromptHardwareKeyPINResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PromptHardwareKeyPINResponse) ProtoMessage() {} + +func (x *PromptHardwareKeyPINResponse) ProtoReflect() protoreflect.Message { + mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[13] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PromptHardwareKeyPINResponse.ProtoReflect.Descriptor instead. +func (*PromptHardwareKeyPINResponse) Descriptor() ([]byte, []int) { + return file_teleport_lib_teleterm_v1_tshd_events_service_proto_rawDescGZIP(), []int{13} +} + +func (x *PromptHardwareKeyPINResponse) GetPin() string { + if x != nil { + return x.Pin + } + return "" +} + +// Request for PromptHardwareKeyTouchRequest. +type PromptHardwareKeyTouchRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RootClusterUri string `protobuf:"bytes,1,opt,name=root_cluster_uri,json=rootClusterUri,proto3" json:"root_cluster_uri,omitempty"` +} + +func (x *PromptHardwareKeyTouchRequest) Reset() { + *x = PromptHardwareKeyTouchRequest{} + mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PromptHardwareKeyTouchRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PromptHardwareKeyTouchRequest) ProtoMessage() {} + +func (x *PromptHardwareKeyTouchRequest) ProtoReflect() protoreflect.Message { + mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[14] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PromptHardwareKeyTouchRequest.ProtoReflect.Descriptor instead. +func (*PromptHardwareKeyTouchRequest) Descriptor() ([]byte, []int) { + return file_teleport_lib_teleterm_v1_tshd_events_service_proto_rawDescGZIP(), []int{14} +} + +func (x *PromptHardwareKeyTouchRequest) GetRootClusterUri() string { + if x != nil { + return x.RootClusterUri + } + return "" +} + +// Response for PromptHardwareKeyTouch. +type PromptHardwareKeyTouchResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *PromptHardwareKeyTouchResponse) Reset() { + *x = PromptHardwareKeyTouchResponse{} + mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PromptHardwareKeyTouchResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PromptHardwareKeyTouchResponse) ProtoMessage() {} + +func (x *PromptHardwareKeyTouchResponse) ProtoReflect() protoreflect.Message { + mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[15] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PromptHardwareKeyTouchResponse.ProtoReflect.Descriptor instead. +func (*PromptHardwareKeyTouchResponse) Descriptor() ([]byte, []int) { + return file_teleport_lib_teleterm_v1_tshd_events_service_proto_rawDescGZIP(), []int{15} +} + +// Response for PromptHardwareKeyPINChange. +type PromptHardwareKeyPINChangeRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RootClusterUri string `protobuf:"bytes,1,opt,name=root_cluster_uri,json=rootClusterUri,proto3" json:"root_cluster_uri,omitempty"` +} + +func (x *PromptHardwareKeyPINChangeRequest) Reset() { + *x = PromptHardwareKeyPINChangeRequest{} + mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PromptHardwareKeyPINChangeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PromptHardwareKeyPINChangeRequest) ProtoMessage() {} + +func (x *PromptHardwareKeyPINChangeRequest) ProtoReflect() protoreflect.Message { + mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[16] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PromptHardwareKeyPINChangeRequest.ProtoReflect.Descriptor instead. +func (*PromptHardwareKeyPINChangeRequest) Descriptor() ([]byte, []int) { + return file_teleport_lib_teleterm_v1_tshd_events_service_proto_rawDescGZIP(), []int{16} +} + +func (x *PromptHardwareKeyPINChangeRequest) GetRootClusterUri() string { + if x != nil { + return x.RootClusterUri + } + return "" +} + +// Response for PromptHardwareKeyPINChange. +type PromptHardwareKeyPINChangeResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // New pin set by the user. + Pin string `protobuf:"bytes,1,opt,name=pin,proto3" json:"pin,omitempty"` + // PUK is needed to change the PIN. + // This is a new PUK if it has not been changed from the default PUK. + Puk string `protobuf:"bytes,2,opt,name=puk,proto3" json:"puk,omitempty"` + // puk_changed is true if the user changed the default PUK. + PukChanged bool `protobuf:"varint,3,opt,name=puk_changed,json=pukChanged,proto3" json:"puk_changed,omitempty"` +} + +func (x *PromptHardwareKeyPINChangeResponse) Reset() { + *x = PromptHardwareKeyPINChangeResponse{} + mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PromptHardwareKeyPINChangeResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PromptHardwareKeyPINChangeResponse) ProtoMessage() {} + +func (x *PromptHardwareKeyPINChangeResponse) ProtoReflect() protoreflect.Message { + mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[17] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PromptHardwareKeyPINChangeResponse.ProtoReflect.Descriptor instead. +func (*PromptHardwareKeyPINChangeResponse) Descriptor() ([]byte, []int) { + return file_teleport_lib_teleterm_v1_tshd_events_service_proto_rawDescGZIP(), []int{17} +} + +func (x *PromptHardwareKeyPINChangeResponse) GetPin() string { + if x != nil { + return x.Pin + } + return "" +} + +func (x *PromptHardwareKeyPINChangeResponse) GetPuk() string { + if x != nil { + return x.Puk + } + return "" +} + +func (x *PromptHardwareKeyPINChangeResponse) GetPukChanged() bool { + if x != nil { + return x.PukChanged + } + return false +} + +// Request for ConfirmHardwareKeySlotOverwrite. +type ConfirmHardwareKeySlotOverwriteRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RootClusterUri string `protobuf:"bytes,1,opt,name=root_cluster_uri,json=rootClusterUri,proto3" json:"root_cluster_uri,omitempty"` + // Message to display in the prompt. + Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` +} + +func (x *ConfirmHardwareKeySlotOverwriteRequest) Reset() { + *x = ConfirmHardwareKeySlotOverwriteRequest{} + mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ConfirmHardwareKeySlotOverwriteRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ConfirmHardwareKeySlotOverwriteRequest) ProtoMessage() {} + +func (x *ConfirmHardwareKeySlotOverwriteRequest) ProtoReflect() protoreflect.Message { + mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[18] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ConfirmHardwareKeySlotOverwriteRequest.ProtoReflect.Descriptor instead. +func (*ConfirmHardwareKeySlotOverwriteRequest) Descriptor() ([]byte, []int) { + return file_teleport_lib_teleterm_v1_tshd_events_service_proto_rawDescGZIP(), []int{18} +} + +func (x *ConfirmHardwareKeySlotOverwriteRequest) GetRootClusterUri() string { + if x != nil { + return x.RootClusterUri + } + return "" +} + +func (x *ConfirmHardwareKeySlotOverwriteRequest) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +// Response for ConfirmHardwareKeySlotOverwrite. +type ConfirmHardwareKeySlotOverwriteResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // If true, the slot will be overridden. + Confirmed bool `protobuf:"varint,1,opt,name=confirmed,proto3" json:"confirmed,omitempty"` +} + +func (x *ConfirmHardwareKeySlotOverwriteResponse) Reset() { + *x = ConfirmHardwareKeySlotOverwriteResponse{} + mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ConfirmHardwareKeySlotOverwriteResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ConfirmHardwareKeySlotOverwriteResponse) ProtoMessage() {} + +func (x *ConfirmHardwareKeySlotOverwriteResponse) ProtoReflect() protoreflect.Message { + mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[19] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ConfirmHardwareKeySlotOverwriteResponse.ProtoReflect.Descriptor instead. +func (*ConfirmHardwareKeySlotOverwriteResponse) Descriptor() ([]byte, []int) { + return file_teleport_lib_teleterm_v1_tshd_events_service_proto_rawDescGZIP(), []int{19} +} + +func (x *ConfirmHardwareKeySlotOverwriteResponse) GetConfirmed() bool { + if x != nil { + return x.Confirmed + } + return false +} + // Request for GetUsageReportingSettings. type GetUsageReportingSettingsRequest struct { state protoimpl.MessageState @@ -751,7 +1150,7 @@ type GetUsageReportingSettingsRequest struct { func (x *GetUsageReportingSettingsRequest) Reset() { *x = GetUsageReportingSettingsRequest{} - mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[12] + mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -763,7 +1162,7 @@ func (x *GetUsageReportingSettingsRequest) String() string { func (*GetUsageReportingSettingsRequest) ProtoMessage() {} func (x *GetUsageReportingSettingsRequest) ProtoReflect() protoreflect.Message { - mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[12] + mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[20] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -776,7 +1175,7 @@ func (x *GetUsageReportingSettingsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetUsageReportingSettingsRequest.ProtoReflect.Descriptor instead. func (*GetUsageReportingSettingsRequest) Descriptor() ([]byte, []int) { - return file_teleport_lib_teleterm_v1_tshd_events_service_proto_rawDescGZIP(), []int{12} + return file_teleport_lib_teleterm_v1_tshd_events_service_proto_rawDescGZIP(), []int{20} } // Response for GetUsageReportingSettings. @@ -790,7 +1189,7 @@ type GetUsageReportingSettingsResponse struct { func (x *GetUsageReportingSettingsResponse) Reset() { *x = GetUsageReportingSettingsResponse{} - mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[13] + mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -802,7 +1201,7 @@ func (x *GetUsageReportingSettingsResponse) String() string { func (*GetUsageReportingSettingsResponse) ProtoMessage() {} func (x *GetUsageReportingSettingsResponse) ProtoReflect() protoreflect.Message { - mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[13] + mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[21] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -815,7 +1214,7 @@ func (x *GetUsageReportingSettingsResponse) ProtoReflect() protoreflect.Message // Deprecated: Use GetUsageReportingSettingsResponse.ProtoReflect.Descriptor instead. func (*GetUsageReportingSettingsResponse) Descriptor() ([]byte, []int) { - return file_teleport_lib_teleterm_v1_tshd_events_service_proto_rawDescGZIP(), []int{13} + return file_teleport_lib_teleterm_v1_tshd_events_service_proto_rawDescGZIP(), []int{21} } func (x *GetUsageReportingSettingsResponse) GetUsageReportingSettings() *UsageReportingSettings { @@ -837,7 +1236,7 @@ type UsageReportingSettings struct { func (x *UsageReportingSettings) Reset() { *x = UsageReportingSettings{} - mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[14] + mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -849,7 +1248,7 @@ func (x *UsageReportingSettings) String() string { func (*UsageReportingSettings) ProtoMessage() {} func (x *UsageReportingSettings) ProtoReflect() protoreflect.Message { - mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[14] + mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[22] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -862,7 +1261,7 @@ func (x *UsageReportingSettings) ProtoReflect() protoreflect.Message { // Deprecated: Use UsageReportingSettings.ProtoReflect.Descriptor instead. func (*UsageReportingSettings) Descriptor() ([]byte, []int) { - return file_teleport_lib_teleterm_v1_tshd_events_service_proto_rawDescGZIP(), []int{14} + return file_teleport_lib_teleterm_v1_tshd_events_service_proto_rawDescGZIP(), []int{22} } func (x *UsageReportingSettings) GetEnabled() bool { @@ -885,7 +1284,7 @@ type ReportUnexpectedVnetShutdownRequest struct { func (x *ReportUnexpectedVnetShutdownRequest) Reset() { *x = ReportUnexpectedVnetShutdownRequest{} - mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[15] + mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -897,7 +1296,7 @@ func (x *ReportUnexpectedVnetShutdownRequest) String() string { func (*ReportUnexpectedVnetShutdownRequest) ProtoMessage() {} func (x *ReportUnexpectedVnetShutdownRequest) ProtoReflect() protoreflect.Message { - mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[15] + mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[23] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -910,7 +1309,7 @@ func (x *ReportUnexpectedVnetShutdownRequest) ProtoReflect() protoreflect.Messag // Deprecated: Use ReportUnexpectedVnetShutdownRequest.ProtoReflect.Descriptor instead. func (*ReportUnexpectedVnetShutdownRequest) Descriptor() ([]byte, []int) { - return file_teleport_lib_teleterm_v1_tshd_events_service_proto_rawDescGZIP(), []int{15} + return file_teleport_lib_teleterm_v1_tshd_events_service_proto_rawDescGZIP(), []int{23} } func (x *ReportUnexpectedVnetShutdownRequest) GetError() string { @@ -929,7 +1328,7 @@ type ReportUnexpectedVnetShutdownResponse struct { func (x *ReportUnexpectedVnetShutdownResponse) Reset() { *x = ReportUnexpectedVnetShutdownResponse{} - mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[16] + mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -941,7 +1340,7 @@ func (x *ReportUnexpectedVnetShutdownResponse) String() string { func (*ReportUnexpectedVnetShutdownResponse) ProtoMessage() {} func (x *ReportUnexpectedVnetShutdownResponse) ProtoReflect() protoreflect.Message { - mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[16] + mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[24] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -954,7 +1353,7 @@ func (x *ReportUnexpectedVnetShutdownResponse) ProtoReflect() protoreflect.Messa // Deprecated: Use ReportUnexpectedVnetShutdownResponse.ProtoReflect.Descriptor instead. func (*ReportUnexpectedVnetShutdownResponse) Descriptor() ([]byte, []int) { - return file_teleport_lib_teleterm_v1_tshd_events_service_proto_rawDescGZIP(), []int{16} + return file_teleport_lib_teleterm_v1_tshd_events_service_proto_rawDescGZIP(), []int{24} } var File_teleport_lib_teleterm_v1_tshd_events_service_proto protoreflect.FileDescriptor @@ -1056,85 +1455,163 @@ var file_teleport_lib_teleterm_v1_tshd_events_service_proto_rawDesc = []byte{ 0x5f, 0x75, 0x72, 0x69, 0x22, 0x30, 0x0a, 0x11, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x4d, 0x46, 0x41, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x6f, 0x74, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x6f, - 0x74, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x22, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x55, 0x73, 0x61, - 0x67, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, - 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x8f, 0x01, 0x0a, 0x21, 0x47, - 0x65, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, - 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x6a, 0x0a, 0x18, 0x75, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, - 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, - 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, + 0x74, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x6a, 0x0a, 0x1b, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, + 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x50, 0x49, 0x4e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x63, 0x6c, + 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0e, 0x72, 0x6f, 0x6f, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x55, 0x72, 0x69, 0x12, + 0x21, 0x0a, 0x0c, 0x70, 0x69, 0x6e, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x70, 0x69, 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x61, 0x6c, 0x22, 0x30, 0x0a, 0x1c, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x48, 0x61, 0x72, 0x64, + 0x77, 0x61, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x50, 0x49, 0x4e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x70, 0x69, 0x6e, 0x22, 0x49, 0x0a, 0x1d, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x48, 0x61, + 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x54, 0x6f, 0x75, 0x63, 0x68, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x63, 0x6c, + 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0e, 0x72, 0x6f, 0x6f, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x55, 0x72, 0x69, 0x22, + 0x20, 0x0a, 0x1e, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, + 0x65, 0x4b, 0x65, 0x79, 0x54, 0x6f, 0x75, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x4d, 0x0a, 0x21, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x48, 0x61, 0x72, 0x64, 0x77, + 0x61, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x50, 0x49, 0x4e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x63, + 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0e, 0x72, 0x6f, 0x6f, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x55, 0x72, 0x69, + 0x22, 0x69, 0x0a, 0x22, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, + 0x72, 0x65, 0x4b, 0x65, 0x79, 0x50, 0x49, 0x4e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x6e, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x70, 0x69, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x75, 0x6b, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x70, 0x75, 0x6b, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x75, + 0x6b, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0a, 0x70, 0x75, 0x6b, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x22, 0x6c, 0x0a, 0x26, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x4b, 0x65, + 0x79, 0x53, 0x6c, 0x6f, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x77, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x63, 0x6c, + 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0e, 0x72, 0x6f, 0x6f, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x55, 0x72, 0x69, 0x12, + 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x47, 0x0a, 0x27, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x72, 0x6d, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x53, + 0x6c, 0x6f, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x77, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, + 0x65, 0x64, 0x22, 0x22, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x8f, 0x01, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, - 0x69, 0x6e, 0x67, 0x73, 0x52, 0x16, 0x75, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, - 0x74, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x32, 0x0a, 0x16, - 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x65, - 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, - 0x22, 0x3b, 0x0a, 0x23, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x55, 0x6e, 0x65, 0x78, 0x70, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x56, 0x6e, 0x65, 0x74, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x26, 0x0a, - 0x24, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x55, 0x6e, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x56, 0x6e, 0x65, 0x74, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xba, 0x06, 0x0a, 0x11, 0x54, 0x73, 0x68, 0x64, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5e, 0x0a, 0x07, 0x52, - 0x65, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x28, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, - 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, - 0x31, 0x2e, 0x52, 0x65, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x29, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, - 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6c, 0x6f, - 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x79, 0x0a, 0x10, 0x53, - 0x65, 0x6e, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x31, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4e, - 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, - 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, - 0x6e, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xac, 0x01, 0x0a, 0x21, 0x53, 0x65, 0x6e, 0x64, 0x50, - 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, - 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x42, 0x2e, 0x74, + 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6a, 0x0a, 0x18, + 0x75, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x5f, + 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, + 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, + 0x52, 0x16, 0x75, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, + 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x32, 0x0a, 0x16, 0x55, 0x73, 0x61, 0x67, + 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, + 0x67, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x3b, 0x0a, 0x23, + 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x55, 0x6e, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x56, 0x6e, 0x65, 0x74, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x26, 0x0a, 0x24, 0x52, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x55, 0x6e, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x56, 0x6e, 0x65, + 0x74, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x32, 0x93, 0x0b, 0x0a, 0x11, 0x54, 0x73, 0x68, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5e, 0x0a, 0x07, 0x52, 0x65, 0x6c, 0x6f, 0x67, + 0x69, 0x6e, 0x12, 0x28, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, + 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, + 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x74, + 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x79, 0x0a, 0x10, 0x53, 0x65, 0x6e, 0x64, 0x4e, + 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x31, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, + 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4e, 0x6f, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0xac, 0x01, 0x0a, 0x21, 0x53, 0x65, 0x6e, 0x64, 0x50, 0x65, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, + 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x42, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, + 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, + 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x43, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, - 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x43, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, - 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x6e, 0x64, - 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x41, - 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x64, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x4d, - 0x46, 0x41, 0x12, 0x2a, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, - 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, - 0x6f, 0x6d, 0x70, 0x74, 0x4d, 0x46, 0x41, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, + 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x64, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x4d, 0x46, 0x41, 0x12, 0x2a, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, - 0x4d, 0x46, 0x41, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x94, 0x01, 0x0a, 0x19, - 0x47, 0x65, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, - 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3a, 0x2e, 0x74, 0x65, 0x6c, 0x65, + 0x4d, 0x46, 0x41, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x74, 0x65, 0x6c, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x4d, 0x46, 0x41, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x85, 0x01, 0x0a, 0x14, 0x50, 0x72, 0x6f, 0x6d, + 0x70, 0x74, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x50, 0x49, 0x4e, + 0x12, 0x35, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, + 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x6d, + 0x70, 0x74, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x50, 0x49, 0x4e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, + 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, + 0x65, 0x4b, 0x65, 0x79, 0x50, 0x49, 0x4e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x8b, 0x01, 0x0a, 0x16, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, + 0x72, 0x65, 0x4b, 0x65, 0x79, 0x54, 0x6f, 0x75, 0x63, 0x68, 0x12, 0x37, 0x2e, 0x74, 0x65, 0x6c, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x48, 0x61, 0x72, 0x64, + 0x77, 0x61, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x54, 0x6f, 0x75, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x38, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, + 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x50, + 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x4b, 0x65, 0x79, + 0x54, 0x6f, 0x75, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x97, 0x01, + 0x0a, 0x1a, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, + 0x4b, 0x65, 0x79, 0x50, 0x49, 0x4e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x3b, 0x2e, 0x74, + 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x48, 0x61, + 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x50, 0x49, 0x4e, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, - 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x70, - 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3b, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, - 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, - 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, - 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x9d, 0x01, 0x0a, 0x1c, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x55, 0x6e, 0x65, - 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x56, 0x6e, 0x65, 0x74, 0x53, 0x68, 0x75, 0x74, 0x64, - 0x6f, 0x77, 0x6e, 0x12, 0x3d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, - 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, - 0x65, 0x70, 0x6f, 0x72, 0x74, 0x55, 0x6e, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x56, - 0x6e, 0x65, 0x74, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x3e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, - 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, - 0x70, 0x6f, 0x72, 0x74, 0x55, 0x6e, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x56, 0x6e, - 0x65, 0x74, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x42, 0x54, 0x5a, 0x52, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, - 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, - 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x6c, 0x69, - 0x62, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2f, 0x76, 0x31, 0x3b, 0x74, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x48, 0x61, 0x72, 0x64, 0x77, + 0x61, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x50, 0x49, 0x4e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xa6, 0x01, 0x0a, 0x1f, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x72, 0x6d, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x53, 0x6c, + 0x6f, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x77, 0x72, 0x69, 0x74, 0x65, 0x12, 0x40, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x48, 0x61, + 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x53, 0x6c, 0x6f, 0x74, 0x4f, 0x76, 0x65, + 0x72, 0x77, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x41, 0x2e, + 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, + 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x53, 0x6c, 0x6f, 0x74, 0x4f, + 0x76, 0x65, 0x72, 0x77, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x94, 0x01, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3a, + 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x61, + 0x67, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, + 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3b, 0x2e, 0x74, 0x65, 0x6c, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x9d, 0x01, 0x0a, 0x1c, 0x52, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x55, 0x6e, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x56, 0x6e, 0x65, 0x74, + 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x12, 0x3d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, + 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x55, 0x6e, 0x65, 0x78, 0x70, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x56, 0x6e, 0x65, 0x74, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, + 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x55, 0x6e, 0x65, 0x78, 0x70, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x56, 0x6e, 0x65, 0x74, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x54, 0x5a, 0x52, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x67, 0x65, 0x6e, + 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2f, + 0x76, 0x31, 0x3b, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x76, 0x31, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1149,7 +1626,7 @@ func file_teleport_lib_teleterm_v1_tshd_events_service_proto_rawDescGZIP() []byt return file_teleport_lib_teleterm_v1_tshd_events_service_proto_rawDescData } -var file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes = make([]protoimpl.MessageInfo, 17) +var file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes = make([]protoimpl.MessageInfo, 25) var file_teleport_lib_teleterm_v1_tshd_events_service_proto_goTypes = []any{ (*ReloginRequest)(nil), // 0: teleport.lib.teleterm.v1.ReloginRequest (*GatewayCertExpired)(nil), // 1: teleport.lib.teleterm.v1.GatewayCertExpired @@ -1163,32 +1640,48 @@ var file_teleport_lib_teleterm_v1_tshd_events_service_proto_goTypes = []any{ (*SendPendingHeadlessAuthenticationResponse)(nil), // 9: teleport.lib.teleterm.v1.SendPendingHeadlessAuthenticationResponse (*PromptMFARequest)(nil), // 10: teleport.lib.teleterm.v1.PromptMFARequest (*PromptMFAResponse)(nil), // 11: teleport.lib.teleterm.v1.PromptMFAResponse - (*GetUsageReportingSettingsRequest)(nil), // 12: teleport.lib.teleterm.v1.GetUsageReportingSettingsRequest - (*GetUsageReportingSettingsResponse)(nil), // 13: teleport.lib.teleterm.v1.GetUsageReportingSettingsResponse - (*UsageReportingSettings)(nil), // 14: teleport.lib.teleterm.v1.UsageReportingSettings - (*ReportUnexpectedVnetShutdownRequest)(nil), // 15: teleport.lib.teleterm.v1.ReportUnexpectedVnetShutdownRequest - (*ReportUnexpectedVnetShutdownResponse)(nil), // 16: teleport.lib.teleterm.v1.ReportUnexpectedVnetShutdownResponse + (*PromptHardwareKeyPINRequest)(nil), // 12: teleport.lib.teleterm.v1.PromptHardwareKeyPINRequest + (*PromptHardwareKeyPINResponse)(nil), // 13: teleport.lib.teleterm.v1.PromptHardwareKeyPINResponse + (*PromptHardwareKeyTouchRequest)(nil), // 14: teleport.lib.teleterm.v1.PromptHardwareKeyTouchRequest + (*PromptHardwareKeyTouchResponse)(nil), // 15: teleport.lib.teleterm.v1.PromptHardwareKeyTouchResponse + (*PromptHardwareKeyPINChangeRequest)(nil), // 16: teleport.lib.teleterm.v1.PromptHardwareKeyPINChangeRequest + (*PromptHardwareKeyPINChangeResponse)(nil), // 17: teleport.lib.teleterm.v1.PromptHardwareKeyPINChangeResponse + (*ConfirmHardwareKeySlotOverwriteRequest)(nil), // 18: teleport.lib.teleterm.v1.ConfirmHardwareKeySlotOverwriteRequest + (*ConfirmHardwareKeySlotOverwriteResponse)(nil), // 19: teleport.lib.teleterm.v1.ConfirmHardwareKeySlotOverwriteResponse + (*GetUsageReportingSettingsRequest)(nil), // 20: teleport.lib.teleterm.v1.GetUsageReportingSettingsRequest + (*GetUsageReportingSettingsResponse)(nil), // 21: teleport.lib.teleterm.v1.GetUsageReportingSettingsResponse + (*UsageReportingSettings)(nil), // 22: teleport.lib.teleterm.v1.UsageReportingSettings + (*ReportUnexpectedVnetShutdownRequest)(nil), // 23: teleport.lib.teleterm.v1.ReportUnexpectedVnetShutdownRequest + (*ReportUnexpectedVnetShutdownResponse)(nil), // 24: teleport.lib.teleterm.v1.ReportUnexpectedVnetShutdownResponse } var file_teleport_lib_teleterm_v1_tshd_events_service_proto_depIdxs = []int32{ 1, // 0: teleport.lib.teleterm.v1.ReloginRequest.gateway_cert_expired:type_name -> teleport.lib.teleterm.v1.GatewayCertExpired 2, // 1: teleport.lib.teleterm.v1.ReloginRequest.vnet_cert_expired:type_name -> teleport.lib.teleterm.v1.VnetCertExpired 5, // 2: teleport.lib.teleterm.v1.SendNotificationRequest.cannot_proxy_gateway_connection:type_name -> teleport.lib.teleterm.v1.CannotProxyGatewayConnection 6, // 3: teleport.lib.teleterm.v1.SendNotificationRequest.cannot_proxy_vnet_connection:type_name -> teleport.lib.teleterm.v1.CannotProxyVnetConnection - 14, // 4: teleport.lib.teleterm.v1.GetUsageReportingSettingsResponse.usage_reporting_settings:type_name -> teleport.lib.teleterm.v1.UsageReportingSettings + 22, // 4: teleport.lib.teleterm.v1.GetUsageReportingSettingsResponse.usage_reporting_settings:type_name -> teleport.lib.teleterm.v1.UsageReportingSettings 0, // 5: teleport.lib.teleterm.v1.TshdEventsService.Relogin:input_type -> teleport.lib.teleterm.v1.ReloginRequest 4, // 6: teleport.lib.teleterm.v1.TshdEventsService.SendNotification:input_type -> teleport.lib.teleterm.v1.SendNotificationRequest 8, // 7: teleport.lib.teleterm.v1.TshdEventsService.SendPendingHeadlessAuthentication:input_type -> teleport.lib.teleterm.v1.SendPendingHeadlessAuthenticationRequest 10, // 8: teleport.lib.teleterm.v1.TshdEventsService.PromptMFA:input_type -> teleport.lib.teleterm.v1.PromptMFARequest - 12, // 9: teleport.lib.teleterm.v1.TshdEventsService.GetUsageReportingSettings:input_type -> teleport.lib.teleterm.v1.GetUsageReportingSettingsRequest - 15, // 10: teleport.lib.teleterm.v1.TshdEventsService.ReportUnexpectedVnetShutdown:input_type -> teleport.lib.teleterm.v1.ReportUnexpectedVnetShutdownRequest - 3, // 11: teleport.lib.teleterm.v1.TshdEventsService.Relogin:output_type -> teleport.lib.teleterm.v1.ReloginResponse - 7, // 12: teleport.lib.teleterm.v1.TshdEventsService.SendNotification:output_type -> teleport.lib.teleterm.v1.SendNotificationResponse - 9, // 13: teleport.lib.teleterm.v1.TshdEventsService.SendPendingHeadlessAuthentication:output_type -> teleport.lib.teleterm.v1.SendPendingHeadlessAuthenticationResponse - 11, // 14: teleport.lib.teleterm.v1.TshdEventsService.PromptMFA:output_type -> teleport.lib.teleterm.v1.PromptMFAResponse - 13, // 15: teleport.lib.teleterm.v1.TshdEventsService.GetUsageReportingSettings:output_type -> teleport.lib.teleterm.v1.GetUsageReportingSettingsResponse - 16, // 16: teleport.lib.teleterm.v1.TshdEventsService.ReportUnexpectedVnetShutdown:output_type -> teleport.lib.teleterm.v1.ReportUnexpectedVnetShutdownResponse - 11, // [11:17] is the sub-list for method output_type - 5, // [5:11] is the sub-list for method input_type + 12, // 9: teleport.lib.teleterm.v1.TshdEventsService.PromptHardwareKeyPIN:input_type -> teleport.lib.teleterm.v1.PromptHardwareKeyPINRequest + 14, // 10: teleport.lib.teleterm.v1.TshdEventsService.PromptHardwareKeyTouch:input_type -> teleport.lib.teleterm.v1.PromptHardwareKeyTouchRequest + 16, // 11: teleport.lib.teleterm.v1.TshdEventsService.PromptHardwareKeyPINChange:input_type -> teleport.lib.teleterm.v1.PromptHardwareKeyPINChangeRequest + 18, // 12: teleport.lib.teleterm.v1.TshdEventsService.ConfirmHardwareKeySlotOverwrite:input_type -> teleport.lib.teleterm.v1.ConfirmHardwareKeySlotOverwriteRequest + 20, // 13: teleport.lib.teleterm.v1.TshdEventsService.GetUsageReportingSettings:input_type -> teleport.lib.teleterm.v1.GetUsageReportingSettingsRequest + 23, // 14: teleport.lib.teleterm.v1.TshdEventsService.ReportUnexpectedVnetShutdown:input_type -> teleport.lib.teleterm.v1.ReportUnexpectedVnetShutdownRequest + 3, // 15: teleport.lib.teleterm.v1.TshdEventsService.Relogin:output_type -> teleport.lib.teleterm.v1.ReloginResponse + 7, // 16: teleport.lib.teleterm.v1.TshdEventsService.SendNotification:output_type -> teleport.lib.teleterm.v1.SendNotificationResponse + 9, // 17: teleport.lib.teleterm.v1.TshdEventsService.SendPendingHeadlessAuthentication:output_type -> teleport.lib.teleterm.v1.SendPendingHeadlessAuthenticationResponse + 11, // 18: teleport.lib.teleterm.v1.TshdEventsService.PromptMFA:output_type -> teleport.lib.teleterm.v1.PromptMFAResponse + 13, // 19: teleport.lib.teleterm.v1.TshdEventsService.PromptHardwareKeyPIN:output_type -> teleport.lib.teleterm.v1.PromptHardwareKeyPINResponse + 15, // 20: teleport.lib.teleterm.v1.TshdEventsService.PromptHardwareKeyTouch:output_type -> teleport.lib.teleterm.v1.PromptHardwareKeyTouchResponse + 17, // 21: teleport.lib.teleterm.v1.TshdEventsService.PromptHardwareKeyPINChange:output_type -> teleport.lib.teleterm.v1.PromptHardwareKeyPINChangeResponse + 19, // 22: teleport.lib.teleterm.v1.TshdEventsService.ConfirmHardwareKeySlotOverwrite:output_type -> teleport.lib.teleterm.v1.ConfirmHardwareKeySlotOverwriteResponse + 21, // 23: teleport.lib.teleterm.v1.TshdEventsService.GetUsageReportingSettings:output_type -> teleport.lib.teleterm.v1.GetUsageReportingSettingsResponse + 24, // 24: teleport.lib.teleterm.v1.TshdEventsService.ReportUnexpectedVnetShutdown:output_type -> teleport.lib.teleterm.v1.ReportUnexpectedVnetShutdownResponse + 15, // [15:25] is the sub-list for method output_type + 5, // [5:15] is the sub-list for method input_type 5, // [5:5] is the sub-list for extension type_name 5, // [5:5] is the sub-list for extension extendee 0, // [0:5] is the sub-list for field type_name @@ -1213,7 +1706,7 @@ func file_teleport_lib_teleterm_v1_tshd_events_service_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_teleport_lib_teleterm_v1_tshd_events_service_proto_rawDesc, NumEnums: 0, - NumMessages: 17, + NumMessages: 25, NumExtensions: 0, NumServices: 1, }, diff --git a/gen/proto/go/teleport/lib/teleterm/v1/tshd_events_service_grpc.pb.go b/gen/proto/go/teleport/lib/teleterm/v1/tshd_events_service_grpc.pb.go index 8ee0b2a271acd..da8f82e67af7e 100644 --- a/gen/proto/go/teleport/lib/teleterm/v1/tshd_events_service_grpc.pb.go +++ b/gen/proto/go/teleport/lib/teleterm/v1/tshd_events_service_grpc.pb.go @@ -40,6 +40,10 @@ const ( TshdEventsService_SendNotification_FullMethodName = "/teleport.lib.teleterm.v1.TshdEventsService/SendNotification" TshdEventsService_SendPendingHeadlessAuthentication_FullMethodName = "/teleport.lib.teleterm.v1.TshdEventsService/SendPendingHeadlessAuthentication" TshdEventsService_PromptMFA_FullMethodName = "/teleport.lib.teleterm.v1.TshdEventsService/PromptMFA" + TshdEventsService_PromptHardwareKeyPIN_FullMethodName = "/teleport.lib.teleterm.v1.TshdEventsService/PromptHardwareKeyPIN" + TshdEventsService_PromptHardwareKeyTouch_FullMethodName = "/teleport.lib.teleterm.v1.TshdEventsService/PromptHardwareKeyTouch" + TshdEventsService_PromptHardwareKeyPINChange_FullMethodName = "/teleport.lib.teleterm.v1.TshdEventsService/PromptHardwareKeyPINChange" + TshdEventsService_ConfirmHardwareKeySlotOverwrite_FullMethodName = "/teleport.lib.teleterm.v1.TshdEventsService/ConfirmHardwareKeySlotOverwrite" TshdEventsService_GetUsageReportingSettings_FullMethodName = "/teleport.lib.teleterm.v1.TshdEventsService/GetUsageReportingSettings" TshdEventsService_ReportUnexpectedVnetShutdown_FullMethodName = "/teleport.lib.teleterm.v1.TshdEventsService/ReportUnexpectedVnetShutdown" ) @@ -66,6 +70,18 @@ type TshdEventsServiceClient interface { // If TOTP is supported, tsh daemon expects that the Electron app responds to this RPC with the // code. PromptMFA(ctx context.Context, in *PromptMFARequest, opts ...grpc.CallOption) (*PromptMFAResponse, error) + // PromptHardwareKeyPIN notifies the Electron app that the daemon is waiting for the user to + // provide the hardware key PIN. + PromptHardwareKeyPIN(ctx context.Context, in *PromptHardwareKeyPINRequest, opts ...grpc.CallOption) (*PromptHardwareKeyPINResponse, error) + // PromptHardwareKeyTouch notifies the Electron app that the daemon is waiting for the user to touch the hardware key. + // When the daemon detects the touch, it cancels the prompt. + PromptHardwareKeyTouch(ctx context.Context, in *PromptHardwareKeyTouchRequest, opts ...grpc.CallOption) (*PromptHardwareKeyTouchResponse, error) + // PromptHardwareKeyPINChange notifies the Electron app that the daemon is waiting for the user to + // change the hardware key PIN. + PromptHardwareKeyPINChange(ctx context.Context, in *PromptHardwareKeyPINChangeRequest, opts ...grpc.CallOption) (*PromptHardwareKeyPINChangeResponse, error) + // ConfirmHardwareKeySlotOverwrite displays a dialog prompting the user to confirm whether + // the slot's private key and certificate should be overwritten. + ConfirmHardwareKeySlotOverwrite(ctx context.Context, in *ConfirmHardwareKeySlotOverwriteRequest, opts ...grpc.CallOption) (*ConfirmHardwareKeySlotOverwriteResponse, error) // GetUsageReportingSettings returns the current state of usage reporting. // At the moment, the user cannot toggle usage reporting on and off without shutting down the app, // with the only exception being the first start of the app when they're prompted about telemetry. @@ -125,6 +141,46 @@ func (c *tshdEventsServiceClient) PromptMFA(ctx context.Context, in *PromptMFARe return out, nil } +func (c *tshdEventsServiceClient) PromptHardwareKeyPIN(ctx context.Context, in *PromptHardwareKeyPINRequest, opts ...grpc.CallOption) (*PromptHardwareKeyPINResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(PromptHardwareKeyPINResponse) + err := c.cc.Invoke(ctx, TshdEventsService_PromptHardwareKeyPIN_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *tshdEventsServiceClient) PromptHardwareKeyTouch(ctx context.Context, in *PromptHardwareKeyTouchRequest, opts ...grpc.CallOption) (*PromptHardwareKeyTouchResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(PromptHardwareKeyTouchResponse) + err := c.cc.Invoke(ctx, TshdEventsService_PromptHardwareKeyTouch_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *tshdEventsServiceClient) PromptHardwareKeyPINChange(ctx context.Context, in *PromptHardwareKeyPINChangeRequest, opts ...grpc.CallOption) (*PromptHardwareKeyPINChangeResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(PromptHardwareKeyPINChangeResponse) + err := c.cc.Invoke(ctx, TshdEventsService_PromptHardwareKeyPINChange_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *tshdEventsServiceClient) ConfirmHardwareKeySlotOverwrite(ctx context.Context, in *ConfirmHardwareKeySlotOverwriteRequest, opts ...grpc.CallOption) (*ConfirmHardwareKeySlotOverwriteResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ConfirmHardwareKeySlotOverwriteResponse) + err := c.cc.Invoke(ctx, TshdEventsService_ConfirmHardwareKeySlotOverwrite_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *tshdEventsServiceClient) GetUsageReportingSettings(ctx context.Context, in *GetUsageReportingSettingsRequest, opts ...grpc.CallOption) (*GetUsageReportingSettingsResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetUsageReportingSettingsResponse) @@ -167,6 +223,18 @@ type TshdEventsServiceServer interface { // If TOTP is supported, tsh daemon expects that the Electron app responds to this RPC with the // code. PromptMFA(context.Context, *PromptMFARequest) (*PromptMFAResponse, error) + // PromptHardwareKeyPIN notifies the Electron app that the daemon is waiting for the user to + // provide the hardware key PIN. + PromptHardwareKeyPIN(context.Context, *PromptHardwareKeyPINRequest) (*PromptHardwareKeyPINResponse, error) + // PromptHardwareKeyTouch notifies the Electron app that the daemon is waiting for the user to touch the hardware key. + // When the daemon detects the touch, it cancels the prompt. + PromptHardwareKeyTouch(context.Context, *PromptHardwareKeyTouchRequest) (*PromptHardwareKeyTouchResponse, error) + // PromptHardwareKeyPINChange notifies the Electron app that the daemon is waiting for the user to + // change the hardware key PIN. + PromptHardwareKeyPINChange(context.Context, *PromptHardwareKeyPINChangeRequest) (*PromptHardwareKeyPINChangeResponse, error) + // ConfirmHardwareKeySlotOverwrite displays a dialog prompting the user to confirm whether + // the slot's private key and certificate should be overwritten. + ConfirmHardwareKeySlotOverwrite(context.Context, *ConfirmHardwareKeySlotOverwriteRequest) (*ConfirmHardwareKeySlotOverwriteResponse, error) // GetUsageReportingSettings returns the current state of usage reporting. // At the moment, the user cannot toggle usage reporting on and off without shutting down the app, // with the only exception being the first start of the app when they're prompted about telemetry. @@ -198,6 +266,18 @@ func (UnimplementedTshdEventsServiceServer) SendPendingHeadlessAuthentication(co func (UnimplementedTshdEventsServiceServer) PromptMFA(context.Context, *PromptMFARequest) (*PromptMFAResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method PromptMFA not implemented") } +func (UnimplementedTshdEventsServiceServer) PromptHardwareKeyPIN(context.Context, *PromptHardwareKeyPINRequest) (*PromptHardwareKeyPINResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method PromptHardwareKeyPIN not implemented") +} +func (UnimplementedTshdEventsServiceServer) PromptHardwareKeyTouch(context.Context, *PromptHardwareKeyTouchRequest) (*PromptHardwareKeyTouchResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method PromptHardwareKeyTouch not implemented") +} +func (UnimplementedTshdEventsServiceServer) PromptHardwareKeyPINChange(context.Context, *PromptHardwareKeyPINChangeRequest) (*PromptHardwareKeyPINChangeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method PromptHardwareKeyPINChange not implemented") +} +func (UnimplementedTshdEventsServiceServer) ConfirmHardwareKeySlotOverwrite(context.Context, *ConfirmHardwareKeySlotOverwriteRequest) (*ConfirmHardwareKeySlotOverwriteResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ConfirmHardwareKeySlotOverwrite not implemented") +} func (UnimplementedTshdEventsServiceServer) GetUsageReportingSettings(context.Context, *GetUsageReportingSettingsRequest) (*GetUsageReportingSettingsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetUsageReportingSettings not implemented") } @@ -297,6 +377,78 @@ func _TshdEventsService_PromptMFA_Handler(srv interface{}, ctx context.Context, return interceptor(ctx, in, info, handler) } +func _TshdEventsService_PromptHardwareKeyPIN_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PromptHardwareKeyPINRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(TshdEventsServiceServer).PromptHardwareKeyPIN(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: TshdEventsService_PromptHardwareKeyPIN_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(TshdEventsServiceServer).PromptHardwareKeyPIN(ctx, req.(*PromptHardwareKeyPINRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _TshdEventsService_PromptHardwareKeyTouch_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PromptHardwareKeyTouchRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(TshdEventsServiceServer).PromptHardwareKeyTouch(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: TshdEventsService_PromptHardwareKeyTouch_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(TshdEventsServiceServer).PromptHardwareKeyTouch(ctx, req.(*PromptHardwareKeyTouchRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _TshdEventsService_PromptHardwareKeyPINChange_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PromptHardwareKeyPINChangeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(TshdEventsServiceServer).PromptHardwareKeyPINChange(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: TshdEventsService_PromptHardwareKeyPINChange_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(TshdEventsServiceServer).PromptHardwareKeyPINChange(ctx, req.(*PromptHardwareKeyPINChangeRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _TshdEventsService_ConfirmHardwareKeySlotOverwrite_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ConfirmHardwareKeySlotOverwriteRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(TshdEventsServiceServer).ConfirmHardwareKeySlotOverwrite(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: TshdEventsService_ConfirmHardwareKeySlotOverwrite_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(TshdEventsServiceServer).ConfirmHardwareKeySlotOverwrite(ctx, req.(*ConfirmHardwareKeySlotOverwriteRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _TshdEventsService_GetUsageReportingSettings_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(GetUsageReportingSettingsRequest) if err := dec(in); err != nil { @@ -356,6 +508,22 @@ var TshdEventsService_ServiceDesc = grpc.ServiceDesc{ MethodName: "PromptMFA", Handler: _TshdEventsService_PromptMFA_Handler, }, + { + MethodName: "PromptHardwareKeyPIN", + Handler: _TshdEventsService_PromptHardwareKeyPIN_Handler, + }, + { + MethodName: "PromptHardwareKeyTouch", + Handler: _TshdEventsService_PromptHardwareKeyTouch_Handler, + }, + { + MethodName: "PromptHardwareKeyPINChange", + Handler: _TshdEventsService_PromptHardwareKeyPINChange_Handler, + }, + { + MethodName: "ConfirmHardwareKeySlotOverwrite", + Handler: _TshdEventsService_ConfirmHardwareKeySlotOverwrite_Handler, + }, { MethodName: "GetUsageReportingSettings", Handler: _TshdEventsService_GetUsageReportingSettings_Handler, diff --git a/gen/proto/ts/teleport/lib/teleterm/v1/tshd_events_service_pb.client.ts b/gen/proto/ts/teleport/lib/teleterm/v1/tshd_events_service_pb.client.ts index 762ad049fc740..639353d5e19a7 100644 --- a/gen/proto/ts/teleport/lib/teleterm/v1/tshd_events_service_pb.client.ts +++ b/gen/proto/ts/teleport/lib/teleterm/v1/tshd_events_service_pb.client.ts @@ -28,6 +28,14 @@ import type { ReportUnexpectedVnetShutdownResponse } from "./tshd_events_service import type { ReportUnexpectedVnetShutdownRequest } from "./tshd_events_service_pb"; import type { GetUsageReportingSettingsResponse } from "./tshd_events_service_pb"; import type { GetUsageReportingSettingsRequest } from "./tshd_events_service_pb"; +import type { ConfirmHardwareKeySlotOverwriteResponse } from "./tshd_events_service_pb"; +import type { ConfirmHardwareKeySlotOverwriteRequest } from "./tshd_events_service_pb"; +import type { PromptHardwareKeyPINChangeResponse } from "./tshd_events_service_pb"; +import type { PromptHardwareKeyPINChangeRequest } from "./tshd_events_service_pb"; +import type { PromptHardwareKeyTouchResponse } from "./tshd_events_service_pb"; +import type { PromptHardwareKeyTouchRequest } from "./tshd_events_service_pb"; +import type { PromptHardwareKeyPINResponse } from "./tshd_events_service_pb"; +import type { PromptHardwareKeyPINRequest } from "./tshd_events_service_pb"; import type { PromptMFAResponse } from "./tshd_events_service_pb"; import type { PromptMFARequest } from "./tshd_events_service_pb"; import type { SendPendingHeadlessAuthenticationResponse } from "./tshd_events_service_pb"; @@ -77,6 +85,34 @@ export interface ITshdEventsServiceClient { * @generated from protobuf rpc: PromptMFA(teleport.lib.teleterm.v1.PromptMFARequest) returns (teleport.lib.teleterm.v1.PromptMFAResponse); */ promptMFA(input: PromptMFARequest, options?: RpcOptions): UnaryCall; + /** + * PromptHardwareKeyPIN notifies the Electron app that the daemon is waiting for the user to + * provide the hardware key PIN. + * + * @generated from protobuf rpc: PromptHardwareKeyPIN(teleport.lib.teleterm.v1.PromptHardwareKeyPINRequest) returns (teleport.lib.teleterm.v1.PromptHardwareKeyPINResponse); + */ + promptHardwareKeyPIN(input: PromptHardwareKeyPINRequest, options?: RpcOptions): UnaryCall; + /** + * PromptHardwareKeyTouch notifies the Electron app that the daemon is waiting for the user to touch the hardware key. + * When the daemon detects the touch, it cancels the prompt. + * + * @generated from protobuf rpc: PromptHardwareKeyTouch(teleport.lib.teleterm.v1.PromptHardwareKeyTouchRequest) returns (teleport.lib.teleterm.v1.PromptHardwareKeyTouchResponse); + */ + promptHardwareKeyTouch(input: PromptHardwareKeyTouchRequest, options?: RpcOptions): UnaryCall; + /** + * PromptHardwareKeyPINChange notifies the Electron app that the daemon is waiting for the user to + * change the hardware key PIN. + * + * @generated from protobuf rpc: PromptHardwareKeyPINChange(teleport.lib.teleterm.v1.PromptHardwareKeyPINChangeRequest) returns (teleport.lib.teleterm.v1.PromptHardwareKeyPINChangeResponse); + */ + promptHardwareKeyPINChange(input: PromptHardwareKeyPINChangeRequest, options?: RpcOptions): UnaryCall; + /** + * ConfirmHardwareKeySlotOverwrite displays a dialog prompting the user to confirm whether + * the slot's private key and certificate should be overwritten. + * + * @generated from protobuf rpc: ConfirmHardwareKeySlotOverwrite(teleport.lib.teleterm.v1.ConfirmHardwareKeySlotOverwriteRequest) returns (teleport.lib.teleterm.v1.ConfirmHardwareKeySlotOverwriteResponse); + */ + confirmHardwareKeySlotOverwrite(input: ConfirmHardwareKeySlotOverwriteRequest, options?: RpcOptions): UnaryCall; /** * GetUsageReportingSettings returns the current state of usage reporting. * At the moment, the user cannot toggle usage reporting on and off without shutting down the app, @@ -150,6 +186,46 @@ export class TshdEventsServiceClient implements ITshdEventsServiceClient, Servic const method = this.methods[3], opt = this._transport.mergeOptions(options); return stackIntercept("unary", this._transport, method, opt, input); } + /** + * PromptHardwareKeyPIN notifies the Electron app that the daemon is waiting for the user to + * provide the hardware key PIN. + * + * @generated from protobuf rpc: PromptHardwareKeyPIN(teleport.lib.teleterm.v1.PromptHardwareKeyPINRequest) returns (teleport.lib.teleterm.v1.PromptHardwareKeyPINResponse); + */ + promptHardwareKeyPIN(input: PromptHardwareKeyPINRequest, options?: RpcOptions): UnaryCall { + const method = this.methods[4], opt = this._transport.mergeOptions(options); + return stackIntercept("unary", this._transport, method, opt, input); + } + /** + * PromptHardwareKeyTouch notifies the Electron app that the daemon is waiting for the user to touch the hardware key. + * When the daemon detects the touch, it cancels the prompt. + * + * @generated from protobuf rpc: PromptHardwareKeyTouch(teleport.lib.teleterm.v1.PromptHardwareKeyTouchRequest) returns (teleport.lib.teleterm.v1.PromptHardwareKeyTouchResponse); + */ + promptHardwareKeyTouch(input: PromptHardwareKeyTouchRequest, options?: RpcOptions): UnaryCall { + const method = this.methods[5], opt = this._transport.mergeOptions(options); + return stackIntercept("unary", this._transport, method, opt, input); + } + /** + * PromptHardwareKeyPINChange notifies the Electron app that the daemon is waiting for the user to + * change the hardware key PIN. + * + * @generated from protobuf rpc: PromptHardwareKeyPINChange(teleport.lib.teleterm.v1.PromptHardwareKeyPINChangeRequest) returns (teleport.lib.teleterm.v1.PromptHardwareKeyPINChangeResponse); + */ + promptHardwareKeyPINChange(input: PromptHardwareKeyPINChangeRequest, options?: RpcOptions): UnaryCall { + const method = this.methods[6], opt = this._transport.mergeOptions(options); + return stackIntercept("unary", this._transport, method, opt, input); + } + /** + * ConfirmHardwareKeySlotOverwrite displays a dialog prompting the user to confirm whether + * the slot's private key and certificate should be overwritten. + * + * @generated from protobuf rpc: ConfirmHardwareKeySlotOverwrite(teleport.lib.teleterm.v1.ConfirmHardwareKeySlotOverwriteRequest) returns (teleport.lib.teleterm.v1.ConfirmHardwareKeySlotOverwriteResponse); + */ + confirmHardwareKeySlotOverwrite(input: ConfirmHardwareKeySlotOverwriteRequest, options?: RpcOptions): UnaryCall { + const method = this.methods[7], opt = this._transport.mergeOptions(options); + return stackIntercept("unary", this._transport, method, opt, input); + } /** * GetUsageReportingSettings returns the current state of usage reporting. * At the moment, the user cannot toggle usage reporting on and off without shutting down the app, @@ -159,7 +235,7 @@ export class TshdEventsServiceClient implements ITshdEventsServiceClient, Servic * @generated from protobuf rpc: GetUsageReportingSettings(teleport.lib.teleterm.v1.GetUsageReportingSettingsRequest) returns (teleport.lib.teleterm.v1.GetUsageReportingSettingsResponse); */ getUsageReportingSettings(input: GetUsageReportingSettingsRequest, options?: RpcOptions): UnaryCall { - const method = this.methods[4], opt = this._transport.mergeOptions(options); + const method = this.methods[8], opt = this._transport.mergeOptions(options); return stackIntercept("unary", this._transport, method, opt, input); } /** @@ -170,7 +246,7 @@ export class TshdEventsServiceClient implements ITshdEventsServiceClient, Servic * @generated from protobuf rpc: ReportUnexpectedVnetShutdown(teleport.lib.teleterm.v1.ReportUnexpectedVnetShutdownRequest) returns (teleport.lib.teleterm.v1.ReportUnexpectedVnetShutdownResponse); */ reportUnexpectedVnetShutdown(input: ReportUnexpectedVnetShutdownRequest, options?: RpcOptions): UnaryCall { - const method = this.methods[5], opt = this._transport.mergeOptions(options); + const method = this.methods[9], opt = this._transport.mergeOptions(options); return stackIntercept("unary", this._transport, method, opt, input); } } diff --git a/gen/proto/ts/teleport/lib/teleterm/v1/tshd_events_service_pb.grpc-server.ts b/gen/proto/ts/teleport/lib/teleterm/v1/tshd_events_service_pb.grpc-server.ts index 7f71d9adf0d4a..110fa4c7d1c33 100644 --- a/gen/proto/ts/teleport/lib/teleterm/v1/tshd_events_service_pb.grpc-server.ts +++ b/gen/proto/ts/teleport/lib/teleterm/v1/tshd_events_service_pb.grpc-server.ts @@ -25,6 +25,14 @@ import { ReportUnexpectedVnetShutdownResponse } from "./tshd_events_service_pb"; import { ReportUnexpectedVnetShutdownRequest } from "./tshd_events_service_pb"; import { GetUsageReportingSettingsResponse } from "./tshd_events_service_pb"; import { GetUsageReportingSettingsRequest } from "./tshd_events_service_pb"; +import { ConfirmHardwareKeySlotOverwriteResponse } from "./tshd_events_service_pb"; +import { ConfirmHardwareKeySlotOverwriteRequest } from "./tshd_events_service_pb"; +import { PromptHardwareKeyPINChangeResponse } from "./tshd_events_service_pb"; +import { PromptHardwareKeyPINChangeRequest } from "./tshd_events_service_pb"; +import { PromptHardwareKeyTouchResponse } from "./tshd_events_service_pb"; +import { PromptHardwareKeyTouchRequest } from "./tshd_events_service_pb"; +import { PromptHardwareKeyPINResponse } from "./tshd_events_service_pb"; +import { PromptHardwareKeyPINRequest } from "./tshd_events_service_pb"; import { PromptMFAResponse } from "./tshd_events_service_pb"; import { PromptMFARequest } from "./tshd_events_service_pb"; import { SendPendingHeadlessAuthenticationResponse } from "./tshd_events_service_pb"; @@ -72,6 +80,34 @@ export interface ITshdEventsService extends grpc.UntypedServiceImplementation { * @generated from protobuf rpc: PromptMFA(teleport.lib.teleterm.v1.PromptMFARequest) returns (teleport.lib.teleterm.v1.PromptMFAResponse); */ promptMFA: grpc.handleUnaryCall; + /** + * PromptHardwareKeyPIN notifies the Electron app that the daemon is waiting for the user to + * provide the hardware key PIN. + * + * @generated from protobuf rpc: PromptHardwareKeyPIN(teleport.lib.teleterm.v1.PromptHardwareKeyPINRequest) returns (teleport.lib.teleterm.v1.PromptHardwareKeyPINResponse); + */ + promptHardwareKeyPIN: grpc.handleUnaryCall; + /** + * PromptHardwareKeyTouch notifies the Electron app that the daemon is waiting for the user to touch the hardware key. + * When the daemon detects the touch, it cancels the prompt. + * + * @generated from protobuf rpc: PromptHardwareKeyTouch(teleport.lib.teleterm.v1.PromptHardwareKeyTouchRequest) returns (teleport.lib.teleterm.v1.PromptHardwareKeyTouchResponse); + */ + promptHardwareKeyTouch: grpc.handleUnaryCall; + /** + * PromptHardwareKeyPINChange notifies the Electron app that the daemon is waiting for the user to + * change the hardware key PIN. + * + * @generated from protobuf rpc: PromptHardwareKeyPINChange(teleport.lib.teleterm.v1.PromptHardwareKeyPINChangeRequest) returns (teleport.lib.teleterm.v1.PromptHardwareKeyPINChangeResponse); + */ + promptHardwareKeyPINChange: grpc.handleUnaryCall; + /** + * ConfirmHardwareKeySlotOverwrite displays a dialog prompting the user to confirm whether + * the slot's private key and certificate should be overwritten. + * + * @generated from protobuf rpc: ConfirmHardwareKeySlotOverwrite(teleport.lib.teleterm.v1.ConfirmHardwareKeySlotOverwriteRequest) returns (teleport.lib.teleterm.v1.ConfirmHardwareKeySlotOverwriteResponse); + */ + confirmHardwareKeySlotOverwrite: grpc.handleUnaryCall; /** * GetUsageReportingSettings returns the current state of usage reporting. * At the moment, the user cannot toggle usage reporting on and off without shutting down the app, @@ -142,6 +178,46 @@ export const tshdEventsServiceDefinition: grpc.ServiceDefinition Buffer.from(PromptMFAResponse.toBinary(value)), requestSerialize: value => Buffer.from(PromptMFARequest.toBinary(value)) }, + promptHardwareKeyPIN: { + path: "/teleport.lib.teleterm.v1.TshdEventsService/PromptHardwareKeyPIN", + originalName: "PromptHardwareKeyPIN", + requestStream: false, + responseStream: false, + responseDeserialize: bytes => PromptHardwareKeyPINResponse.fromBinary(bytes), + requestDeserialize: bytes => PromptHardwareKeyPINRequest.fromBinary(bytes), + responseSerialize: value => Buffer.from(PromptHardwareKeyPINResponse.toBinary(value)), + requestSerialize: value => Buffer.from(PromptHardwareKeyPINRequest.toBinary(value)) + }, + promptHardwareKeyTouch: { + path: "/teleport.lib.teleterm.v1.TshdEventsService/PromptHardwareKeyTouch", + originalName: "PromptHardwareKeyTouch", + requestStream: false, + responseStream: false, + responseDeserialize: bytes => PromptHardwareKeyTouchResponse.fromBinary(bytes), + requestDeserialize: bytes => PromptHardwareKeyTouchRequest.fromBinary(bytes), + responseSerialize: value => Buffer.from(PromptHardwareKeyTouchResponse.toBinary(value)), + requestSerialize: value => Buffer.from(PromptHardwareKeyTouchRequest.toBinary(value)) + }, + promptHardwareKeyPINChange: { + path: "/teleport.lib.teleterm.v1.TshdEventsService/PromptHardwareKeyPINChange", + originalName: "PromptHardwareKeyPINChange", + requestStream: false, + responseStream: false, + responseDeserialize: bytes => PromptHardwareKeyPINChangeResponse.fromBinary(bytes), + requestDeserialize: bytes => PromptHardwareKeyPINChangeRequest.fromBinary(bytes), + responseSerialize: value => Buffer.from(PromptHardwareKeyPINChangeResponse.toBinary(value)), + requestSerialize: value => Buffer.from(PromptHardwareKeyPINChangeRequest.toBinary(value)) + }, + confirmHardwareKeySlotOverwrite: { + path: "/teleport.lib.teleterm.v1.TshdEventsService/ConfirmHardwareKeySlotOverwrite", + originalName: "ConfirmHardwareKeySlotOverwrite", + requestStream: false, + responseStream: false, + responseDeserialize: bytes => ConfirmHardwareKeySlotOverwriteResponse.fromBinary(bytes), + requestDeserialize: bytes => ConfirmHardwareKeySlotOverwriteRequest.fromBinary(bytes), + responseSerialize: value => Buffer.from(ConfirmHardwareKeySlotOverwriteResponse.toBinary(value)), + requestSerialize: value => Buffer.from(ConfirmHardwareKeySlotOverwriteRequest.toBinary(value)) + }, getUsageReportingSettings: { path: "/teleport.lib.teleterm.v1.TshdEventsService/GetUsageReportingSettings", originalName: "GetUsageReportingSettings", diff --git a/gen/proto/ts/teleport/lib/teleterm/v1/tshd_events_service_pb.ts b/gen/proto/ts/teleport/lib/teleterm/v1/tshd_events_service_pb.ts index 1fc11883d6438..6bc1ef96ed469 100644 --- a/gen/proto/ts/teleport/lib/teleterm/v1/tshd_events_service_pb.ts +++ b/gen/proto/ts/teleport/lib/teleterm/v1/tshd_events_service_pb.ts @@ -246,6 +246,121 @@ export interface PromptMFAResponse { */ totpCode: string; } +/** + * Request for PromptHardwareKeyPIN. + * + * @generated from protobuf message teleport.lib.teleterm.v1.PromptHardwareKeyPINRequest + */ +export interface PromptHardwareKeyPINRequest { + /** + * @generated from protobuf field: string root_cluster_uri = 1; + */ + rootClusterUri: string; + /** + * Specifies if a PIN is optional, allowing the user to set it up if left empty. + * + * @generated from protobuf field: bool pin_optional = 2; + */ + pinOptional: boolean; +} +/** + * Response for PromptHardwareKeyPIN. + * + * @generated from protobuf message teleport.lib.teleterm.v1.PromptHardwareKeyPINResponse + */ +export interface PromptHardwareKeyPINResponse { + /** + * pin as inputted by the user in the Electron app. + * + * @generated from protobuf field: string pin = 1; + */ + pin: string; +} +/** + * Request for PromptHardwareKeyTouchRequest. + * + * @generated from protobuf message teleport.lib.teleterm.v1.PromptHardwareKeyTouchRequest + */ +export interface PromptHardwareKeyTouchRequest { + /** + * @generated from protobuf field: string root_cluster_uri = 1; + */ + rootClusterUri: string; +} +/** + * Response for PromptHardwareKeyTouch. + * + * @generated from protobuf message teleport.lib.teleterm.v1.PromptHardwareKeyTouchResponse + */ +export interface PromptHardwareKeyTouchResponse { +} +/** + * Response for PromptHardwareKeyPINChange. + * + * @generated from protobuf message teleport.lib.teleterm.v1.PromptHardwareKeyPINChangeRequest + */ +export interface PromptHardwareKeyPINChangeRequest { + /** + * @generated from protobuf field: string root_cluster_uri = 1; + */ + rootClusterUri: string; +} +/** + * Response for PromptHardwareKeyPINChange. + * + * @generated from protobuf message teleport.lib.teleterm.v1.PromptHardwareKeyPINChangeResponse + */ +export interface PromptHardwareKeyPINChangeResponse { + /** + * New pin set by the user. + * + * @generated from protobuf field: string pin = 1; + */ + pin: string; + /** + * PUK is needed to change the PIN. + * This is a new PUK if it has not been changed from the default PUK. + * + * @generated from protobuf field: string puk = 2; + */ + puk: string; + /** + * puk_changed is true if the user changed the default PUK. + * + * @generated from protobuf field: bool puk_changed = 3; + */ + pukChanged: boolean; +} +/** + * Request for ConfirmHardwareKeySlotOverwrite. + * + * @generated from protobuf message teleport.lib.teleterm.v1.ConfirmHardwareKeySlotOverwriteRequest + */ +export interface ConfirmHardwareKeySlotOverwriteRequest { + /** + * @generated from protobuf field: string root_cluster_uri = 1; + */ + rootClusterUri: string; + /** + * Message to display in the prompt. + * + * @generated from protobuf field: string message = 2; + */ + message: string; +} +/** + * Response for ConfirmHardwareKeySlotOverwrite. + * + * @generated from protobuf message teleport.lib.teleterm.v1.ConfirmHardwareKeySlotOverwriteResponse + */ +export interface ConfirmHardwareKeySlotOverwriteResponse { + /** + * If true, the slot will be overridden. + * + * @generated from protobuf field: bool confirmed = 1; + */ + confirmed: boolean; +} /** * Request for GetUsageReportingSettings. * @@ -918,6 +1033,392 @@ class PromptMFAResponse$Type extends MessageType { */ export const PromptMFAResponse = new PromptMFAResponse$Type(); // @generated message type with reflection information, may provide speed optimized methods +class PromptHardwareKeyPINRequest$Type extends MessageType { + constructor() { + super("teleport.lib.teleterm.v1.PromptHardwareKeyPINRequest", [ + { no: 1, name: "root_cluster_uri", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "pin_optional", kind: "scalar", T: 8 /*ScalarType.BOOL*/ } + ]); + } + create(value?: PartialMessage): PromptHardwareKeyPINRequest { + const message = globalThis.Object.create((this.messagePrototype!)); + message.rootClusterUri = ""; + message.pinOptional = false; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: PromptHardwareKeyPINRequest): PromptHardwareKeyPINRequest { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string root_cluster_uri */ 1: + message.rootClusterUri = reader.string(); + break; + case /* bool pin_optional */ 2: + message.pinOptional = reader.bool(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: PromptHardwareKeyPINRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string root_cluster_uri = 1; */ + if (message.rootClusterUri !== "") + writer.tag(1, WireType.LengthDelimited).string(message.rootClusterUri); + /* bool pin_optional = 2; */ + if (message.pinOptional !== false) + writer.tag(2, WireType.Varint).bool(message.pinOptional); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message teleport.lib.teleterm.v1.PromptHardwareKeyPINRequest + */ +export const PromptHardwareKeyPINRequest = new PromptHardwareKeyPINRequest$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class PromptHardwareKeyPINResponse$Type extends MessageType { + constructor() { + super("teleport.lib.teleterm.v1.PromptHardwareKeyPINResponse", [ + { no: 1, name: "pin", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): PromptHardwareKeyPINResponse { + const message = globalThis.Object.create((this.messagePrototype!)); + message.pin = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: PromptHardwareKeyPINResponse): PromptHardwareKeyPINResponse { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string pin */ 1: + message.pin = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: PromptHardwareKeyPINResponse, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string pin = 1; */ + if (message.pin !== "") + writer.tag(1, WireType.LengthDelimited).string(message.pin); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message teleport.lib.teleterm.v1.PromptHardwareKeyPINResponse + */ +export const PromptHardwareKeyPINResponse = new PromptHardwareKeyPINResponse$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class PromptHardwareKeyTouchRequest$Type extends MessageType { + constructor() { + super("teleport.lib.teleterm.v1.PromptHardwareKeyTouchRequest", [ + { no: 1, name: "root_cluster_uri", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): PromptHardwareKeyTouchRequest { + const message = globalThis.Object.create((this.messagePrototype!)); + message.rootClusterUri = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: PromptHardwareKeyTouchRequest): PromptHardwareKeyTouchRequest { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string root_cluster_uri */ 1: + message.rootClusterUri = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: PromptHardwareKeyTouchRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string root_cluster_uri = 1; */ + if (message.rootClusterUri !== "") + writer.tag(1, WireType.LengthDelimited).string(message.rootClusterUri); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message teleport.lib.teleterm.v1.PromptHardwareKeyTouchRequest + */ +export const PromptHardwareKeyTouchRequest = new PromptHardwareKeyTouchRequest$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class PromptHardwareKeyTouchResponse$Type extends MessageType { + constructor() { + super("teleport.lib.teleterm.v1.PromptHardwareKeyTouchResponse", []); + } + create(value?: PartialMessage): PromptHardwareKeyTouchResponse { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: PromptHardwareKeyTouchResponse): PromptHardwareKeyTouchResponse { + return target ?? this.create(); + } + internalBinaryWrite(message: PromptHardwareKeyTouchResponse, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message teleport.lib.teleterm.v1.PromptHardwareKeyTouchResponse + */ +export const PromptHardwareKeyTouchResponse = new PromptHardwareKeyTouchResponse$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class PromptHardwareKeyPINChangeRequest$Type extends MessageType { + constructor() { + super("teleport.lib.teleterm.v1.PromptHardwareKeyPINChangeRequest", [ + { no: 1, name: "root_cluster_uri", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): PromptHardwareKeyPINChangeRequest { + const message = globalThis.Object.create((this.messagePrototype!)); + message.rootClusterUri = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: PromptHardwareKeyPINChangeRequest): PromptHardwareKeyPINChangeRequest { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string root_cluster_uri */ 1: + message.rootClusterUri = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: PromptHardwareKeyPINChangeRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string root_cluster_uri = 1; */ + if (message.rootClusterUri !== "") + writer.tag(1, WireType.LengthDelimited).string(message.rootClusterUri); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message teleport.lib.teleterm.v1.PromptHardwareKeyPINChangeRequest + */ +export const PromptHardwareKeyPINChangeRequest = new PromptHardwareKeyPINChangeRequest$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class PromptHardwareKeyPINChangeResponse$Type extends MessageType { + constructor() { + super("teleport.lib.teleterm.v1.PromptHardwareKeyPINChangeResponse", [ + { no: 1, name: "pin", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "puk", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "puk_changed", kind: "scalar", T: 8 /*ScalarType.BOOL*/ } + ]); + } + create(value?: PartialMessage): PromptHardwareKeyPINChangeResponse { + const message = globalThis.Object.create((this.messagePrototype!)); + message.pin = ""; + message.puk = ""; + message.pukChanged = false; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: PromptHardwareKeyPINChangeResponse): PromptHardwareKeyPINChangeResponse { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string pin */ 1: + message.pin = reader.string(); + break; + case /* string puk */ 2: + message.puk = reader.string(); + break; + case /* bool puk_changed */ 3: + message.pukChanged = reader.bool(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: PromptHardwareKeyPINChangeResponse, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string pin = 1; */ + if (message.pin !== "") + writer.tag(1, WireType.LengthDelimited).string(message.pin); + /* string puk = 2; */ + if (message.puk !== "") + writer.tag(2, WireType.LengthDelimited).string(message.puk); + /* bool puk_changed = 3; */ + if (message.pukChanged !== false) + writer.tag(3, WireType.Varint).bool(message.pukChanged); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message teleport.lib.teleterm.v1.PromptHardwareKeyPINChangeResponse + */ +export const PromptHardwareKeyPINChangeResponse = new PromptHardwareKeyPINChangeResponse$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class ConfirmHardwareKeySlotOverwriteRequest$Type extends MessageType { + constructor() { + super("teleport.lib.teleterm.v1.ConfirmHardwareKeySlotOverwriteRequest", [ + { no: 1, name: "root_cluster_uri", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "message", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): ConfirmHardwareKeySlotOverwriteRequest { + const message = globalThis.Object.create((this.messagePrototype!)); + message.rootClusterUri = ""; + message.message = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ConfirmHardwareKeySlotOverwriteRequest): ConfirmHardwareKeySlotOverwriteRequest { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string root_cluster_uri */ 1: + message.rootClusterUri = reader.string(); + break; + case /* string message */ 2: + message.message = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: ConfirmHardwareKeySlotOverwriteRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string root_cluster_uri = 1; */ + if (message.rootClusterUri !== "") + writer.tag(1, WireType.LengthDelimited).string(message.rootClusterUri); + /* string message = 2; */ + if (message.message !== "") + writer.tag(2, WireType.LengthDelimited).string(message.message); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message teleport.lib.teleterm.v1.ConfirmHardwareKeySlotOverwriteRequest + */ +export const ConfirmHardwareKeySlotOverwriteRequest = new ConfirmHardwareKeySlotOverwriteRequest$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class ConfirmHardwareKeySlotOverwriteResponse$Type extends MessageType { + constructor() { + super("teleport.lib.teleterm.v1.ConfirmHardwareKeySlotOverwriteResponse", [ + { no: 1, name: "confirmed", kind: "scalar", T: 8 /*ScalarType.BOOL*/ } + ]); + } + create(value?: PartialMessage): ConfirmHardwareKeySlotOverwriteResponse { + const message = globalThis.Object.create((this.messagePrototype!)); + message.confirmed = false; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ConfirmHardwareKeySlotOverwriteResponse): ConfirmHardwareKeySlotOverwriteResponse { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* bool confirmed */ 1: + message.confirmed = reader.bool(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: ConfirmHardwareKeySlotOverwriteResponse, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* bool confirmed = 1; */ + if (message.confirmed !== false) + writer.tag(1, WireType.Varint).bool(message.confirmed); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message teleport.lib.teleterm.v1.ConfirmHardwareKeySlotOverwriteResponse + */ +export const ConfirmHardwareKeySlotOverwriteResponse = new ConfirmHardwareKeySlotOverwriteResponse$Type(); +// @generated message type with reflection information, may provide speed optimized methods class GetUsageReportingSettingsRequest$Type extends MessageType { constructor() { super("teleport.lib.teleterm.v1.GetUsageReportingSettingsRequest", []); @@ -1115,6 +1616,10 @@ export const TshdEventsService = new ServiceType("teleport.lib.teleterm.v1.TshdE { name: "SendNotification", options: {}, I: SendNotificationRequest, O: SendNotificationResponse }, { name: "SendPendingHeadlessAuthentication", options: {}, I: SendPendingHeadlessAuthenticationRequest, O: SendPendingHeadlessAuthenticationResponse }, { name: "PromptMFA", options: {}, I: PromptMFARequest, O: PromptMFAResponse }, + { name: "PromptHardwareKeyPIN", options: {}, I: PromptHardwareKeyPINRequest, O: PromptHardwareKeyPINResponse }, + { name: "PromptHardwareKeyTouch", options: {}, I: PromptHardwareKeyTouchRequest, O: PromptHardwareKeyTouchResponse }, + { name: "PromptHardwareKeyPINChange", options: {}, I: PromptHardwareKeyPINChangeRequest, O: PromptHardwareKeyPINChangeResponse }, + { name: "ConfirmHardwareKeySlotOverwrite", options: {}, I: ConfirmHardwareKeySlotOverwriteRequest, O: ConfirmHardwareKeySlotOverwriteResponse }, { name: "GetUsageReportingSettings", options: {}, I: GetUsageReportingSettingsRequest, O: GetUsageReportingSettingsResponse }, { name: "ReportUnexpectedVnetShutdown", options: {}, I: ReportUnexpectedVnetShutdownRequest, O: ReportUnexpectedVnetShutdownResponse } ]); diff --git a/go.mod b/go.mod index 26b7458c73761..b75dec86e94a7 100644 --- a/go.mod +++ b/go.mod @@ -42,7 +42,7 @@ require ( github.com/aquasecurity/libbpfgo v0.5.1-libbpf-1.2 github.com/armon/go-radix v1.0.0 github.com/aws/aws-sdk-go v1.55.5 - github.com/aws/aws-sdk-go-v2 v1.31.0 + github.com/aws/aws-sdk-go-v2 v1.32.2 github.com/aws/aws-sdk-go-v2/config v1.27.39 github.com/aws/aws-sdk-go-v2/credentials v1.17.37 github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.15.8 @@ -59,7 +59,9 @@ require ( github.com/aws/aws-sdk-go-v2/service/eks v1.49.3 github.com/aws/aws-sdk-go-v2/service/glue v1.99.2 github.com/aws/aws-sdk-go-v2/service/iam v1.36.3 + github.com/aws/aws-sdk-go-v2/service/identitystore v1.27.2 github.com/aws/aws-sdk-go-v2/service/kms v1.36.3 + github.com/aws/aws-sdk-go-v2/service/organizations v1.34.2 github.com/aws/aws-sdk-go-v2/service/rds v1.85.2 github.com/aws/aws-sdk-go-v2/service/redshift v1.47.3 github.com/aws/aws-sdk-go-v2/service/s3 v1.63.3 @@ -67,9 +69,10 @@ require ( github.com/aws/aws-sdk-go-v2/service/sns v1.32.3 github.com/aws/aws-sdk-go-v2/service/sqs v1.35.3 github.com/aws/aws-sdk-go-v2/service/ssm v1.54.3 + github.com/aws/aws-sdk-go-v2/service/ssoadmin v1.29.2 github.com/aws/aws-sdk-go-v2/service/sts v1.31.3 github.com/aws/aws-sigv4-auth-cassandra-gocql-driver-plugin v1.1.0 - github.com/aws/smithy-go v1.21.0 + github.com/aws/smithy-go v1.22.0 github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20240918142057-e21b7a4e92d1 github.com/beevik/etree v1.4.1 github.com/buildkite/bintest/v3 v3.3.0 @@ -262,8 +265,8 @@ require ( github.com/apache/arrow/go/v15 v15.0.0 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.5 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.18 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.18 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.18 // indirect github.com/aws/aws-sdk-go-v2/service/ecr v1.33.0 // indirect diff --git a/go.sum b/go.sum index 7f0ecb63d99dd..f66f4a8af0e7d 100644 --- a/go.sum +++ b/go.sum @@ -835,8 +835,8 @@ github.com/aws/aws-sdk-go v1.49.12/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3Tj github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU= github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= github.com/aws/aws-sdk-go-v2 v1.18.0/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= -github.com/aws/aws-sdk-go-v2 v1.31.0 h1:3V05LbxTSItI5kUqNwhJrrrY1BAXxXt0sN0l72QmG5U= -github.com/aws/aws-sdk-go-v2 v1.31.0/go.mod h1:ztolYtaEUtdpf9Wftr31CJfLVjOnD/CVRkKOOYgF8hA= +github.com/aws/aws-sdk-go-v2 v1.32.2 h1:AkNLZEyYMLnx/Q/mSKkcMqwNFXMAvFto9bNsHqcTduI= +github.com/aws/aws-sdk-go-v2 v1.32.2/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.5 h1:xDAuZTn4IMm8o1LnBZvmrL8JA1io4o3YWNXgohbf20g= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.5/go.mod h1:wYSv6iDS621sEFLfKvpPE2ugjTuGlAG7iROg0hLOkfc= github.com/aws/aws-sdk-go-v2/config v1.18.25/go.mod h1:dZnYpD5wTW/dQF0rRNLVypB396zWCcPiBIvdvSWHEg4= @@ -855,11 +855,11 @@ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.14/go.mod h1:7I0Ju7p9mCIdlrf github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.25 h1:HkpHeZMM39sGtMHVYG1buAg93vhj5d7F81y6G0OAbGc= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.25/go.mod h1:j3Vz04ZjaWA6kygOsZRpmWe4CyGqfqq2u3unDTU0QGA= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33/go.mod h1:7i0PF1ME/2eUPFcjkVIwq+DOygHEoK92t5cDqNgYbIw= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.18 h1:kYQ3H1u0ANr9KEKlGs/jTLrBFPo8P8NaH/w7A01NeeM= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.18/go.mod h1:r506HmK5JDUh9+Mw4CfGJGSSoqIiLCndAuqXuhbv67Y= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21 h1:UAsR3xA31QGf79WzpG/ixT9FZvQlh5HY1NRqSHBNOCk= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21/go.mod h1:JNr43NFf5L9YaG3eKTm7HQzls9J+A9YYcGI5Quh1r2Y= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27/go.mod h1:UrHnn3QV/d0pBZ6QBAEQcqFLf8FAzLmoUfPVIueOvoM= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.18 h1:Z7IdFUONvTcvS7YuhtVxN99v2cCoHRXOS4mTr0B/pUc= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.18/go.mod h1:DkKMmksZVVyat+Y+r1dEOgJEfUeA7UngIHWeKsi0yNc= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21 h1:6jZVETqmYCadGFvrYEQfC5fAQmlo80CeL5psbno6r0s= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21/go.mod h1:1SR0GbLlnN3QUmYaflZNiH1ql+1qrSiB2vwcJ+4UM60= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.34/go.mod h1:Etz2dj6UHYuw+Xw830KfzCfWGMzqvUTCjUj5b76GVDc= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= @@ -889,6 +889,8 @@ github.com/aws/aws-sdk-go-v2/service/glue v1.99.2 h1:pfX1qky3shRS3rgxkdXKtiNWtMU github.com/aws/aws-sdk-go-v2/service/glue v1.99.2/go.mod h1:rCyUHLWGaSR9/oQgj2nGKRmPqFwtq3qxL14LkuQdadA= github.com/aws/aws-sdk-go-v2/service/iam v1.36.3 h1:dV9iimLEHKYAz2qTi+tGAD9QCnAG2pLD7HUEHB7m4mI= github.com/aws/aws-sdk-go-v2/service/iam v1.36.3/go.mod h1:HSvujsK8xeEHMIB18oMXjSfqaN9cVqpo/MtHJIksQRk= +github.com/aws/aws-sdk-go-v2/service/identitystore v1.27.2 h1:QSrf6HsounqUtlFAwArhVNHPt3WXmSm0pz7RtojjBdo= +github.com/aws/aws-sdk-go-v2/service/identitystore v1.27.2/go.mod h1:PtkL4CXOQy84zudggyFtyJFXCGDRY8igg9Nfo9df1sU= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.5 h1:QFASJGfT8wMXtuP3D5CRmMjARHv9ZmzFUMJznHDOY3w= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.5/go.mod h1:QdZ3OmoIjSX+8D1OPAzPxDfjXASbBMDsz9qvtyIhtik= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.20 h1:rTWjG6AvWekO2B1LHeM3ktU7MqyX9rzWQ7hgzneZW7E= @@ -902,6 +904,8 @@ github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.18 h1:eb+tFOIl9ZsUe github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.18/go.mod h1:GVCC2IJNJTmdlyEsSmofEy7EfJncP7DNnXDzRjJ5Keg= github.com/aws/aws-sdk-go-v2/service/kms v1.36.3 h1:iHi6lC6LfW6SNvB2bixmlOW3WMyWFrHZCWX+P+CCxMk= github.com/aws/aws-sdk-go-v2/service/kms v1.36.3/go.mod h1:OHmlX4+o0XIlJAQGAHPIy0N9yZcYS/vNG+T7geSNcFw= +github.com/aws/aws-sdk-go-v2/service/organizations v1.34.2 h1:ndH1E8olS/rDB+tiUMKj09g0o11PoOLAC+xRFB13bJw= +github.com/aws/aws-sdk-go-v2/service/organizations v1.34.2/go.mod h1:YZvv/wXIgIviYq9P/fQDhoMlzlI89M0D45GnYvIorLk= github.com/aws/aws-sdk-go-v2/service/rds v1.85.2 h1:KDO/FSO8V+zlvnQF6v4nOariw2qwPx5/z2pyb6X7ibk= github.com/aws/aws-sdk-go-v2/service/rds v1.85.2/go.mod h1:lhiPj6RvoJHWG2STp+k5az55YqGgFLBzkKYdYHgUh9g= github.com/aws/aws-sdk-go-v2/service/redshift v1.47.3 h1:TRJP6RflPN5A4yRpyXgznsJTJMT46tKigNAKzd7owic= @@ -919,6 +923,8 @@ github.com/aws/aws-sdk-go-v2/service/ssm v1.54.3/go.mod h1:qs3TBNpFEnVubl0WL3jru github.com/aws/aws-sdk-go-v2/service/sso v1.12.10/go.mod h1:ouy2P4z6sJN70fR3ka3wD3Ro3KezSxU6eKGQI2+2fjI= github.com/aws/aws-sdk-go-v2/service/sso v1.23.3 h1:rs4JCczF805+FDv2tRhZ1NU0RB2H6ryAvsWPanAr72Y= github.com/aws/aws-sdk-go-v2/service/sso v1.23.3/go.mod h1:XRlMvmad0ZNL+75C5FYdMvbbLkd6qiqz6foR1nA1PXY= +github.com/aws/aws-sdk-go-v2/service/ssoadmin v1.29.2 h1:O6MhOmqKN1dSmc04jaxmfdmSb3UbeQ715SYdVzNBiL4= +github.com/aws/aws-sdk-go-v2/service/ssoadmin v1.29.2/go.mod h1:QkSUZzFJsxztercu38+HLsTz9kHqRvAhVwp9+6SAeFA= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.10/go.mod h1:AFvkxc8xfBe8XA+5St5XIHHrQQtkxqrRincx4hmMHOk= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.27.3 h1:S7EPdMVZod8BGKQQPTBK+FcX9g7bKR7c4+HxWqHP7Vg= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.27.3/go.mod h1:FnvDM4sfa+isJ3kDXIzAB9GAwVSzFzSy97uZ3IsHo4E= @@ -928,8 +934,8 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.31.3/go.mod h1:yMWe0F+XG0DkRZK5ODZhG github.com/aws/aws-sigv4-auth-cassandra-gocql-driver-plugin v1.1.0 h1:EJsHUYgFBV7/N1YtL73lsfZODAOU+CnNSZfEAlqqQaA= github.com/aws/aws-sigv4-auth-cassandra-gocql-driver-plugin v1.1.0/go.mod h1:AxKuXHc0zv2yYaeueUG7R3ONbcnQIuDj0bkdFmPVRzU= github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= -github.com/aws/smithy-go v1.21.0 h1:H7L8dtDRk0P1Qm6y0ji7MCYMQObJ5R9CRpyPhRUkLYA= -github.com/aws/smithy-go v1.21.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= +github.com/aws/smithy-go v1.22.0 h1:uunKnWlcoL3zO7q+gG2Pk53joueEOsnNB28QdMsmiMM= +github.com/aws/smithy-go v1.22.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20240918142057-e21b7a4e92d1 h1:SlKqHasm//EZ5eJI3J6+HQWMCw2QS8ha1V7JtMsX6Tc= github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20240918142057-e21b7a4e92d1/go.mod h1:TZP0PQALiGqPiKB35wBb4Z6E/3DCFVh/o2Eul3lVS9Q= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= diff --git a/integrations/event-handler/go.mod b/integrations/event-handler/go.mod index 20ea1568397a2..2e8dcc7c26f60 100644 --- a/integrations/event-handler/go.mod +++ b/integrations/event-handler/go.mod @@ -63,14 +63,14 @@ require ( github.com/armon/go-radix v1.0.0 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/aws/aws-sdk-go v1.55.5 // indirect - github.com/aws/aws-sdk-go-v2 v1.31.0 // indirect + github.com/aws/aws-sdk-go-v2 v1.32.2 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.5 // indirect github.com/aws/aws-sdk-go-v2/config v1.27.39 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.17.37 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.14 // indirect github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.25 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.18 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.18 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.18 // indirect github.com/aws/aws-sdk-go-v2/service/athena v1.46.2 // indirect @@ -80,18 +80,21 @@ require ( github.com/aws/aws-sdk-go-v2/service/eks v1.49.3 // indirect github.com/aws/aws-sdk-go-v2/service/glue v1.99.2 // indirect github.com/aws/aws-sdk-go-v2/service/iam v1.36.3 // indirect + github.com/aws/aws-sdk-go-v2/service/identitystore v1.27.2 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.5 // indirect github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.20 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.20 // indirect github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.18 // indirect github.com/aws/aws-sdk-go-v2/service/kms v1.36.3 // indirect + github.com/aws/aws-sdk-go-v2/service/organizations v1.34.2 // indirect github.com/aws/aws-sdk-go-v2/service/rds v1.85.2 // indirect github.com/aws/aws-sdk-go-v2/service/s3 v1.63.3 // indirect github.com/aws/aws-sdk-go-v2/service/ssm v1.54.3 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.23.3 // indirect + github.com/aws/aws-sdk-go-v2/service/ssoadmin v1.29.2 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.27.3 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.31.3 // indirect - github.com/aws/smithy-go v1.21.0 // indirect + github.com/aws/smithy-go v1.22.0 // indirect github.com/beevik/etree v1.4.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect diff --git a/integrations/event-handler/go.sum b/integrations/event-handler/go.sum index e3e05ecc43ee3..7b888e2365515 100644 --- a/integrations/event-handler/go.sum +++ b/integrations/event-handler/go.sum @@ -717,8 +717,8 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3d github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU= github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= -github.com/aws/aws-sdk-go-v2 v1.31.0 h1:3V05LbxTSItI5kUqNwhJrrrY1BAXxXt0sN0l72QmG5U= -github.com/aws/aws-sdk-go-v2 v1.31.0/go.mod h1:ztolYtaEUtdpf9Wftr31CJfLVjOnD/CVRkKOOYgF8hA= +github.com/aws/aws-sdk-go-v2 v1.32.2 h1:AkNLZEyYMLnx/Q/mSKkcMqwNFXMAvFto9bNsHqcTduI= +github.com/aws/aws-sdk-go-v2 v1.32.2/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.5 h1:xDAuZTn4IMm8o1LnBZvmrL8JA1io4o3YWNXgohbf20g= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.5/go.mod h1:wYSv6iDS621sEFLfKvpPE2ugjTuGlAG7iROg0hLOkfc= github.com/aws/aws-sdk-go-v2/config v1.27.39 h1:FCylu78eTGzW1ynHcongXK9YHtoXD5AiiUqq3YfJYjU= @@ -729,10 +729,10 @@ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.14 h1:C/d03NAmh8C4BZXhuRNboF github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.14/go.mod h1:7I0Ju7p9mCIdlrfS+JCgqcYD0VXz/N4yozsox+0o078= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.25 h1:HkpHeZMM39sGtMHVYG1buAg93vhj5d7F81y6G0OAbGc= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.25/go.mod h1:j3Vz04ZjaWA6kygOsZRpmWe4CyGqfqq2u3unDTU0QGA= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.18 h1:kYQ3H1u0ANr9KEKlGs/jTLrBFPo8P8NaH/w7A01NeeM= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.18/go.mod h1:r506HmK5JDUh9+Mw4CfGJGSSoqIiLCndAuqXuhbv67Y= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.18 h1:Z7IdFUONvTcvS7YuhtVxN99v2cCoHRXOS4mTr0B/pUc= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.18/go.mod h1:DkKMmksZVVyat+Y+r1dEOgJEfUeA7UngIHWeKsi0yNc= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21 h1:UAsR3xA31QGf79WzpG/ixT9FZvQlh5HY1NRqSHBNOCk= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21/go.mod h1:JNr43NFf5L9YaG3eKTm7HQzls9J+A9YYcGI5Quh1r2Y= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21 h1:6jZVETqmYCadGFvrYEQfC5fAQmlo80CeL5psbno6r0s= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21/go.mod h1:1SR0GbLlnN3QUmYaflZNiH1ql+1qrSiB2vwcJ+4UM60= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.18 h1:OWYvKL53l1rbsUmW7bQyJVsYU/Ii3bbAAQIIFNbM0Tk= @@ -751,6 +751,8 @@ github.com/aws/aws-sdk-go-v2/service/glue v1.99.2 h1:pfX1qky3shRS3rgxkdXKtiNWtMU github.com/aws/aws-sdk-go-v2/service/glue v1.99.2/go.mod h1:rCyUHLWGaSR9/oQgj2nGKRmPqFwtq3qxL14LkuQdadA= github.com/aws/aws-sdk-go-v2/service/iam v1.36.3 h1:dV9iimLEHKYAz2qTi+tGAD9QCnAG2pLD7HUEHB7m4mI= github.com/aws/aws-sdk-go-v2/service/iam v1.36.3/go.mod h1:HSvujsK8xeEHMIB18oMXjSfqaN9cVqpo/MtHJIksQRk= +github.com/aws/aws-sdk-go-v2/service/identitystore v1.27.2 h1:QSrf6HsounqUtlFAwArhVNHPt3WXmSm0pz7RtojjBdo= +github.com/aws/aws-sdk-go-v2/service/identitystore v1.27.2/go.mod h1:PtkL4CXOQy84zudggyFtyJFXCGDRY8igg9Nfo9df1sU= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.5 h1:QFASJGfT8wMXtuP3D5CRmMjARHv9ZmzFUMJznHDOY3w= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.5/go.mod h1:QdZ3OmoIjSX+8D1OPAzPxDfjXASbBMDsz9qvtyIhtik= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.20 h1:rTWjG6AvWekO2B1LHeM3ktU7MqyX9rzWQ7hgzneZW7E= @@ -761,6 +763,8 @@ github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.18 h1:eb+tFOIl9ZsUe github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.18/go.mod h1:GVCC2IJNJTmdlyEsSmofEy7EfJncP7DNnXDzRjJ5Keg= github.com/aws/aws-sdk-go-v2/service/kms v1.36.3 h1:iHi6lC6LfW6SNvB2bixmlOW3WMyWFrHZCWX+P+CCxMk= github.com/aws/aws-sdk-go-v2/service/kms v1.36.3/go.mod h1:OHmlX4+o0XIlJAQGAHPIy0N9yZcYS/vNG+T7geSNcFw= +github.com/aws/aws-sdk-go-v2/service/organizations v1.34.2 h1:ndH1E8olS/rDB+tiUMKj09g0o11PoOLAC+xRFB13bJw= +github.com/aws/aws-sdk-go-v2/service/organizations v1.34.2/go.mod h1:YZvv/wXIgIviYq9P/fQDhoMlzlI89M0D45GnYvIorLk= github.com/aws/aws-sdk-go-v2/service/rds v1.85.2 h1:KDO/FSO8V+zlvnQF6v4nOariw2qwPx5/z2pyb6X7ibk= github.com/aws/aws-sdk-go-v2/service/rds v1.85.2/go.mod h1:lhiPj6RvoJHWG2STp+k5az55YqGgFLBzkKYdYHgUh9g= github.com/aws/aws-sdk-go-v2/service/s3 v1.63.3 h1:3zt8qqznMuAZWDTDpcwv9Xr11M/lVj2FsRR7oYBt0OA= @@ -769,12 +773,14 @@ github.com/aws/aws-sdk-go-v2/service/ssm v1.54.3 h1:Ctzev3ppcc46m2FgrLEZhsHMEr1G github.com/aws/aws-sdk-go-v2/service/ssm v1.54.3/go.mod h1:qs3TBNpFEnVubl0WL3jruj7NJMF1RCAPEPQ1f+fLTBE= github.com/aws/aws-sdk-go-v2/service/sso v1.23.3 h1:rs4JCczF805+FDv2tRhZ1NU0RB2H6ryAvsWPanAr72Y= github.com/aws/aws-sdk-go-v2/service/sso v1.23.3/go.mod h1:XRlMvmad0ZNL+75C5FYdMvbbLkd6qiqz6foR1nA1PXY= +github.com/aws/aws-sdk-go-v2/service/ssoadmin v1.29.2 h1:O6MhOmqKN1dSmc04jaxmfdmSb3UbeQ715SYdVzNBiL4= +github.com/aws/aws-sdk-go-v2/service/ssoadmin v1.29.2/go.mod h1:QkSUZzFJsxztercu38+HLsTz9kHqRvAhVwp9+6SAeFA= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.27.3 h1:S7EPdMVZod8BGKQQPTBK+FcX9g7bKR7c4+HxWqHP7Vg= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.27.3/go.mod h1:FnvDM4sfa+isJ3kDXIzAB9GAwVSzFzSy97uZ3IsHo4E= github.com/aws/aws-sdk-go-v2/service/sts v1.31.3 h1:VzudTFrDCIDakXtemR7l6Qzt2+JYsVqo2MxBPt5k8T8= github.com/aws/aws-sdk-go-v2/service/sts v1.31.3/go.mod h1:yMWe0F+XG0DkRZK5ODZhG7BEFYhLXi2dqGsv6tX0cgI= -github.com/aws/smithy-go v1.21.0 h1:H7L8dtDRk0P1Qm6y0ji7MCYMQObJ5R9CRpyPhRUkLYA= -github.com/aws/smithy-go v1.21.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= +github.com/aws/smithy-go v1.22.0 h1:uunKnWlcoL3zO7q+gG2Pk53joueEOsnNB28QdMsmiMM= +github.com/aws/smithy-go v1.22.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/beevik/etree v1.4.1 h1:PmQJDDYahBGNKDcpdX8uPy1xRCwoCGVUiW669MEirVI= github.com/beevik/etree v1.4.1/go.mod h1:gPNJNaBGVZ9AwsidazFZyygnd+0pAU38N4D+WemwKNs= diff --git a/integrations/terraform/go.mod b/integrations/terraform/go.mod index ee81e1b7d054c..11a8a22127c90 100644 --- a/integrations/terraform/go.mod +++ b/integrations/terraform/go.mod @@ -76,14 +76,14 @@ require ( github.com/armon/go-radix v1.0.0 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/aws/aws-sdk-go v1.55.5 // indirect - github.com/aws/aws-sdk-go-v2 v1.31.0 // indirect + github.com/aws/aws-sdk-go-v2 v1.32.2 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.5 // indirect github.com/aws/aws-sdk-go-v2/config v1.27.39 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.17.37 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.14 // indirect github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.25 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.18 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.18 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.18 // indirect github.com/aws/aws-sdk-go-v2/service/athena v1.46.2 // indirect @@ -93,18 +93,21 @@ require ( github.com/aws/aws-sdk-go-v2/service/eks v1.49.3 // indirect github.com/aws/aws-sdk-go-v2/service/glue v1.99.2 // indirect github.com/aws/aws-sdk-go-v2/service/iam v1.36.3 // indirect + github.com/aws/aws-sdk-go-v2/service/identitystore v1.27.2 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.5 // indirect github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.20 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.20 // indirect github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.18 // indirect github.com/aws/aws-sdk-go-v2/service/kms v1.36.3 // indirect + github.com/aws/aws-sdk-go-v2/service/organizations v1.34.2 // indirect github.com/aws/aws-sdk-go-v2/service/rds v1.85.2 // indirect github.com/aws/aws-sdk-go-v2/service/s3 v1.63.3 // indirect github.com/aws/aws-sdk-go-v2/service/ssm v1.54.3 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.23.3 // indirect + github.com/aws/aws-sdk-go-v2/service/ssoadmin v1.29.2 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.27.3 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.31.3 // indirect - github.com/aws/smithy-go v1.21.0 // indirect + github.com/aws/smithy-go v1.22.0 // indirect github.com/beevik/etree v1.4.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.0 // indirect diff --git a/integrations/terraform/go.sum b/integrations/terraform/go.sum index 43d9ce09ebd55..85c86c5aad347 100644 --- a/integrations/terraform/go.sum +++ b/integrations/terraform/go.sum @@ -774,8 +774,8 @@ github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3A github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU= github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= -github.com/aws/aws-sdk-go-v2 v1.31.0 h1:3V05LbxTSItI5kUqNwhJrrrY1BAXxXt0sN0l72QmG5U= -github.com/aws/aws-sdk-go-v2 v1.31.0/go.mod h1:ztolYtaEUtdpf9Wftr31CJfLVjOnD/CVRkKOOYgF8hA= +github.com/aws/aws-sdk-go-v2 v1.32.2 h1:AkNLZEyYMLnx/Q/mSKkcMqwNFXMAvFto9bNsHqcTduI= +github.com/aws/aws-sdk-go-v2 v1.32.2/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.5 h1:xDAuZTn4IMm8o1LnBZvmrL8JA1io4o3YWNXgohbf20g= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.5/go.mod h1:wYSv6iDS621sEFLfKvpPE2ugjTuGlAG7iROg0hLOkfc= github.com/aws/aws-sdk-go-v2/config v1.27.39 h1:FCylu78eTGzW1ynHcongXK9YHtoXD5AiiUqq3YfJYjU= @@ -790,10 +790,10 @@ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.14 h1:C/d03NAmh8C4BZXhuRNboF github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.14/go.mod h1:7I0Ju7p9mCIdlrfS+JCgqcYD0VXz/N4yozsox+0o078= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.25 h1:HkpHeZMM39sGtMHVYG1buAg93vhj5d7F81y6G0OAbGc= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.25/go.mod h1:j3Vz04ZjaWA6kygOsZRpmWe4CyGqfqq2u3unDTU0QGA= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.18 h1:kYQ3H1u0ANr9KEKlGs/jTLrBFPo8P8NaH/w7A01NeeM= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.18/go.mod h1:r506HmK5JDUh9+Mw4CfGJGSSoqIiLCndAuqXuhbv67Y= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.18 h1:Z7IdFUONvTcvS7YuhtVxN99v2cCoHRXOS4mTr0B/pUc= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.18/go.mod h1:DkKMmksZVVyat+Y+r1dEOgJEfUeA7UngIHWeKsi0yNc= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21 h1:UAsR3xA31QGf79WzpG/ixT9FZvQlh5HY1NRqSHBNOCk= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21/go.mod h1:JNr43NFf5L9YaG3eKTm7HQzls9J+A9YYcGI5Quh1r2Y= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21 h1:6jZVETqmYCadGFvrYEQfC5fAQmlo80CeL5psbno6r0s= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21/go.mod h1:1SR0GbLlnN3QUmYaflZNiH1ql+1qrSiB2vwcJ+4UM60= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.18 h1:OWYvKL53l1rbsUmW7bQyJVsYU/Ii3bbAAQIIFNbM0Tk= @@ -818,6 +818,8 @@ github.com/aws/aws-sdk-go-v2/service/glue v1.99.2 h1:pfX1qky3shRS3rgxkdXKtiNWtMU github.com/aws/aws-sdk-go-v2/service/glue v1.99.2/go.mod h1:rCyUHLWGaSR9/oQgj2nGKRmPqFwtq3qxL14LkuQdadA= github.com/aws/aws-sdk-go-v2/service/iam v1.36.3 h1:dV9iimLEHKYAz2qTi+tGAD9QCnAG2pLD7HUEHB7m4mI= github.com/aws/aws-sdk-go-v2/service/iam v1.36.3/go.mod h1:HSvujsK8xeEHMIB18oMXjSfqaN9cVqpo/MtHJIksQRk= +github.com/aws/aws-sdk-go-v2/service/identitystore v1.27.2 h1:QSrf6HsounqUtlFAwArhVNHPt3WXmSm0pz7RtojjBdo= +github.com/aws/aws-sdk-go-v2/service/identitystore v1.27.2/go.mod h1:PtkL4CXOQy84zudggyFtyJFXCGDRY8igg9Nfo9df1sU= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.5 h1:QFASJGfT8wMXtuP3D5CRmMjARHv9ZmzFUMJznHDOY3w= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.5/go.mod h1:QdZ3OmoIjSX+8D1OPAzPxDfjXASbBMDsz9qvtyIhtik= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.20 h1:rTWjG6AvWekO2B1LHeM3ktU7MqyX9rzWQ7hgzneZW7E= @@ -830,6 +832,8 @@ github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.18 h1:eb+tFOIl9ZsUe github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.18/go.mod h1:GVCC2IJNJTmdlyEsSmofEy7EfJncP7DNnXDzRjJ5Keg= github.com/aws/aws-sdk-go-v2/service/kms v1.36.3 h1:iHi6lC6LfW6SNvB2bixmlOW3WMyWFrHZCWX+P+CCxMk= github.com/aws/aws-sdk-go-v2/service/kms v1.36.3/go.mod h1:OHmlX4+o0XIlJAQGAHPIy0N9yZcYS/vNG+T7geSNcFw= +github.com/aws/aws-sdk-go-v2/service/organizations v1.34.2 h1:ndH1E8olS/rDB+tiUMKj09g0o11PoOLAC+xRFB13bJw= +github.com/aws/aws-sdk-go-v2/service/organizations v1.34.2/go.mod h1:YZvv/wXIgIviYq9P/fQDhoMlzlI89M0D45GnYvIorLk= github.com/aws/aws-sdk-go-v2/service/rds v1.85.2 h1:KDO/FSO8V+zlvnQF6v4nOariw2qwPx5/z2pyb6X7ibk= github.com/aws/aws-sdk-go-v2/service/rds v1.85.2/go.mod h1:lhiPj6RvoJHWG2STp+k5az55YqGgFLBzkKYdYHgUh9g= github.com/aws/aws-sdk-go-v2/service/s3 v1.63.3 h1:3zt8qqznMuAZWDTDpcwv9Xr11M/lVj2FsRR7oYBt0OA= @@ -842,14 +846,16 @@ github.com/aws/aws-sdk-go-v2/service/ssm v1.54.3 h1:Ctzev3ppcc46m2FgrLEZhsHMEr1G github.com/aws/aws-sdk-go-v2/service/ssm v1.54.3/go.mod h1:qs3TBNpFEnVubl0WL3jruj7NJMF1RCAPEPQ1f+fLTBE= github.com/aws/aws-sdk-go-v2/service/sso v1.23.3 h1:rs4JCczF805+FDv2tRhZ1NU0RB2H6ryAvsWPanAr72Y= github.com/aws/aws-sdk-go-v2/service/sso v1.23.3/go.mod h1:XRlMvmad0ZNL+75C5FYdMvbbLkd6qiqz6foR1nA1PXY= +github.com/aws/aws-sdk-go-v2/service/ssoadmin v1.29.2 h1:O6MhOmqKN1dSmc04jaxmfdmSb3UbeQ715SYdVzNBiL4= +github.com/aws/aws-sdk-go-v2/service/ssoadmin v1.29.2/go.mod h1:QkSUZzFJsxztercu38+HLsTz9kHqRvAhVwp9+6SAeFA= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.27.3 h1:S7EPdMVZod8BGKQQPTBK+FcX9g7bKR7c4+HxWqHP7Vg= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.27.3/go.mod h1:FnvDM4sfa+isJ3kDXIzAB9GAwVSzFzSy97uZ3IsHo4E= github.com/aws/aws-sdk-go-v2/service/sts v1.31.3 h1:VzudTFrDCIDakXtemR7l6Qzt2+JYsVqo2MxBPt5k8T8= github.com/aws/aws-sdk-go-v2/service/sts v1.31.3/go.mod h1:yMWe0F+XG0DkRZK5ODZhG7BEFYhLXi2dqGsv6tX0cgI= github.com/aws/aws-sigv4-auth-cassandra-gocql-driver-plugin v1.1.0 h1:EJsHUYgFBV7/N1YtL73lsfZODAOU+CnNSZfEAlqqQaA= github.com/aws/aws-sigv4-auth-cassandra-gocql-driver-plugin v1.1.0/go.mod h1:AxKuXHc0zv2yYaeueUG7R3ONbcnQIuDj0bkdFmPVRzU= -github.com/aws/smithy-go v1.21.0 h1:H7L8dtDRk0P1Qm6y0ji7MCYMQObJ5R9CRpyPhRUkLYA= -github.com/aws/smithy-go v1.21.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= +github.com/aws/smithy-go v1.22.0 h1:uunKnWlcoL3zO7q+gG2Pk53joueEOsnNB28QdMsmiMM= +github.com/aws/smithy-go v1.22.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/beevik/etree v1.4.1 h1:PmQJDDYahBGNKDcpdX8uPy1xRCwoCGVUiW669MEirVI= github.com/beevik/etree v1.4.1/go.mod h1:gPNJNaBGVZ9AwsidazFZyygnd+0pAU38N4D+WemwKNs= diff --git a/lib/integrations/awsoidc/credentialscache.go b/lib/integrations/awsoidc/credentialscache.go new file mode 100644 index 0000000000000..1d1ddffe3bf1c --- /dev/null +++ b/lib/integrations/awsoidc/credentialscache.go @@ -0,0 +1,284 @@ +// Teleport +// Copyright (C) 2024 Gravitational, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package awsoidc + +import ( + "context" + "errors" + "log/slog" + "sync" + "time" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/arn" + "github.com/aws/aws-sdk-go-v2/credentials/stscreds" + "github.com/gravitational/trace" + "github.com/jonboulle/clockwork" + + "github.com/gravitational/teleport" +) + +const ( + // TokenLifetime is the lifetime of OIDC tokens used by the + // ExternalAuditStorage service with the AWS OIDC integration. + TokenLifetime = time.Hour + + refreshBeforeExpirationPeriod = 15 * time.Minute + refreshCheckInterval = 30 * time.Second + retrieveTimeout = 30 * time.Second +) + +// GenerateOIDCTokenFn is a function that should return a valid, signed JWT for +// authenticating to AWS via OIDC. +type GenerateOIDCTokenFn func(ctx context.Context, integration string) (string, error) + +type credsOrErr struct { + creds aws.Credentials + err error +} + +// CredentialsCache is used to store and refresh AWS credentials used with +// AWS OIDC integration. +// +// Credentials are valid for 1h, but they cannot be refreshed if Proxy is down, +// so we attempt to refresh the credentials early and retry on failure. +type CredentialsCache struct { + log *slog.Logger + + roleARN arn.ARN + integration string + + // generateOIDCTokenFn is dynamically set after auth is initialized. + generateOIDCTokenFn GenerateOIDCTokenFn + + // initialized communicates (via closing channel) that generateOIDCTokenFn is set. + initialized chan struct{} + closeInitialized func() + + // gotFirstCredsOrErr communicates (via closing channel) that the first + // credsOrErr has been set. + gotFirstCredsOrErr chan struct{} + closeGotFirstCredsOrErr func() + + credsOrErr credsOrErr + credsOrErrMu sync.RWMutex + + stsClient stscreds.AssumeRoleWithWebIdentityAPIClient + clock clockwork.Clock +} + +type CredentialsCacheOptions struct { + // Integration is the name of the Teleport OIDC integration to use + Integration string + + // RoleARN is the ARN of the role to assume once authenticated + RoleARN arn.ARN + + // STSClient is the AWS sts client implementation to use when communicating + // with AWS + STSClient stscreds.AssumeRoleWithWebIdentityAPIClient + + // Log is the logger to use. A default will be supplied if no logger is + // explicitly set + Log *slog.Logger + + // Clock is the clock to use. A default system clock will be provided if + // none is supplied. + Clock clockwork.Clock +} + +func (opts *CredentialsCacheOptions) CheckAndSetDefaults() error { + if opts.STSClient == nil { + return trace.BadParameter("stsClient must be provided") + } + + if opts.Log == nil { + opts.Log = slog.Default().With(teleport.ComponentKey, "AWS-OIDC-CredentialCache") + } + + if opts.Clock == nil { + opts.Clock = clockwork.NewRealClock() + } + + return nil +} + +var errNotReady = errors.New("ExternalAuditStorage: credential cache not yet initialized") + +func NewCredentialsCache(options CredentialsCacheOptions) (*CredentialsCache, error) { + if err := options.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err, "creating credentials cache") + } + + initialized := make(chan struct{}) + gotFirstCredsOrErr := make(chan struct{}) + + return &CredentialsCache{ + roleARN: options.RoleARN, + integration: options.Integration, + log: options.Log.With("integration", options.Integration), + initialized: initialized, + closeInitialized: sync.OnceFunc(func() { close(initialized) }), + gotFirstCredsOrErr: gotFirstCredsOrErr, + closeGotFirstCredsOrErr: sync.OnceFunc(func() { close(gotFirstCredsOrErr) }), + credsOrErr: credsOrErr{err: errNotReady}, + clock: options.Clock, + stsClient: options.STSClient, + }, nil +} + +func (cc *CredentialsCache) SetGenerateOIDCTokenFn(fn GenerateOIDCTokenFn) { + cc.generateOIDCTokenFn = fn + cc.closeInitialized() +} + +// Retrieve implements [aws.CredentialsProvider] and returns the latest cached +// credentials, or an error if no credentials have been generated yet or the +// last generated credentials have expired. +func (cc *CredentialsCache) Retrieve(ctx context.Context) (aws.Credentials, error) { + cc.credsOrErrMu.RLock() + defer cc.credsOrErrMu.RUnlock() + + if cc.credsOrErr.err != nil { + cc.log.WarnContext(ctx, "Returning error to AWS client", errorValue(cc.credsOrErr.err)) + } + + return cc.credsOrErr.creds, cc.credsOrErr.err +} + +func (cc *CredentialsCache) Run(ctx context.Context) { + // Wait for initialized signal before running loop. + select { + case <-cc.initialized: + case <-ctx.Done(): + cc.log.DebugContext(ctx, "Context canceled before initialized.") + return + } + + cc.refreshIfNeeded(ctx) + + ticker := cc.clock.NewTicker(refreshCheckInterval) + defer ticker.Stop() + for { + select { + case <-ticker.Chan(): + cc.refreshIfNeeded(ctx) + case <-ctx.Done(): + cc.log.DebugContext(ctx, "Context canceled, stopping refresh loop.") + return + } + } +} + +func (cc *CredentialsCache) refreshIfNeeded(ctx context.Context) { + credsFromCache, err := cc.Retrieve(ctx) + if err == nil && + credsFromCache.HasKeys() && + cc.clock.Now().Add(refreshBeforeExpirationPeriod).Before(credsFromCache.Expires) { + // No need to refresh, credentials in cache are still valid for longer + // than refreshBeforeExpirationPeriod + return + } + cc.log.DebugContext(ctx, "Refreshing credentials.") + + creds, err := cc.refresh(ctx) + if err != nil { + cc.log.WarnContext(ctx, "Failed to retrieve new credentials", errorValue(err)) + now := cc.clock.Now() + // If we were not able to refresh, check if existing credentials in + // cache are still valid. If yes, just log debug, it will be retried on + // next interval check. + if credsFromCache.HasKeys() && now.Before(credsFromCache.Expires) { + cc.log.DebugContext(ctx, "Continuing to use existing credentials", + slog.Duration( + "ttl", + credsFromCache.Expires.Sub(now).Round(time.Second))) + return + } + // If existing creds are expired, update cached error. + cc.log.ErrorContext(ctx, "Setting cached error", "error", err) + cc.setCredsOrErr(credsOrErr{err: trace.Wrap(err)}) + return + } + + // Refresh went well, update cached creds. + cc.setCredsOrErr(credsOrErr{creds: creds}) + cc.log.DebugContext(ctx, "Successfully refreshed credentials", + slog.Time("expires", creds.Expires)) +} + +func (cc *CredentialsCache) setCredsOrErr(coe credsOrErr) { + cc.credsOrErrMu.Lock() + defer cc.credsOrErrMu.Unlock() + cc.credsOrErr = coe + cc.closeGotFirstCredsOrErr() +} + +func (cc *CredentialsCache) refresh(ctx context.Context) (aws.Credentials, error) { + cc.log.InfoContext(ctx, "Refreshing AWS credentials") + defer cc.log.InfoContext(ctx, "Exiting AWS credentials refresh") + + cc.log.InfoContext(ctx, "Generating Token") + oidcToken, err := cc.generateOIDCTokenFn(ctx, cc.integration) + if err != nil { + cc.log.ErrorContext(ctx, "Token generation failed", errorValue(err)) + return aws.Credentials{}, trace.Wrap(err) + } + + roleProvider := stscreds.NewWebIdentityRoleProvider( + cc.stsClient, + cc.roleARN.String(), + identityToken(oidcToken), + func(wiro *stscreds.WebIdentityRoleOptions) { + wiro.Duration = TokenLifetime + }, + ) + + ctx, cancel := context.WithTimeout(ctx, retrieveTimeout) + defer cancel() + + cc.log.InfoContext(ctx, "Retrieving AWS role credentials") + + creds, err := roleProvider.Retrieve(ctx) + if err != nil { + cc.log.ErrorContext(ctx, "Role retrieval failed", errorValue(err)) + } + + return creds, trace.Wrap(err) +} + +func (cc *CredentialsCache) WaitForFirstCredsOrErr(ctx context.Context) { + cc.log.InfoContext(ctx, "Entering wait on first credential refresh") + defer cc.log.InfoContext(ctx, "Exiting wait on first credential refresh") + + select { + case <-ctx.Done(): + case <-cc.gotFirstCredsOrErr: + } +} + +// identityToken is an implementation of [stscreds.IdentityTokenRetriever] for returning a static token. +type identityToken string + +// GetIdentityToken returns the token configured. +func (j identityToken) GetIdentityToken() ([]byte, error) { + return []byte(j), nil +} + +func errorValue(v error) slog.Attr { + return slog.Any("error", v) +} diff --git a/lib/integrations/awsoidc/credentialscache_test.go b/lib/integrations/awsoidc/credentialscache_test.go new file mode 100644 index 0000000000000..cc997758f70be --- /dev/null +++ b/lib/integrations/awsoidc/credentialscache_test.go @@ -0,0 +1,226 @@ +// Teleport +// Copyright (C) 2024 Gravitational, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package awsoidc + +import ( + "context" + "errors" + "sync" + "testing" + "time" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/sts" + ststypes "github.com/aws/aws-sdk-go-v2/service/sts/types" + "github.com/google/uuid" + "github.com/jonboulle/clockwork" + "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/gravitational/teleport/entitlements" + "github.com/gravitational/teleport/lib/modules" +) + +type fakeSTSClient struct { + clock clockwork.Clock + err error + sync.Mutex +} + +func (f *fakeSTSClient) setError(err error) { + f.Lock() + f.err = err + f.Unlock() +} + +func (f *fakeSTSClient) getError() error { + f.Lock() + defer f.Unlock() + return f.err +} + +func (f *fakeSTSClient) AssumeRoleWithWebIdentity(ctx context.Context, params *sts.AssumeRoleWithWebIdentityInput, optFns ...func(*sts.Options)) (*sts.AssumeRoleWithWebIdentityOutput, error) { + if err := f.getError(); err != nil { + return nil, err + } + + expiration := f.clock.Now().Add(time.Second * time.Duration(*params.DurationSeconds)) + return &sts.AssumeRoleWithWebIdentityOutput{ + Credentials: &ststypes.Credentials{ + Expiration: &expiration, + // These are example values taken from https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html + SessionToken: aws.String("AQoDYXdzEE0a8ANXXXXXXXXNO1ewxE5TijQyp+IEXAMPLE"), + SecretAccessKey: aws.String("wJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY"), + AccessKeyId: aws.String("ASgeIAIOSFODNN7EXAMPLE"), + }, + }, nil +} + +func TestCredentialsCache(t *testing.T) { + logrus.SetLevel(logrus.DebugLevel) + + ctx, cancel := context.WithCancel(context.Background()) + t.Cleanup(cancel) + + modules.SetTestModules(t, &modules.TestModules{ + TestFeatures: modules.Features{ + Cloud: true, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.ExternalAuditStorage: {Enabled: true}, + }, + }, + }) + + // GIVEN a configured and running credential cache... + clock := clockwork.NewFakeClock() + stsClient := &fakeSTSClient{ + clock: clock, + } + cacheUnderTest, err := NewCredentialsCache(CredentialsCacheOptions{ + STSClient: stsClient, + Integration: "test", + Clock: clock, + }) + require.NoError(t, err) + require.NotNil(t, cacheUnderTest) + go cacheUnderTest.Run(ctx) + + advanceClock := func(d time.Duration) { + // Wait for the run loop to actually wait on the clock ticker before advancing. If we advance before + // the loop waits on the ticker, it may never tick. + clock.BlockUntil(1) + clock.Advance(d) + } + + // Set the GenerateOIDCTokenFn to a dumb faked function. + cacheUnderTest.SetGenerateOIDCTokenFn( + func(ctx context.Context, integration string) (string, error) { + return uuid.NewString(), nil + }) + + checkRetrieveCredentials := func(t require.TestingT, expectErr error) { + _, err := cacheUnderTest.Retrieve(ctx) + assert.ErrorIs(t, err, expectErr) + } + + checkRetrieveCredentialsWithExpiry := func(t require.TestingT, expectExpiry time.Time) { + creds, err := cacheUnderTest.Retrieve(ctx) + assert.NoError(t, err) + if err == nil { + assert.WithinDuration(t, expectExpiry, creds.Expires, time.Minute) + } + } + + const ( + // Using a longer wait time to avoid test flakes observed with 1s wait. + waitFor = 10 * time.Second + // We're using a short sleep (1ms) to allow the refresh loop goroutine to get scheduled. + // This keeps the test fast under normal conditions. If there's CPU starvation in CI, + // neither the test goroutine nor the refresh loop are likely getting scheduled often, + // so this shouldn't result in a busy loop. + tick = 1 * time.Millisecond + ) + + t.Run("Retrieve", func(t *testing.T) { + // Assert that credentials can be retrieved when everything is happy. + // EventuallyWithT is necessary to allow credentialsCache.run to be + // scheduled after SetGenerateOIDCTokenFn above. + initialCredentialExpiry := clock.Now().Add(TokenLifetime) + require.EventuallyWithT(t, func(t *assert.CollectT) { + checkRetrieveCredentialsWithExpiry(t, initialCredentialExpiry) + }, waitFor, tick) + }) + + t.Run("CachedCredsArePreservedOnError", func(t *testing.T) { + initialCredentialExpiry := clock.Now().Add(TokenLifetime) + require.EventuallyWithT(t, func(t *assert.CollectT) { + checkRetrieveCredentialsWithExpiry(t, initialCredentialExpiry) + }, waitFor, tick) + + // Assert that the good cached credentials are still used even if sts starts + // returning errors. + stsError := errors.New("test error") + stsClient.setError(stsError) + // Test immediately + checkRetrieveCredentialsWithExpiry(t, initialCredentialExpiry) + // Advance to 1 minute before first refresh attempt + advanceClock(TokenLifetime - refreshBeforeExpirationPeriod - time.Minute) + checkRetrieveCredentialsWithExpiry(t, initialCredentialExpiry) + // Advance to 1 minute after first refresh attempt + advanceClock(2 * time.Minute) + checkRetrieveCredentialsWithExpiry(t, initialCredentialExpiry) + // Advance to 1 minute before credential expiry + advanceClock(refreshBeforeExpirationPeriod - 2*time.Minute) + checkRetrieveCredentialsWithExpiry(t, initialCredentialExpiry) + + // Advance 1 minute past the credential expiry and make sure we get the + // expected error. + advanceClock(2 * time.Minute) + require.EventuallyWithT(t, func(t *assert.CollectT) { + checkRetrieveCredentials(t, stsError) + }, waitFor, tick) + + // Fix STS and make sure we stop getting errors within refreshCheckInterval + stsClient.setError(nil) + advanceClock(refreshCheckInterval) + newCredentialExpiry := clock.Now().Add(TokenLifetime) + require.EventuallyWithT(t, func(t *assert.CollectT) { + checkRetrieveCredentialsWithExpiry(t, newCredentialExpiry) + }, waitFor, tick) + }) + + t.Run("WindowedErrors", func(t *testing.T) { + // Test a scenario where STS is returning errors in two different 10-minute windows: the first surrounding + // the expected cert refresh time, and the second surrounding the cert expiry time. + // In this case the credentials cache should refresh the certs somewhere between those two outages, and + // clients should never see an error retrieving credentials. + newCredentialExpiry := clock.Now().Add(TokenLifetime) + expectedRefreshTime := newCredentialExpiry.Add(-refreshBeforeExpirationPeriod) + credentialsUpdated := false + done := newCredentialExpiry.Add(10 * time.Minute) + stsError := errors.New("test error") + for clock.Now().Before(done) { + if clock.Now().Sub(expectedRefreshTime).Abs() < 5*time.Minute || + clock.Now().Sub(newCredentialExpiry).Abs() < 5*time.Minute { + // Within one of the 10-minute outage windows, make the STS client return errors. + stsClient.setError(stsError) + advanceClock(time.Minute) + } else { + // Not within an outage window, STS client should not return errors. + stsClient.setError(nil) + advanceClock(time.Minute) + + if !credentialsUpdated && clock.Now().After(expectedRefreshTime) { + // This is after the expected refresh time and not within an outage window, for the test to + // not be flaky we need to wait for the cache run loop to get a chance to refresh the + // credentials. + expectedExpiry := clock.Now().Add(TokenLifetime) + require.EventuallyWithT(t, func(t *assert.CollectT) { + creds, err := cacheUnderTest.Retrieve(ctx) + assert.NoError(t, err) + assert.WithinDuration(t, expectedExpiry, creds.Expires, 2*time.Minute) + }, waitFor, tick) + credentialsUpdated = true + } + } + + // Assert that there is never an error getting credentials. + checkRetrieveCredentials(t, nil) + } + }) +} diff --git a/lib/integrations/externalauditstorage/configurator.go b/lib/integrations/externalauditstorage/configurator.go index 050298f9e13e0..66cea204a57cc 100644 --- a/lib/integrations/externalauditstorage/configurator.go +++ b/lib/integrations/externalauditstorage/configurator.go @@ -20,23 +20,21 @@ package externalauditstorage import ( "context" - "errors" - "sync" "time" "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/arn" "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/credentials/stscreds" "github.com/aws/aws-sdk-go-v2/service/sts" "github.com/aws/aws-sdk-go/aws/credentials" "github.com/gravitational/trace" "github.com/jonboulle/clockwork" - "github.com/sirupsen/logrus" - "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/types/externalauditstorage" "github.com/gravitational/teleport/entitlements" + "github.com/gravitational/teleport/lib/integrations/awsoidc" "github.com/gravitational/teleport/lib/modules" "github.com/gravitational/teleport/lib/services" ) @@ -86,7 +84,7 @@ type Configurator struct { spec *externalauditstorage.ExternalAuditStorageSpec isUsed bool - credentialsCache *credentialsCache + credentialsCache *awsoidc.CredentialsCache } // Options holds options for the Configurator. @@ -202,7 +200,10 @@ func newConfigurator(ctx context.Context, spec *externalauditstorage.ExternalAud "ExternalAuditStorage: configured integration %q does not appear to be an AWS OIDC integration", oidcIntegrationName) } - awsRoleARN := awsOIDCSpec.RoleARN + awsRoleARN, err := arn.Parse(awsOIDCSpec.RoleARN) + if err != nil { + return nil, trace.Wrap(err, "AWS role is not a valid ARN") + } options := &Options{} for _, optFn := range optFns { @@ -212,11 +213,16 @@ func newConfigurator(ctx context.Context, spec *externalauditstorage.ExternalAud return nil, trace.Wrap(err) } - credentialsCache, err := newCredentialsCache(oidcIntegrationName, awsRoleARN, options) + credentialsCache, err := awsoidc.NewCredentialsCache(awsoidc.CredentialsCacheOptions{ + Integration: oidcIntegrationName, + RoleARN: awsRoleARN, + STSClient: options.stsClient, + Clock: options.clock, + }) if err != nil { return nil, trace.Wrap(err) } - go credentialsCache.run(ctx) + go credentialsCache.Run(ctx) // Draft configurator does not need to count errors or create cluster // alerts. @@ -245,13 +251,9 @@ func (c *Configurator) GetSpec() *externalauditstorage.ExternalAuditStorageSpec return c.spec } -// GenerateOIDCTokenFn is a function that should return a valid, signed JWT for -// authenticating to AWS via OIDC. -type GenerateOIDCTokenFn func(ctx context.Context, integration string) (string, error) - // SetGenerateOIDCTokenFn sets the source of OIDC tokens for this Configurator. -func (c *Configurator) SetGenerateOIDCTokenFn(fn GenerateOIDCTokenFn) { - c.credentialsCache.setGenerateOIDCTokenFn(fn) +func (c *Configurator) SetGenerateOIDCTokenFn(fn awsoidc.GenerateOIDCTokenFn) { + c.credentialsCache.SetGenerateOIDCTokenFn(fn) } // CredentialsProvider returns an aws.CredentialsProvider that can be used to @@ -274,185 +276,13 @@ func (p *Configurator) CredentialsProviderSDKV1() credentials.ProviderWithContex // credential providers won't return errors simply due to the cache not being // ready yet. func (p *Configurator) WaitForFirstCredentials(ctx context.Context) { - p.credentialsCache.waitForFirstCredsOrErr(ctx) -} - -// credentialsCache is used to store and refresh AWS credentials used with -// AWS OIDC integration. -// -// Credentials are valid for 1h, but they cannot be refreshed if Proxy is down, -// so we attempt to refresh the credentials early and retry on failure. -// -// credentialsCache is a dependency to both the s3 session uploader and the -// athena audit logger. They are both initialized before auth. However AWS -// credentials using OIDC integration can be obtained only after auth is -// initialized. That's why generateOIDCTokenFn is injected dynamically after -// auth is initialized. Before initialization, credentialsCache will return -// an error on any Retrieve call. -type credentialsCache struct { - log *logrus.Entry - - roleARN string - integration string - - // generateOIDCTokenFn is dynamically set after auth is initialized. - generateOIDCTokenFn GenerateOIDCTokenFn - - // initialized communicates (via closing channel) that generateOIDCTokenFn is set. - initialized chan struct{} - closeInitialized func() - - // gotFirstCredsOrErr communicates (via closing channel) that the first - // credsOrErr has been set. - gotFirstCredsOrErr chan struct{} - closeGotFirstCredsOrErr func() - - credsOrErr credsOrErr - credsOrErrMu sync.RWMutex - - stsClient stscreds.AssumeRoleWithWebIdentityAPIClient - clock clockwork.Clock -} - -type credsOrErr struct { - creds aws.Credentials - err error -} - -func newCredentialsCache(integration, roleARN string, options *Options) (*credentialsCache, error) { - initialized := make(chan struct{}) - gotFirstCredsOrErr := make(chan struct{}) - return &credentialsCache{ - roleARN: roleARN, - integration: integration, - log: logrus.WithField(teleport.ComponentKey, "ExternalAuditStorage.CredentialsCache"), - initialized: initialized, - closeInitialized: sync.OnceFunc(func() { close(initialized) }), - gotFirstCredsOrErr: gotFirstCredsOrErr, - closeGotFirstCredsOrErr: sync.OnceFunc(func() { close(gotFirstCredsOrErr) }), - credsOrErr: credsOrErr{ - err: errors.New("ExternalAuditStorage: credential cache not yet initialized"), - }, - clock: options.clock, - stsClient: options.stsClient, - }, nil -} - -func (cc *credentialsCache) setGenerateOIDCTokenFn(fn GenerateOIDCTokenFn) { - cc.generateOIDCTokenFn = fn - cc.closeInitialized() -} - -// Retrieve implements [aws.CredentialsProvider] and returns the latest cached -// credentials, or an error if no credentials have been generated yet or the -// last generated credentials have expired. -func (cc *credentialsCache) Retrieve(ctx context.Context) (aws.Credentials, error) { - cc.credsOrErrMu.RLock() - defer cc.credsOrErrMu.RUnlock() - return cc.credsOrErr.creds, cc.credsOrErr.err -} - -func (cc *credentialsCache) run(ctx context.Context) { - // Wait for initialized signal before running loop. - select { - case <-cc.initialized: - case <-ctx.Done(): - cc.log.Debug("Context canceled before initialized.") - return - } - - cc.refreshIfNeeded(ctx) - - ticker := cc.clock.NewTicker(refreshCheckInterval) - defer ticker.Stop() - for { - select { - case <-ticker.Chan(): - cc.refreshIfNeeded(ctx) - case <-ctx.Done(): - cc.log.Debugf("Context canceled, stopping refresh loop.") - return - } - } -} - -func (cc *credentialsCache) refreshIfNeeded(ctx context.Context) { - credsFromCache, err := cc.Retrieve(ctx) - if err == nil && - credsFromCache.HasKeys() && - cc.clock.Now().Add(refreshBeforeExpirationPeriod).Before(credsFromCache.Expires) { - // No need to refresh, credentials in cache are still valid for longer - // than refreshBeforeExpirationPeriod - return - } - cc.log.Debugf("Refreshing credentials.") - - creds, err := cc.refresh(ctx) - if err != nil { - cc.log.Warnf("Failed to retrieve new credentials: %v", err) - // If we were not able to refresh, check if existing credentials in cache are still valid. - // If yes, just log debug, it will be retried on next interval check. - if credsFromCache.HasKeys() && cc.clock.Now().Before(credsFromCache.Expires) { - cc.log.Debugf("Using existing credentials expiring in %s.", credsFromCache.Expires.Sub(cc.clock.Now()).Round(time.Second).String()) - return - } - // If existing creds are expired, update cached error. - cc.setCredsOrErr(credsOrErr{err: trace.Wrap(err)}) - return - } - // Refresh went well, update cached creds. - cc.setCredsOrErr(credsOrErr{creds: creds}) - cc.log.Debugf("Successfully refreshed credentials, new expiry at %v", creds.Expires) -} - -func (cc *credentialsCache) setCredsOrErr(coe credsOrErr) { - cc.credsOrErrMu.Lock() - defer cc.credsOrErrMu.Unlock() - cc.credsOrErr = coe - cc.closeGotFirstCredsOrErr() -} - -func (cc *credentialsCache) refresh(ctx context.Context) (aws.Credentials, error) { - oidcToken, err := cc.generateOIDCTokenFn(ctx, cc.integration) - if err != nil { - return aws.Credentials{}, trace.Wrap(err) - } - - roleProvider := stscreds.NewWebIdentityRoleProvider( - cc.stsClient, - cc.roleARN, - identityToken(oidcToken), - func(wiro *stscreds.WebIdentityRoleOptions) { - wiro.Duration = TokenLifetime - }, - ) - - ctx, cancel := context.WithTimeout(ctx, retrieveTimeout) - defer cancel() - - creds, err := roleProvider.Retrieve(ctx) - return creds, trace.Wrap(err) -} - -func (cc *credentialsCache) waitForFirstCredsOrErr(ctx context.Context) { - select { - case <-ctx.Done(): - case <-cc.gotFirstCredsOrErr: - } -} - -// identityToken is an implementation of [stscreds.IdentityTokenRetriever] for returning a static token. -type identityToken string - -// GetIdentityToken returns the token configured. -func (j identityToken) GetIdentityToken() ([]byte, error) { - return []byte(j), nil + p.credentialsCache.WaitForFirstCredsOrErr(ctx) } // v1Adapter wraps the credentialsCache to implement // [credentials.ProviderWithContext] used by aws-sdk-go (v1). type v1Adapter struct { - cc *credentialsCache + cc *awsoidc.CredentialsCache } var _ credentials.ProviderWithContext = (*v1Adapter)(nil) diff --git a/lib/integrations/externalauditstorage/configurator_test.go b/lib/integrations/externalauditstorage/configurator_test.go index abb1ce1425b9e..ba86e5f8e0c27 100644 --- a/lib/integrations/externalauditstorage/configurator_test.go +++ b/lib/integrations/externalauditstorage/configurator_test.go @@ -47,7 +47,7 @@ func testOIDCIntegration(t *testing.T) *types.IntegrationV1 { oidcIntegration, err := types.NewIntegrationAWSOIDC( types.Metadata{Name: "aws-integration-1"}, &types.AWSOIDCIntegrationSpecV1{ - RoleARN: "role1", + RoleARN: "arn:aws:iam::account:role/role1", }, ) require.NoError(t, err) diff --git a/lib/service/service_test.go b/lib/service/service_test.go index 8b029bdab2ca8..ec596200d1edc 100644 --- a/lib/service/service_test.go +++ b/lib/service/service_test.go @@ -503,7 +503,7 @@ func TestAthenaAuditLogSetup(t *testing.T) { oidcIntegration, err := types.NewIntegrationAWSOIDC( types.Metadata{Name: "aws-integration-1"}, &types.AWSOIDCIntegrationSpecV1{ - RoleARN: "role1", + RoleARN: "arn:aws:iam::account:role/role1", }, ) require.NoError(t, err) diff --git a/lib/teleterm/daemon/hardwarekeyprompt.go b/lib/teleterm/daemon/hardwarekeyprompt.go new file mode 100644 index 0000000000000..4c8b5838a3b01 --- /dev/null +++ b/lib/teleterm/daemon/hardwarekeyprompt.go @@ -0,0 +1,108 @@ +/* + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package daemon + +import ( + "context" + + "github.com/gravitational/trace" + + "github.com/gravitational/teleport/api/utils/keys" + api "github.com/gravitational/teleport/gen/proto/go/teleport/lib/teleterm/v1" + "github.com/gravitational/teleport/lib/teleterm/api/uri" +) + +// NewHardwareKeyPromptConstructor returns a new hardware key prompt constructor +// for this service and the given root cluster URI. +func (s *Service) NewHardwareKeyPromptConstructor(rootClusterURI uri.ResourceURI) keys.HardwareKeyPrompt { + return &hardwareKeyPrompter{s: s, rootClusterURI: rootClusterURI} +} + +type hardwareKeyPrompter struct { + s *Service + rootClusterURI uri.ResourceURI +} + +// Touch prompts the user to touch the hardware key. +func (h *hardwareKeyPrompter) Touch(ctx context.Context) error { + if err := h.s.importantModalSemaphore.Acquire(ctx); err != nil { + return trace.Wrap(err) + } + defer h.s.importantModalSemaphore.Release() + _, err := h.s.tshdEventsClient.PromptHardwareKeyTouch(ctx, &api.PromptHardwareKeyTouchRequest{ + RootClusterUri: h.rootClusterURI.String(), + }) + if err != nil { + return trace.Wrap(err) + } + return nil +} + +// AskPIN prompts the user for a PIN. +func (h *hardwareKeyPrompter) AskPIN(ctx context.Context, requirement keys.PINPromptRequirement) (string, error) { + if err := h.s.importantModalSemaphore.Acquire(ctx); err != nil { + return "", trace.Wrap(err) + } + defer h.s.importantModalSemaphore.Release() + res, err := h.s.tshdEventsClient.PromptHardwareKeyPIN(ctx, &api.PromptHardwareKeyPINRequest{ + RootClusterUri: h.rootClusterURI.String(), + PinOptional: requirement == keys.PINOptional, + }) + if err != nil { + return "", trace.Wrap(err) + } + return res.Pin, nil +} + +// ChangePIN asks for a new PIN. +// The Electron app prompt must handle default values for PIN and PUK, +// preventing the user from submitting empty/default values. +func (h *hardwareKeyPrompter) ChangePIN(ctx context.Context) (*keys.PINAndPUK, error) { + if err := h.s.importantModalSemaphore.Acquire(ctx); err != nil { + return nil, trace.Wrap(err) + } + defer h.s.importantModalSemaphore.Release() + res, err := h.s.tshdEventsClient.PromptHardwareKeyPINChange(ctx, &api.PromptHardwareKeyPINChangeRequest{ + RootClusterUri: h.rootClusterURI.String(), + }) + if err != nil { + return nil, trace.Wrap(err) + } + return &keys.PINAndPUK{ + PIN: res.Pin, + PUK: res.Puk, + PUKChanged: res.PukChanged, + }, nil +} + +// ConfirmSlotOverwrite asks the user if the slot's private key and certificate can be overridden. +func (h *hardwareKeyPrompter) ConfirmSlotOverwrite(ctx context.Context, message string) (bool, error) { + if err := h.s.importantModalSemaphore.Acquire(ctx); err != nil { + return false, trace.Wrap(err) + } + defer h.s.importantModalSemaphore.Release() + res, err := h.s.tshdEventsClient.ConfirmHardwareKeySlotOverwrite(ctx, &api.ConfirmHardwareKeySlotOverwriteRequest{ + RootClusterUri: h.rootClusterURI.String(), + Message: message, + }) + if err != nil { + return false, trace.Wrap(err) + } + return res.Confirmed, nil +} diff --git a/lib/teleterm/teleterm.go b/lib/teleterm/teleterm.go index fd868169642e0..c8bc92b4e0e8a 100644 --- a/lib/teleterm/teleterm.go +++ b/lib/teleterm/teleterm.go @@ -42,6 +42,7 @@ import ( // Serve starts daemon service func Serve(ctx context.Context, cfg Config) error { + var hardwareKeyPromptConstructor func(clusterURI uri.ResourceURI) keys.HardwareKeyPrompt if err := cfg.CheckAndSetDefaults(); err != nil { return trace.Wrap(err) } @@ -58,8 +59,8 @@ func Serve(ctx context.Context, cfg Config) error { Clock: clock, InsecureSkipVerify: cfg.InsecureSkipVerify, AddKeysToAgent: cfg.AddKeysToAgent, - HardwareKeyPromptConstructor: func(clusterURI uri.ResourceURI) keys.HardwareKeyPrompt { - return nil + HardwareKeyPromptConstructor: func(rootClusterURI uri.ResourceURI) keys.HardwareKeyPrompt { + return hardwareKeyPromptConstructor(rootClusterURI) }, }) if err != nil { @@ -80,6 +81,9 @@ func Serve(ctx context.Context, cfg Config) error { return trace.Wrap(err) } + // TODO(gzdunek): Move tshdEventsClient out of daemonService so that we can + // construct the prompt before creating Storage. + hardwareKeyPromptConstructor = daemonService.NewHardwareKeyPromptConstructor apiServer, err := apiserver.New(apiserver.Config{ HostAddr: cfg.Addr, InsecureSkipVerify: cfg.InsecureSkipVerify, diff --git a/proto/teleport/lib/teleterm/v1/tshd_events_service.proto b/proto/teleport/lib/teleterm/v1/tshd_events_service.proto index 1e5b6b6a53d45..de3f127c62a2d 100644 --- a/proto/teleport/lib/teleterm/v1/tshd_events_service.proto +++ b/proto/teleport/lib/teleterm/v1/tshd_events_service.proto @@ -44,6 +44,22 @@ service TshdEventsService { // code. rpc PromptMFA(PromptMFARequest) returns (PromptMFAResponse); + // PromptHardwareKeyPIN notifies the Electron app that the daemon is waiting for the user to + // provide the hardware key PIN. + rpc PromptHardwareKeyPIN(PromptHardwareKeyPINRequest) returns (PromptHardwareKeyPINResponse); + + // PromptHardwareKeyTouch notifies the Electron app that the daemon is waiting for the user to touch the hardware key. + // When the daemon detects the touch, it cancels the prompt. + rpc PromptHardwareKeyTouch(PromptHardwareKeyTouchRequest) returns (PromptHardwareKeyTouchResponse); + + // PromptHardwareKeyPINChange notifies the Electron app that the daemon is waiting for the user to + // change the hardware key PIN. + rpc PromptHardwareKeyPINChange(PromptHardwareKeyPINChangeRequest) returns (PromptHardwareKeyPINChangeResponse); + + // ConfirmHardwareKeySlotOverwrite displays a dialog prompting the user to confirm whether + // the slot's private key and certificate should be overwritten. + rpc ConfirmHardwareKeySlotOverwrite(ConfirmHardwareKeySlotOverwriteRequest) returns (ConfirmHardwareKeySlotOverwriteResponse); + // GetUsageReportingSettings returns the current state of usage reporting. // At the moment, the user cannot toggle usage reporting on and off without shutting down the app, // with the only exception being the first start of the app when they're prompted about telemetry. @@ -146,6 +162,56 @@ message PromptMFAResponse { string totp_code = 1; } +// Request for PromptHardwareKeyPIN. +message PromptHardwareKeyPINRequest { + string root_cluster_uri = 1; + // Specifies if a PIN is optional, allowing the user to set it up if left empty. + bool pin_optional = 2; +} + +// Response for PromptHardwareKeyPIN. +message PromptHardwareKeyPINResponse { + // pin as inputted by the user in the Electron app. + string pin = 1; +} + +// Request for PromptHardwareKeyTouchRequest. +message PromptHardwareKeyTouchRequest { + string root_cluster_uri = 1; +} + +// Response for PromptHardwareKeyTouch. +message PromptHardwareKeyTouchResponse {} + +// Response for PromptHardwareKeyPINChange. +message PromptHardwareKeyPINChangeRequest { + string root_cluster_uri = 1; +} + +// Response for PromptHardwareKeyPINChange. +message PromptHardwareKeyPINChangeResponse { + // New pin set by the user. + string pin = 1; + // PUK is needed to change the PIN. + // This is a new PUK if it has not been changed from the default PUK. + string puk = 2; + // puk_changed is true if the user changed the default PUK. + bool puk_changed = 3; +} + +// Request for ConfirmHardwareKeySlotOverwrite. +message ConfirmHardwareKeySlotOverwriteRequest { + string root_cluster_uri = 1; + // Message to display in the prompt. + string message = 2; +} + +// Response for ConfirmHardwareKeySlotOverwrite. +message ConfirmHardwareKeySlotOverwriteResponse { + // If true, the slot will be overridden. + bool confirmed = 1; +} + // Request for GetUsageReportingSettings. message GetUsageReportingSettingsRequest {} diff --git a/web/packages/teleport/src/Account/Account.test.tsx b/web/packages/teleport/src/Account/Account.test.tsx index 6fb23549a0e36..7dcf86f471adb 100644 --- a/web/packages/teleport/src/Account/Account.test.tsx +++ b/web/packages/teleport/src/Account/Account.test.tsx @@ -243,9 +243,11 @@ test('adding an MFA device', async () => { const user = userEvent.setup(); const ctx = createTeleportContext(); jest.spyOn(ctx.mfaService, 'fetchDevices').mockResolvedValue([testPasskey]); - jest - .spyOn(auth, 'getChallenge') - .mockResolvedValue({ webauthnPublicKey: null, totpChallenge: true }); + jest.spyOn(auth, 'getChallenge').mockResolvedValue({ + webauthnPublicKey: null, + totpChallenge: true, + ssoChallenge: null, + }); jest .spyOn(auth, 'createNewWebAuthnDevice') .mockResolvedValueOnce(dummyCredential); @@ -325,9 +327,11 @@ test('removing an MFA method', async () => { const user = userEvent.setup(); const ctx = createTeleportContext(); jest.spyOn(ctx.mfaService, 'fetchDevices').mockResolvedValue([testMfaMethod]); - jest - .spyOn(auth, 'getChallenge') - .mockResolvedValue({ webauthnPublicKey: null, totpChallenge: false }); + jest.spyOn(auth, 'getChallenge').mockResolvedValue({ + webauthnPublicKey: null, + totpChallenge: false, + ssoChallenge: null, + }); jest .spyOn(auth, 'createPrivilegeTokenWithWebauthn') .mockResolvedValueOnce('webauthn-privilege-token'); diff --git a/web/packages/teleport/src/Console/DocumentKubeExec/DocumentKubeExec.tsx b/web/packages/teleport/src/Console/DocumentKubeExec/DocumentKubeExec.tsx index 1589c6ef7d347..3b405e034f04c 100644 --- a/web/packages/teleport/src/Console/DocumentKubeExec/DocumentKubeExec.tsx +++ b/web/packages/teleport/src/Console/DocumentKubeExec/DocumentKubeExec.tsx @@ -22,7 +22,7 @@ import { Box, Indicator } from 'design'; import * as stores from 'teleport/Console/stores/types'; import { Terminal, TerminalRef } from 'teleport/Console/DocumentSsh/Terminal'; -import useWebAuthn from 'teleport/lib/useWebAuthn'; +import { useMfa } from 'teleport/lib/useMfa'; import useKubeExecSession from 'teleport/Console/DocumentKubeExec/useKubeExecSession'; import Document from 'teleport/Console/Document'; @@ -39,11 +39,11 @@ export default function DocumentKubeExec({ doc, visible }: Props) { const terminalRef = useRef(); const { tty, status, closeDocument, sendKubeExecData } = useKubeExecSession(doc); - const webauthn = useWebAuthn(tty); + const mfa = useMfa(tty); useEffect(() => { // when switching tabs or closing tabs, focus on visible terminal terminalRef.current?.focus(); - }, [visible, webauthn.requested]); + }, [visible, mfa.requested]); const theme = useTheme(); const terminal = ( @@ -63,13 +63,7 @@ export default function DocumentKubeExec({ doc, visible }: Props) { )} - {webauthn.requested && ( - - )} + {mfa.requested && } {status === 'waiting-for-exec-data' && ( diff --git a/web/packages/teleport/src/Console/DocumentSsh/DocumentSsh.tsx b/web/packages/teleport/src/Console/DocumentSsh/DocumentSsh.tsx index eb2720d7f012e..aacafdc35808a 100644 --- a/web/packages/teleport/src/Console/DocumentSsh/DocumentSsh.tsx +++ b/web/packages/teleport/src/Console/DocumentSsh/DocumentSsh.tsx @@ -31,7 +31,7 @@ import { import * as stores from 'teleport/Console/stores'; import AuthnDialog from 'teleport/components/AuthnDialog'; -import useWebAuthn from 'teleport/lib/useWebAuthn'; +import { useMfa } from 'teleport/lib/useMfa'; import Document from '../Document'; @@ -50,13 +50,13 @@ export default function DocumentSshWrapper(props: PropTypes) { function DocumentSsh({ doc, visible }: PropTypes) { const terminalRef = useRef(); const { tty, status, closeDocument, session } = useSshSession(doc); - const webauthn = useWebAuthn(tty); + const mfa = useMfa(tty); const { getMfaResponseAttempt, getDownloader, getUploader, fileTransferRequests, - } = useFileTransfer(tty, session, doc, webauthn.addMfaToScpUrls); + } = useFileTransfer(tty, session, doc, mfa.addMfaToScpUrls); const theme = useTheme(); function handleCloseFileTransfer() { @@ -70,7 +70,7 @@ function DocumentSsh({ doc, visible }: PropTypes) { useEffect(() => { // when switching tabs or closing tabs, focus on visible terminal terminalRef.current?.focus(); - }, [visible, webauthn.requested]); + }, [visible, mfa.requested]); const terminal = ( )} - {webauthn.requested && ( - - )} + {mfa.requested && } {status === 'initialized' && terminal} {}, clientOnClipboardData: async () => {}, setTdpConnection: () => {}, - webauthn: { - errorText: '', - requested: false, - authenticate: () => {}, - setState: () => {}, - addMfaToScpUrls: false, - }, + mfa: makeDefaultMfaState(), showAnotherSessionActiveDialog: false, setShowAnotherSessionActiveDialog: () => {}, alerts: [], @@ -265,12 +260,15 @@ export const WebAuthnPrompt = () => ( writeState: 'granted', }} wsConnection={{ status: 'open' }} - webauthn={{ + mfa={{ errorText: '', requested: true, - authenticate: () => {}, - setState: () => {}, + setErrorText: () => null, addMfaToScpUrls: false, + onWebauthnAuthenticate: () => null, + onSsoAuthenticate: () => null, + webauthnPublicKey: null, + ssoChallenge: null, }} /> ); diff --git a/web/packages/teleport/src/DesktopSession/DesktopSession.tsx b/web/packages/teleport/src/DesktopSession/DesktopSession.tsx index 66a66825a209e..b1f188f2997c9 100644 --- a/web/packages/teleport/src/DesktopSession/DesktopSession.tsx +++ b/web/packages/teleport/src/DesktopSession/DesktopSession.tsx @@ -39,7 +39,7 @@ import useDesktopSession, { import TopBar from './TopBar'; import type { State, WebsocketAttempt } from './useDesktopSession'; -import type { WebAuthnState } from 'teleport/lib/useWebAuthn'; +import type { MfaState } from 'teleport/lib/useMfa'; export function DesktopSessionContainer() { const state = useDesktopSession(); @@ -54,7 +54,7 @@ declare global { export function DesktopSession(props: State) { const { - webauthn, + mfa, tdpClient, username, hostname, @@ -105,7 +105,7 @@ export function DesktopSession(props: State) { tdpConnection, wsConnection, showAnotherSessionActiveDialog, - webauthn + mfa ) ); }, [ @@ -113,7 +113,7 @@ export function DesktopSession(props: State) { tdpConnection, wsConnection, showAnotherSessionActiveDialog, - webauthn, + mfa, ]); return ( @@ -144,7 +144,7 @@ export function DesktopSession(props: State) { {screenState.screen === 'anotherSessionActive' && ( )} - {screenState.screen === 'mfa' && } + {screenState.screen === 'mfa' && } {screenState.screen === 'alert dialog' && ( )} @@ -181,20 +181,15 @@ export function DesktopSession(props: State) { ); } -const MfaDialog = ({ webauthn }: { webauthn: WebAuthnState }) => { +const MfaDialog = ({ mfa }: { mfa: MfaState }) => { return ( { - webauthn.setState(prevState => { - return { - ...prevState, - errorText: - 'This session requires multi factor authentication to continue. Please hit "Retry" and follow the prompts given by your browser to complete authentication.', - }; - }); + mfa.setErrorText( + 'This session requires multi factor authentication to continue. Please hit "Retry" and follow the prompts given by your browser to complete authentication.' + ); }} - errorText={webauthn.errorText} /> ); }; @@ -282,7 +277,7 @@ const nextScreenState = ( tdpConnection: Attempt, wsConnection: WebsocketAttempt, showAnotherSessionActiveDialog: boolean, - webauthn: WebAuthnState + webauthn: MfaState ): ScreenState => { // We always want to show the user the first alert that caused the session to fail/end, // so if we're already showing an alert, don't change the screen. diff --git a/web/packages/teleport/src/DesktopSession/useDesktopSession.tsx b/web/packages/teleport/src/DesktopSession/useDesktopSession.tsx index a49e6d4a268fc..1f642d38d8d96 100644 --- a/web/packages/teleport/src/DesktopSession/useDesktopSession.tsx +++ b/web/packages/teleport/src/DesktopSession/useDesktopSession.tsx @@ -22,7 +22,7 @@ import { useParams } from 'react-router'; import useAttempt from 'shared/hooks/useAttemptNext'; import { ButtonState } from 'teleport/lib/tdp'; -import useWebAuthn from 'teleport/lib/useWebAuthn'; +import { useMfa } from 'teleport/lib/useMfa'; import desktopService from 'teleport/services/desktops'; import userService from 'teleport/services/user'; @@ -130,7 +130,7 @@ export default function useDesktopSession() { }); const tdpClient = clientCanvasProps.tdpClient; - const webauthn = useWebAuthn(tdpClient); + const mfa = useMfa(tdpClient); const onShareDirectory = () => { try { @@ -205,7 +205,7 @@ export default function useDesktopSession() { fetchAttempt, tdpConnection, wsConnection, - webauthn, + mfa, setTdpConnection, showAnotherSessionActiveDialog, setShowAnotherSessionActiveDialog, diff --git a/web/packages/teleport/src/components/AuthnDialog/AuthnDialog.story.tsx b/web/packages/teleport/src/components/AuthnDialog/AuthnDialog.story.tsx index 73600b5a7fb1c..8ec5592c47a0c 100644 --- a/web/packages/teleport/src/components/AuthnDialog/AuthnDialog.story.tsx +++ b/web/packages/teleport/src/components/AuthnDialog/AuthnDialog.story.tsx @@ -18,6 +18,8 @@ import React from 'react'; +import { makeDefaultMfaState } from 'teleport/lib/useMfa'; + import AuthnDialog, { Props } from './AuthnDialog'; export default { @@ -26,12 +28,9 @@ export default { export const Loaded = () => ; -export const Error = () => ( - -); +export const Error = () => ; const props: Props = { - onContinue: () => null, + mfa: makeDefaultMfaState(), onCancel: () => null, - errorText: '', }; diff --git a/web/packages/teleport/src/components/AuthnDialog/AuthnDialog.tsx b/web/packages/teleport/src/components/AuthnDialog/AuthnDialog.tsx index a8b5cd532a1bf..05685c0d6a3eb 100644 --- a/web/packages/teleport/src/components/AuthnDialog/AuthnDialog.tsx +++ b/web/packages/teleport/src/components/AuthnDialog/AuthnDialog.tsx @@ -18,48 +18,51 @@ import React from 'react'; import Dialog, { - DialogFooter, DialogHeader, DialogTitle, DialogContent, } from 'design/Dialog'; import { Danger } from 'design/Alert'; -import { Text, ButtonPrimary, ButtonSecondary } from 'design'; +import { Text, ButtonPrimary, ButtonSecondary, Flex } from 'design'; -export default function AuthnDialog({ - onContinue, - onCancel, - errorText, -}: Props) { +import { MfaState } from 'teleport/lib/useMfa'; + +export default function AuthnDialog({ mfa, onCancel }: Props) { return ( - ({ width: '400px' })} open={true}> + ({ width: '500px' })} open={true}> Multi-factor authentication - {errorText && ( + {mfa.errorText && ( - {errorText} + {mfa.errorText} )} Re-enter your multi-factor authentication in the browser to continue. - - - {errorText ? 'Retry' : 'OK'} + + {/* TODO (avatus) this will eventually be conditionally rendered based on what + type of challenges exist. For now, its only webauthn. */} + + {mfa.errorText ? 'Retry' : 'OK'} Cancel - + ); } export type Props = { - onContinue: () => void; + mfa: MfaState; onCancel: () => void; - errorText: string; }; diff --git a/web/packages/teleport/src/lib/EventEmitterWebAuthnSender.ts b/web/packages/teleport/src/lib/EventEmitterMfaSender.ts similarity index 91% rename from web/packages/teleport/src/lib/EventEmitterWebAuthnSender.ts rename to web/packages/teleport/src/lib/EventEmitterMfaSender.ts index 834746c866bf6..68eae3367f6ea 100644 --- a/web/packages/teleport/src/lib/EventEmitterWebAuthnSender.ts +++ b/web/packages/teleport/src/lib/EventEmitterMfaSender.ts @@ -20,7 +20,7 @@ import { EventEmitter } from 'events'; import { WebauthnAssertionResponse } from 'teleport/services/auth'; -class EventEmitterWebAuthnSender extends EventEmitter { +class EventEmitterMfaSender extends EventEmitter { constructor() { super(); } @@ -31,4 +31,4 @@ class EventEmitterWebAuthnSender extends EventEmitter { } } -export { EventEmitterWebAuthnSender }; +export { EventEmitterMfaSender }; diff --git a/web/packages/teleport/src/lib/tdp/client.ts b/web/packages/teleport/src/lib/tdp/client.ts index 098cb9d824fa6..6f000b083d820 100644 --- a/web/packages/teleport/src/lib/tdp/client.ts +++ b/web/packages/teleport/src/lib/tdp/client.ts @@ -24,7 +24,7 @@ import init, { } from 'teleport/ironrdp/pkg/ironrdp'; import { WebsocketCloseCode, TermEvent } from 'teleport/lib/term/enums'; -import { EventEmitterWebAuthnSender } from 'teleport/lib/EventEmitterWebAuthnSender'; +import { EventEmitterMfaSender } from 'teleport/lib/EventEmitterMfaSender'; import { AuthenticatedWebSocket } from 'teleport/lib/AuthenticatedWebSocket'; import Codec, { @@ -93,7 +93,7 @@ export enum LogType { // sending client commands, and receiving and processing server messages. Its creator is responsible for // ensuring the websocket gets closed and all of its event listeners cleaned up when it is no longer in use. // For convenience, this can be done in one fell swoop by calling Client.shutdown(). -export default class Client extends EventEmitterWebAuthnSender { +export default class Client extends EventEmitterMfaSender { protected codec: Codec; protected socket: AuthenticatedWebSocket | undefined; private socketAddr: string; diff --git a/web/packages/teleport/src/lib/term/tty.ts b/web/packages/teleport/src/lib/term/tty.ts index 6bd9014234323..2eb11957b8fbd 100644 --- a/web/packages/teleport/src/lib/term/tty.ts +++ b/web/packages/teleport/src/lib/term/tty.ts @@ -18,7 +18,7 @@ import Logger from 'shared/libs/logger'; -import { EventEmitterWebAuthnSender } from 'teleport/lib/EventEmitterWebAuthnSender'; +import { EventEmitterMfaSender } from 'teleport/lib/EventEmitterMfaSender'; import { WebauthnAssertionResponse } from 'teleport/services/auth'; import { AuthenticatedWebSocket } from 'teleport/lib/AuthenticatedWebSocket'; @@ -31,7 +31,7 @@ const defaultOptions = { buffered: true, }; -class Tty extends EventEmitterWebAuthnSender { +class Tty extends EventEmitterMfaSender { socket = null; _buffered = true; diff --git a/web/packages/teleport/src/lib/useMfa.ts b/web/packages/teleport/src/lib/useMfa.ts new file mode 100644 index 0000000000000..8d55cf4c73f75 --- /dev/null +++ b/web/packages/teleport/src/lib/useMfa.ts @@ -0,0 +1,148 @@ +/** + * Teleport + * Copyright (C) 2023 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { useState, useEffect, useCallback } from 'react'; + +import { EventEmitterMfaSender } from 'teleport/lib/EventEmitterMfaSender'; +import { TermEvent } from 'teleport/lib/term/enums'; +import { + makeMfaAuthenticateChallenge, + makeWebauthnAssertionResponse, + SSOChallenge, +} from 'teleport/services/auth'; + +export function useMfa(emitterSender: EventEmitterMfaSender): MfaState { + const [state, setState] = useState<{ + errorText: string; + addMfaToScpUrls: boolean; + webauthnPublicKey: PublicKeyCredentialRequestOptions; + ssoChallenge: SSOChallenge; + totpChallenge: boolean; + }>({ + addMfaToScpUrls: false, + errorText: '', + webauthnPublicKey: null, + ssoChallenge: null, + totpChallenge: false, + }); + + // TODO (avatus), this is stubbed for types but will not be called + // until SSO as MFA backend is in. + function onSsoAuthenticate() { + // eslint-disable-next-line no-console + console.error('not yet implemented'); + } + + function onWebauthnAuthenticate() { + if (!window.PublicKeyCredential) { + const errorText = + 'This browser does not support WebAuthn required for hardware tokens, \ + please try the latest version of Chrome, Firefox or Safari.'; + + setState({ + ...state, + errorText, + }); + return; + } + + navigator.credentials + .get({ publicKey: state.webauthnPublicKey }) + .then(res => { + setState(prevState => ({ + ...prevState, + errorText: '', + webauthnPublicKey: null, + })); + const credential = makeWebauthnAssertionResponse(res); + emitterSender.sendWebAuthn(credential); + }) + .catch((err: Error) => { + setErrorText(err.message); + }); + } + + const onChallenge = useCallback(challengeJson => { + const { webauthnPublicKey, ssoChallenge, totpChallenge } = + makeMfaAuthenticateChallenge(challengeJson); + + setState(prevState => ({ + ...prevState, + ssoChallenge, + webauthnPublicKey, + totpChallenge, + })); + }, []); + + useEffect(() => { + if (emitterSender) { + emitterSender.on(TermEvent.WEBAUTHN_CHALLENGE, onChallenge); + + return () => { + emitterSender.removeListener(TermEvent.WEBAUTHN_CHALLENGE, onChallenge); + }; + } + }, [emitterSender, onChallenge]); + + function setErrorText(newErrorText: string) { + setState(prevState => ({ ...prevState, errorText: newErrorText })); + } + + // if any challenge exists, requested is true + const requested = !!( + state.webauthnPublicKey || + state.totpChallenge || + state.ssoChallenge + ); + + return { + requested, + onWebauthnAuthenticate, + onSsoAuthenticate, + addMfaToScpUrls: state.addMfaToScpUrls, + setErrorText, + errorText: state.errorText, + webauthnPublicKey: state.webauthnPublicKey, + ssoChallenge: state.ssoChallenge, + }; +} + +export type MfaState = { + onWebauthnAuthenticate: () => void; + onSsoAuthenticate: () => void; + setErrorText: (errorText: string) => void; + errorText: string; + requested: boolean; + addMfaToScpUrls: boolean; + webauthnPublicKey: PublicKeyCredentialRequestOptions; + ssoChallenge: SSOChallenge; +}; + +// used for testing +export function makeDefaultMfaState(): MfaState { + return { + onWebauthnAuthenticate: () => null, + onSsoAuthenticate: () => null, + setErrorText: () => null, + errorText: '', + requested: false, + addMfaToScpUrls: false, + webauthnPublicKey: null, + ssoChallenge: null, + }; +} diff --git a/web/packages/teleport/src/lib/useWebAuthn.ts b/web/packages/teleport/src/lib/useWebAuthn.ts deleted file mode 100644 index 730065299ceed..0000000000000 --- a/web/packages/teleport/src/lib/useWebAuthn.ts +++ /dev/null @@ -1,115 +0,0 @@ -/** - * Teleport - * Copyright (C) 2023 Gravitational, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -import { useState, useEffect, Dispatch, SetStateAction } from 'react'; - -import { EventEmitterWebAuthnSender } from 'teleport/lib/EventEmitterWebAuthnSender'; -import { TermEvent } from 'teleport/lib/term/enums'; -import { - makeMfaAuthenticateChallenge, - makeWebauthnAssertionResponse, -} from 'teleport/services/auth'; - -export default function useWebAuthn( - emitterSender: EventEmitterWebAuthnSender -): WebAuthnState { - const [state, setState] = useState({ - addMfaToScpUrls: false, - requested: false, - errorText: '', - publicKey: null as PublicKeyCredentialRequestOptions, - }); - - function authenticate() { - if (!window.PublicKeyCredential) { - const errorText = - 'This browser does not support WebAuthn required for hardware tokens, \ - please try the latest version of Chrome, Firefox or Safari.'; - - setState({ - ...state, - errorText, - }); - return; - } - - navigator.credentials - .get({ publicKey: state.publicKey }) - .then(res => { - const credential = makeWebauthnAssertionResponse(res); - emitterSender.sendWebAuthn(credential); - - setState({ - ...state, - requested: false, - errorText: '', - }); - }) - .catch((err: Error) => { - setState({ - ...state, - errorText: err.message, - }); - }); - } - - const onChallenge = challengeJson => { - const challenge = JSON.parse(challengeJson); - const publicKey = makeMfaAuthenticateChallenge(challenge).webauthnPublicKey; - - setState({ - ...state, - requested: true, - addMfaToScpUrls: true, - publicKey, - }); - }; - - useEffect(() => { - if (emitterSender) { - emitterSender.on(TermEvent.WEBAUTHN_CHALLENGE, onChallenge); - - return () => { - emitterSender.removeListener(TermEvent.WEBAUTHN_CHALLENGE, onChallenge); - }; - } - }, [emitterSender]); - - return { - errorText: state.errorText, - requested: state.requested, - authenticate, - setState, - addMfaToScpUrls: state.addMfaToScpUrls, - }; -} - -export type WebAuthnState = { - errorText: string; - requested: boolean; - authenticate: () => void; - setState: Dispatch< - SetStateAction<{ - addMfaToScpUrls: boolean; - requested: boolean; - errorText: string; - publicKey: PublicKeyCredentialRequestOptions; - }> - >; - addMfaToScpUrls: boolean; -}; diff --git a/web/packages/teleport/src/services/auth/makeMfa.ts b/web/packages/teleport/src/services/auth/makeMfa.ts index 0637967483911..506cca4a874c7 100644 --- a/web/packages/teleport/src/services/auth/makeMfa.ts +++ b/web/packages/teleport/src/services/auth/makeMfa.ts @@ -50,12 +50,15 @@ export function makeMfaRegistrationChallenge(json): MfaRegistrationChallenge { } // makeMfaAuthenticateChallenge formats fetched authenticate challenge JSON. -// Webauthn challange contains Base64URL(byte) fields that needs to +// Webauthn challenge contains Base64URL(byte) fields that needs to // be converted to ArrayBuffer expected by navigator.credentials.get: // - challenge // - allowCredentials[i].id export function makeMfaAuthenticateChallenge(json): MfaAuthenticateChallenge { - const webauthnPublicKey = json.webauthn_challenge?.publicKey; + const challenge = typeof json === 'string' ? JSON.parse(json) : json; + const { sso_challenge, webauthn_challenge } = challenge; + + const webauthnPublicKey = webauthn_challenge?.publicKey; if (webauthnPublicKey) { const challenge = webauthnPublicKey.challenge || ''; const allowCredentials = webauthnPublicKey.allowCredentials || []; @@ -70,6 +73,12 @@ export function makeMfaAuthenticateChallenge(json): MfaAuthenticateChallenge { } return { + ssoChallenge: sso_challenge + ? { + redirectUrl: sso_challenge.redirect_url, + requestId: sso_challenge.request_id, + } + : null, totpChallenge: json.totp_challenge, webauthnPublicKey: webauthnPublicKey, }; diff --git a/web/packages/teleport/src/services/auth/types.ts b/web/packages/teleport/src/services/auth/types.ts index 11057cd185645..170d4eedee272 100644 --- a/web/packages/teleport/src/services/auth/types.ts +++ b/web/packages/teleport/src/services/auth/types.ts @@ -32,7 +32,13 @@ export type AuthnChallengeRequest = { userCred: UserCredentials; }; +export type SSOChallenge = { + redirectUrl: string; + requestId: string; +}; + export type MfaAuthenticateChallenge = { + ssoChallenge: SSOChallenge; totpChallenge: boolean; webauthnPublicKey: PublicKeyCredentialRequestOptions; }; diff --git a/web/packages/teleterm/electron.vite.config.mts b/web/packages/teleterm/electron.vite.config.mts index 42a7d81eb44d6..926fc20b307cb 100644 --- a/web/packages/teleterm/electron.vite.config.mts +++ b/web/packages/teleterm/electron.vite.config.mts @@ -17,7 +17,6 @@ */ import path from 'node:path'; -import { existsSync, readFileSync } from 'node:fs'; import { defineConfig, externalizeDepsPlugin, UserConfig } from 'electron-vite'; @@ -120,31 +119,6 @@ const config = defineConfig(env => { }, }; - if (env.mode === 'development') { - if (process.env.VITE_HTTPS_KEY && process.env.VITE_HTTPS_CERT) { - config.renderer.server.https = { - key: readFileSync(process.env.VITE_HTTPS_KEY), - cert: readFileSync(process.env.VITE_HTTPS_CERT), - }; - } else { - const certsDirectory = path.resolve(rootDirectory, 'web/certs'); - - if (!existsSync(certsDirectory)) { - throw new Error( - 'Could not find SSL certificates. Please follow web/README.md to generate certificates.' - ); - } - - const keyPath = path.resolve(certsDirectory, 'server.key'); - const certPath = path.resolve(certsDirectory, 'server.crt'); - - config.renderer.server.https = { - key: readFileSync(keyPath), - cert: readFileSync(certPath), - }; - } - } - return config; }); diff --git a/web/packages/teleterm/src/mainProcess/windowsManager.ts b/web/packages/teleterm/src/mainProcess/windowsManager.ts index daa0935122c4c..513e31573400c 100644 --- a/web/packages/teleterm/src/mainProcess/windowsManager.ts +++ b/web/packages/teleterm/src/mainProcess/windowsManager.ts @@ -362,7 +362,7 @@ export class WindowsManager { * */ function getWindowUrl(isDev: boolean): string { if (isDev) { - return 'https://localhost:8080/'; + return 'http://localhost:8080/'; } // The returned URL is percent-encoded. diff --git a/web/packages/teleterm/src/services/tshd/interceptors.ts b/web/packages/teleterm/src/services/tshd/interceptors.ts index a3375ea1f32a2..3acd92d81feef 100644 --- a/web/packages/teleterm/src/services/tshd/interceptors.ts +++ b/web/packages/teleterm/src/services/tshd/interceptors.ts @@ -22,7 +22,7 @@ import { isObject } from 'shared/utils/highbar'; import Logger from 'teleterm/logger'; -const SENSITIVE_PROPERTIES = ['password', 'authClusterId', 'pin']; +const SENSITIVE_PROPERTIES = ['password', 'authClusterId', 'pin', 'puk']; export function loggingInterceptor(logger: Logger): RpcInterceptor { return { diff --git a/web/packages/teleterm/src/services/tshdEvents/index.ts b/web/packages/teleterm/src/services/tshdEvents/index.ts index eb63c14cb9a3d..a8744d9a7c576 100644 --- a/web/packages/teleterm/src/services/tshdEvents/index.ts +++ b/web/packages/teleterm/src/services/tshdEvents/index.ts @@ -206,6 +206,18 @@ function createService(logger: Logger): { const service: apiService.ITshdEventsService = { relogin: (call, callback) => processEvent('relogin', call, callback), + promptHardwareKeyPIN: (call, callback) => + processEvent('promptHardwareKeyPIN', call, callback), + + promptHardwareKeyTouch: (call, callback) => + processEvent('promptHardwareKeyTouch', call, callback), + + promptHardwareKeyPINChange: (call, callback) => + processEvent('promptHardwareKeyPINChange', call, callback), + + confirmHardwareKeySlotOverwrite: (call, callback) => + processEvent('confirmHardwareKeySlotOverwrite', call, callback), + sendNotification: (call, callback) => processEvent('sendNotification', call, callback), diff --git a/web/packages/teleterm/src/ui/ModalsHost/ModalsHost.tsx b/web/packages/teleterm/src/ui/ModalsHost/ModalsHost.tsx index 582eaa09a49b9..09e1c09a94cd3 100644 --- a/web/packages/teleterm/src/ui/ModalsHost/ModalsHost.tsx +++ b/web/packages/teleterm/src/ui/ModalsHost/ModalsHost.tsx @@ -34,6 +34,7 @@ import { UserJobRole } from './modals/UserJobRole'; import { ReAuthenticate } from './modals/ReAuthenticate'; import { AuthenticateWebDevice } from './modals/AuthenticateWebDevice/AuthenticateWebDevice'; import { ChangeAccessRequestKind } from './modals/ChangeAccessRequestKind'; +import { AskPin, ChangePin, OverwriteSlot, Touch } from './modals/HardwareKeys'; export default function ModalsHost() { const { modalsService } = useAppContext(); @@ -202,6 +203,56 @@ function renderDialog(dialog: Dialog, handleClose: () => void) { /> ); } + case 'hardware-key-pin': { + return ( + { + handleClose(); + dialog.onSuccess(res); + }} + onCancel={() => { + handleClose(); + dialog.onCancel(); + }} + /> + ); + } + case 'hardware-key-touch': { + return ( + { + handleClose(); + dialog.onCancel(); + }} + /> + ); + } + case 'hardware-key-pin-change': { + return ( + { + handleClose(); + dialog.onCancel(); + }} + /> + ); + } + case 'hardware-key-slot-overwrite': { + return ( + { + handleClose(); + dialog.onCancel(); + }} + /> + ); + } case 'none': { return null; diff --git a/web/packages/teleterm/src/ui/ModalsHost/modals/HardwareKeys/AskPin.tsx b/web/packages/teleterm/src/ui/ModalsHost/modals/HardwareKeys/AskPin.tsx new file mode 100644 index 0000000000000..2dbf6da7e1472 --- /dev/null +++ b/web/packages/teleterm/src/ui/ModalsHost/modals/HardwareKeys/AskPin.tsx @@ -0,0 +1,98 @@ +/** + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { useState } from 'react'; + +import DialogConfirmation, { + DialogContent, + DialogFooter, +} from 'design/DialogConfirmation'; +import { ButtonPrimary, Flex, P2 } from 'design'; +import FieldInput from 'shared/components/FieldInput'; +import Validation from 'shared/components/Validation'; +import { requiredField } from 'shared/components/Validation/rules'; + +import { PromptHardwareKeyPINRequest } from 'gen-proto-ts/teleport/lib/teleterm/v1/tshd_events_service_pb'; + +import { CommonHeader } from './CommonHeader'; + +export function AskPin(props: { + req: PromptHardwareKeyPINRequest; + onCancel(): void; + onSuccess(pin: string): void; +}) { + const [pin, setPin] = useState(''); + + return ( + ({ + maxWidth: '450px', + width: '100%', + })} + > + + {({ validator }) => ( +
{ + e.preventDefault(); + validator.validate() && props.onSuccess(pin); + }} + > + + + + + + Enter your YubiKey PIV PIN. +
+ {props.req.pinOptional && + 'To change the default PIN, leave the field blank.'} +
+ + setPin(e.target.value)} + placeholder="123 456" + mb={0} + /> +
+
+ + + Continue + + + )} +
+
+ ); +} diff --git a/web/packages/teleterm/src/ui/ModalsHost/modals/HardwareKeys/ChangePin.tsx b/web/packages/teleterm/src/ui/ModalsHost/modals/HardwareKeys/ChangePin.tsx new file mode 100644 index 0000000000000..64fb239cc6f6e --- /dev/null +++ b/web/packages/teleterm/src/ui/ModalsHost/modals/HardwareKeys/ChangePin.tsx @@ -0,0 +1,257 @@ +/** + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { useState } from 'react'; + +import DialogConfirmation, { + DialogContent, + DialogFooter, +} from 'design/DialogConfirmation'; +import { ButtonPrimary, Flex, Toggle, P2 } from 'design'; +import Validation from 'shared/components/Validation'; +import FieldInput from 'shared/components/FieldInput'; +import { + PromptHardwareKeyPINChangeRequest, + PromptHardwareKeyPINChangeResponse, +} from 'gen-proto-ts/teleport/lib/teleterm/v1/tshd_events_service_pb'; + +import { + requiredField, + Rule, + requiredAll, +} from 'shared/components/Validation/rules'; + +import { CommonHeader } from './CommonHeader'; + +const DEFAULT_PIN = '123456'; +const DEFAULT_PUK = '12345678'; + +export function ChangePin(props: { + req: PromptHardwareKeyPINChangeRequest; + onCancel(): void; + onSuccess(response: PromptHardwareKeyPINChangeResponse): void; +}) { + const [pin, setPin] = useState(''); + const [confirmPin, setConfirmPin] = useState(''); + const [puk, setPuk] = useState(''); + const [newPuk, setNewPuk] = useState(''); + const [confirmNewPuk, setConfirmNewPuk] = useState(''); + const [pukChanged, setPukChanged] = useState(false); + + return ( + ({ + maxWidth: '450px', + width: '100%', + })} + > + + {({ validator }) => ( +
{ + e.preventDefault(); + validator.validate() && + props.onSuccess({ + pin, + pukChanged: pukChanged, + puk: pukChanged ? newPuk : puk, + }); + }} + > + + + + + + The default PIV PIN is not allowed. +
+ Please set a new PIV PIN for your hardware key before + proceeding. Both the PIN and PUK must be 4-6 characters long. +
+ + setPin(e.target.value)} + mb={0} + rule={requiredAll( + requiredField('New PIV PIN is required'), + notDefaultPin(), + correctLength('PIV PIN must be 4-6 characters long') + )} + /> + setConfirmPin(e.target.value)} + mb={0} + rule={requiredAll( + requiredConfirmed(pin, { + confirm: 'Confirm New PIV PIN is required', + doesNotMatch: 'PIV PIN does not match', + }), + notDefaultPin(), + correctLength('PIV PIN must be 4-6 characters long') + )} + /> + + + To change the PIN, please provide your PUK code. +
+ For security purposes, the default PUK ({DEFAULT_PUK}) cannot + be used. If you haven't changed your PUK yet, you'll need to + update it now. +
+ setPukChanged(p => !p)} + > + + Set up new PUK + + + + {!pukChanged ? ( + setPuk(e.target.value)} + mb={0} + rule={requiredAll( + requiredField('PUK is required'), + notDefaultPuk(), + correctLength('PUK must be 4-6 characters long') + )} + /> + ) : ( + <> + setNewPuk(e.target.value)} + mb={0} + rule={requiredAll( + requiredField('New PUK is required'), + notDefaultPuk(), + correctLength('PUK must be 4-6 characters long') + )} + /> + setConfirmNewPuk(e.target.value)} + mb={0} + rule={requiredAll( + requiredConfirmed(pin, { + confirm: 'Confirm New PUK is required', + doesNotMatch: 'PUK does not match', + }), + notDefaultPuk(), + correctLength('PUK must be 4-6 characters long') + )} + /> + + )} +
+
+ + + Continue + + + )} +
+
+ ); +} + +const notDefaultPin = + (): Rule => + value => + () => { + const message = 'Default PIN is not allowed'; + const valid = value !== DEFAULT_PIN; + return { + valid, + message: !valid ? message : '', + }; + }; + +const notDefaultPuk = + (): Rule => + value => + () => { + const message = 'Default PUK is not allowed'; + const valid = value !== DEFAULT_PUK; + return { + valid, + message: !valid ? message : '', + }; + }; + +const correctLength = + (message: string): Rule => + value => + () => { + const valid = + typeof value === 'string' && value.length >= 4 && value.length <= 6; + return { + valid, + message: !valid ? message : '', + }; + }; + +const requiredConfirmed = + ( + code: string, + messages: { + confirm: string; + doesNotMatch: string; + } + ): Rule => + (confirmedCode: string) => + () => { + if (!confirmedCode) { + return { + valid: false, + message: messages.confirm, + }; + } + + if (confirmedCode !== code) { + return { + valid: false, + message: messages.doesNotMatch, + }; + } + + return { + valid: true, + }; + }; diff --git a/web/packages/teleterm/src/ui/ModalsHost/modals/HardwareKeys/CommonHeader.tsx b/web/packages/teleterm/src/ui/ModalsHost/modals/HardwareKeys/CommonHeader.tsx new file mode 100644 index 0000000000000..8027886e8fa64 --- /dev/null +++ b/web/packages/teleterm/src/ui/ModalsHost/modals/HardwareKeys/CommonHeader.tsx @@ -0,0 +1,46 @@ +/** + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { H2, ButtonIcon } from 'design'; +import * as icons from 'design/Icon'; +import { DialogHeader } from 'design/Dialog'; + +import { RootClusterUri, routing } from 'teleterm/ui/uri'; + +export function CommonHeader(props: { + onCancel(): void; + rootClusterUri: RootClusterUri; +}) { + const rootClusterName = routing.parseClusterName(props.rootClusterUri); + + return ( + +

+ Unlock hardware key to access {rootClusterName} +

+ + + + +
+ ); +} diff --git a/web/packages/teleterm/src/ui/ModalsHost/modals/HardwareKeys/OverwriteSlot.tsx b/web/packages/teleterm/src/ui/ModalsHost/modals/HardwareKeys/OverwriteSlot.tsx new file mode 100644 index 0000000000000..1a67d691c9747 --- /dev/null +++ b/web/packages/teleterm/src/ui/ModalsHost/modals/HardwareKeys/OverwriteSlot.tsx @@ -0,0 +1,68 @@ +/** + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import DialogConfirmation, { + DialogContent, + DialogFooter, +} from 'design/DialogConfirmation'; +import { ButtonPrimary, ButtonSecondary, Flex, P2 } from 'design'; +import { ConfirmHardwareKeySlotOverwriteRequest } from 'gen-proto-ts/teleport/lib/teleterm/v1/tshd_events_service_pb'; + +import { CommonHeader } from './CommonHeader'; + +export function OverwriteSlot(props: { + req: ConfirmHardwareKeySlotOverwriteRequest; + onCancel(): void; + onConfirm(): void; +}) { + return ( + ({ + maxWidth: '450px', + width: '100%', + })} + > +
{ + e.preventDefault(); + props.onConfirm(); + }} + > + + + + {props.req.message} + + + + + Yes + + No + + + + +
+ ); +} diff --git a/web/packages/teleterm/src/ui/ModalsHost/modals/HardwareKeys/Touch.tsx b/web/packages/teleterm/src/ui/ModalsHost/modals/HardwareKeys/Touch.tsx new file mode 100644 index 0000000000000..a25e1f42dc5fd --- /dev/null +++ b/web/packages/teleterm/src/ui/ModalsHost/modals/HardwareKeys/Touch.tsx @@ -0,0 +1,63 @@ +/** + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import DialogConfirmation, { DialogContent } from 'design/DialogConfirmation'; +import { Flex, Image, P2 } from 'design'; + +import { PromptHardwareKeyTouchRequest } from 'gen-proto-ts/teleport/lib/teleterm/v1/tshd_events_service_pb'; + +import svgHardwareKey from 'teleterm/ui/ClusterConnect/ClusterLogin/FormLogin/PromptWebauthn/hardware.svg'; +import LinearProgress from 'teleterm/ui/components/LinearProgress'; + +import { CommonHeader } from './CommonHeader'; + +export function Touch(props: { + req: PromptHardwareKeyTouchRequest; + onCancel(): void; +}) { + return ( + ({ + maxWidth: '450px', + width: '100%', + })} + > + + + + + + Touch your YubiKey + + + + + ); +} diff --git a/web/packages/teleterm/src/ui/ModalsHost/modals/HardwareKeys/index.story.tsx b/web/packages/teleterm/src/ui/ModalsHost/modals/HardwareKeys/index.story.tsx new file mode 100644 index 0000000000000..835e3b17606b6 --- /dev/null +++ b/web/packages/teleterm/src/ui/ModalsHost/modals/HardwareKeys/index.story.tsx @@ -0,0 +1,93 @@ +/** + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { Meta } from '@storybook/react'; + +import { makeRootCluster } from 'teleterm/services/tshd/testHelpers'; + +import { Touch as TouchComponent } from './Touch'; +import { OverwriteSlot as OverwriteSlotComponent } from './OverwriteSlot'; +import { ChangePin as ChangePinComponent } from './ChangePin'; +import { AskPin as AskPinComponent } from './AskPin'; + +const rootCluster = makeRootCluster(); + +export default { + title: 'Teleterm/ModalsHost/HardwareKeys', +} satisfies Meta; + +export function AskPinOptional() { + return ( + {}} + onCancel={() => {}} + req={{ + rootClusterUri: rootCluster.uri, + pinOptional: true, + }} + /> + ); +} + +export function AskPinRequired() { + return ( + {}} + onCancel={() => {}} + req={{ + rootClusterUri: rootCluster.uri, + pinOptional: false, + }} + /> + ); +} + +export function Touch() { + return ( + {}} + req={{ + rootClusterUri: rootCluster.uri, + }} + /> + ); +} + +export function ChangePin() { + return ( + {}} + onCancel={() => {}} + req={{ rootClusterUri: rootCluster.uri }} + /> + ); +} + +export function OverwriteSlot() { + return ( + {}} + onCancel={() => {}} + req={{ + rootClusterUri: rootCluster.uri, + message: + "Would you like to overwrite this slot's private key and certificate?", + }} + /> + ); +} diff --git a/web/packages/teleterm/src/ui/ModalsHost/modals/HardwareKeys/index.ts b/web/packages/teleterm/src/ui/ModalsHost/modals/HardwareKeys/index.ts new file mode 100644 index 0000000000000..473dcd5d9694a --- /dev/null +++ b/web/packages/teleterm/src/ui/ModalsHost/modals/HardwareKeys/index.ts @@ -0,0 +1,22 @@ +/** + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +export * from './Touch'; +export * from './AskPin'; +export * from './ChangePin'; +export * from './OverwriteSlot'; diff --git a/web/packages/teleterm/src/ui/services/modals/modalsService.ts b/web/packages/teleterm/src/ui/services/modals/modalsService.ts index 6078e49dd2079..421a45c94398f 100644 --- a/web/packages/teleterm/src/ui/services/modals/modalsService.ts +++ b/web/packages/teleterm/src/ui/services/modals/modalsService.ts @@ -220,6 +220,33 @@ export interface DialogChangeAccessRequestKind { onCancel(): void; } +export interface DialogHardwareKeyPin { + kind: 'hardware-key-pin'; + req: tshdEventsApi.PromptHardwareKeyPINRequest; + onSuccess(pin: string): void; + onCancel(): void; +} + +export interface DialogHardwareKeyTouch { + kind: 'hardware-key-touch'; + req: tshdEventsApi.PromptHardwareKeyTouchRequest; + onCancel(): void; +} + +export interface DialogHardwareKeyPinChange { + kind: 'hardware-key-pin-change'; + req: tshdEventsApi.PromptHardwareKeyPINChangeRequest; + onSuccess(res: tshdEventsApi.PromptHardwareKeyPINChangeResponse): void; + onCancel(): void; +} + +export interface DialogHardwareKeySlotOverwrite { + kind: 'hardware-key-slot-overwrite'; + req: tshdEventsApi.ConfirmHardwareKeySlotOverwriteRequest; + onConfirm(): void; + onCancel(): void; +} + export type Dialog = | DialogClusterConnect | DialogClusterLogout @@ -231,4 +258,8 @@ export type Dialog = | DialogHeadlessAuthentication | DialogReAuthenticate | DialogChangeAccessRequestKind + | DialogHardwareKeyPin + | DialogHardwareKeyTouch + | DialogHardwareKeyPinChange + | DialogHardwareKeySlotOverwrite | DialogNone; diff --git a/web/packages/teleterm/src/ui/tshdEvents.ts b/web/packages/teleterm/src/ui/tshdEvents.ts index c48e48faa1481..b06aa73196b9e 100644 --- a/web/packages/teleterm/src/ui/tshdEvents.ts +++ b/web/packages/teleterm/src/ui/tshdEvents.ts @@ -16,6 +16,8 @@ * along with this program. If not, see . */ +import { PromptHardwareKeyPINChangeResponse } from 'gen-proto-ts/teleport/lib/teleterm/v1/tshd_events_service_pb'; + import { TshdEventContextBridgeService } from 'teleterm/types'; import { IAppContext } from 'teleterm/ui/types'; import Logger from 'teleterm/logger'; @@ -101,5 +103,135 @@ export function createTshdEventsContextBridgeService( } return {}; }, + + promptHardwareKeyPIN: async ({ request, onRequestCancelled }) => { + ctx.mainProcessClient.forceFocusWindow(); + const { pin, hasCanceledModal } = await new Promise<{ + pin: string; + hasCanceledModal: boolean; + }>(resolve => { + const { closeDialog } = ctx.modalsService.openImportantDialog({ + kind: 'hardware-key-pin', + req: request, + onSuccess: pin => resolve({ hasCanceledModal: false, pin }), + onCancel: () => + resolve({ + hasCanceledModal: true, + pin: undefined, + }), + }); + + // tshd can cancel the request + onRequestCancelled(closeDialog); + }); + + if (hasCanceledModal) { + throw { + isCrossContextError: true, + name: 'AbortError', + message: 'hardware key PIN modal closed by user', + }; + } + + return { pin: pin }; + }, + + promptHardwareKeyTouch: async ({ request, onRequestCancelled }) => { + ctx.mainProcessClient.forceFocusWindow(); + const { hasCanceledModal } = await new Promise<{ + hasCanceledModal: boolean; + }>(resolve => { + const { closeDialog } = ctx.modalsService.openImportantDialog({ + kind: 'hardware-key-touch', + req: request, + onCancel: () => + resolve({ + hasCanceledModal: true, + }), + }); + + // When a tap is detected, tshd cancels this request. + onRequestCancelled(closeDialog); + }); + + if (hasCanceledModal) { + throw { + isCrossContextError: true, + name: 'AbortError', + message: 'hardware key touch modal closed by user', + }; + } + + return {}; + }, + + promptHardwareKeyPINChange: async ({ request, onRequestCancelled }) => { + const { hasCanceledModal, res } = await new Promise<{ + hasCanceledModal: boolean; + res: PromptHardwareKeyPINChangeResponse; + }>(resolve => { + const { closeDialog } = ctx.modalsService.openImportantDialog({ + kind: 'hardware-key-pin-change', + req: request, + onSuccess: res => { + resolve({ hasCanceledModal: false, res }); + }, + onCancel: () => + resolve({ + hasCanceledModal: true, + res: undefined, + }), + }); + + // tshd can cancel the request + onRequestCancelled(closeDialog); + }); + + if (hasCanceledModal) { + throw { + isCrossContextError: true, + name: 'AbortError', + message: 'hardware key change PIN modal closed by user', + }; + } + + return res; + }, + + confirmHardwareKeySlotOverwrite: async ({ + request, + onRequestCancelled, + }) => { + const { hasCanceledModal, confirmed } = await new Promise<{ + hasCanceledModal: boolean; + confirmed: boolean; + }>(resolve => { + const { closeDialog } = ctx.modalsService.openImportantDialog({ + kind: 'hardware-key-slot-overwrite', + req: request, + onConfirm: () => { + resolve({ hasCanceledModal: false, confirmed: true }); + }, + onCancel: () => + resolve({ + hasCanceledModal: true, + confirmed: false, + }), + }); + + // tshd can cancel the request + onRequestCancelled(closeDialog); + }); + + if (hasCanceledModal) { + throw { + isCrossContextError: true, + name: 'AbortError', + message: 'hardware key slot overwrite modal closed by user', + }; + } + + return { confirmed }; + }, }; }