From 8f99076d4ce3dfb9861ed30b490fe2310d21a355 Mon Sep 17 00:00:00 2001 From: Marco Dinis Date: Thu, 16 Jan 2025 18:36:39 +0000 Subject: [PATCH] Remove EICE dead code (#51107) * Remove EICE dead code Accessing EC2 instances using EC2 Instance Connect Endpoint was developed some releases ago. However, due to strict quotas put in place by amazon, we decide to remove this feature. Since a couple of releases ago we hide this feature from the UI. This PR removes dead code: - removes the UI bits used during the Discovery flow - removes the `teleport integrationn configure eice-iam` command - removes API endpoinst that are no longer used - deprecates the unused gRPC calls The following parts were kept, to ensure we don't break existing set ups: - auto discovery of ec2 instances using the EICE method - accessing Servers which have the ec2-ice subkind - kubernetes operator and terraform provider EICE resource management We might remove those in the future, but for now, they will be kept. * add delete version notice --- .../integration/v1/awsoidc_service.pb.go | 883 +++++++++--------- .../integration/v1/awsoidc_service_grpc.pb.go | 9 + .../integration/v1/awsoidc_service.proto | 23 +- lib/auth/integration/integrationv1/awsoidc.go | 6 + .../integration/integrationv1/awsoidc_test.go | 24 - lib/config/configuration.go | 17 - lib/integrations/awsoidc/eice_iam_config.go | 160 ---- .../awsoidc/eice_iam_config_test.go | 199 ---- .../testdata/TestEICEIAMConfigOutput.golden | 28 - lib/usagereporter/web/userevent.go | 6 - lib/usagereporter/web/userevent_discover.go | 27 - lib/web/apiserver.go | 4 - lib/web/integrations_awsoidc.go | 203 ---- lib/web/integrations_awsoidc_test.go | 104 --- lib/web/ui/integration.go | 91 -- tool/teleport/common/integration_configure.go | 18 - tool/teleport/common/teleport.go | 8 - .../CreateEc2Ice/CreateEc2Ice.story.tsx | 496 ---------- .../Server/CreateEc2Ice/CreateEc2Ice.tsx | 320 ------- .../CreateEc2Ice/CreateEc2IceDialog.tsx | 378 -------- .../EnrollEc2Instance/Ec2InstanceList.tsx | 154 --- .../EnrollEc2Instance.story.tsx | 417 --------- .../EnrollEc2Instance.test.tsx | 726 -------------- .../EnrollEc2Instance/EnrollEc2Instance.tsx | 565 ----------- .../NoEc2IceRequiredDialog.tsx | 51 - .../teleport/src/Discover/Server/index.tsx | 25 - .../Discover/Shared/Aws/ConfigureIamPerms.tsx | 39 +- .../teleport/src/Discover/useDiscover.tsx | 2 - web/packages/teleport/src/config.ts | 48 - .../teleport/src/services/discovery/types.ts | 1 - .../src/services/integrations/integrations.ts | 68 -- .../src/services/integrations/types.ts | 76 -- .../teleport/src/services/userEvent/types.ts | 4 - 33 files changed, 487 insertions(+), 4693 deletions(-) delete mode 100644 lib/integrations/awsoidc/eice_iam_config.go delete mode 100644 lib/integrations/awsoidc/eice_iam_config_test.go delete mode 100644 lib/integrations/awsoidc/testdata/TestEICEIAMConfigOutput.golden delete mode 100644 web/packages/teleport/src/Discover/Server/CreateEc2Ice/CreateEc2Ice.story.tsx delete mode 100644 web/packages/teleport/src/Discover/Server/CreateEc2Ice/CreateEc2Ice.tsx delete mode 100644 web/packages/teleport/src/Discover/Server/CreateEc2Ice/CreateEc2IceDialog.tsx delete mode 100644 web/packages/teleport/src/Discover/Server/EnrollEc2Instance/Ec2InstanceList.tsx delete mode 100644 web/packages/teleport/src/Discover/Server/EnrollEc2Instance/EnrollEc2Instance.story.tsx delete mode 100644 web/packages/teleport/src/Discover/Server/EnrollEc2Instance/EnrollEc2Instance.test.tsx delete mode 100644 web/packages/teleport/src/Discover/Server/EnrollEc2Instance/EnrollEc2Instance.tsx delete mode 100644 web/packages/teleport/src/Discover/Server/EnrollEc2Instance/NoEc2IceRequiredDialog.tsx diff --git a/api/gen/proto/go/teleport/integration/v1/awsoidc_service.pb.go b/api/gen/proto/go/teleport/integration/v1/awsoidc_service.pb.go index cec0138373c3c..8630cd64a4076 100644 --- a/api/gen/proto/go/teleport/integration/v1/awsoidc_service.pb.go +++ b/api/gen/proto/go/teleport/integration/v1/awsoidc_service.pb.go @@ -36,6 +36,8 @@ const ( ) // ListEICERequest is a request for a paginated list of AWS EC2 Instance Connect Endpoints. +// +// Deprecated: Marked as deprecated in teleport/integration/v1/awsoidc_service.proto. type ListEICERequest struct { state protoimpl.MessageState `protogen:"open.v1"` // Integration is the AWS OIDC Integration name. @@ -113,6 +115,8 @@ func (x *ListEICERequest) GetNextToken() string { } // EC2InstanceConnectEndpoint is a representation of a Amazon VPC EC2 Instance Connect Endpoint. +// +// Deprecated: Marked as deprecated in teleport/integration/v1/awsoidc_service.proto. type EC2InstanceConnectEndpoint struct { state protoimpl.MessageState `protogen:"open.v1"` // Name is the endpoint name. @@ -206,6 +210,8 @@ func (x *EC2InstanceConnectEndpoint) GetVpcId() string { } // ListEICEResponse contains a page of AWS EC2 Instance Connect Endpoints. +// +// Deprecated: Marked as deprecated in teleport/integration/v1/awsoidc_service.proto. type ListEICEResponse struct { state protoimpl.MessageState `protogen:"open.v1"` // EC2ICEs contains the page of EC2 Instance Connect Endpoints. @@ -271,6 +277,8 @@ func (x *ListEICEResponse) GetNextToken() string { } // CreateEICERequest contains the required fields to create an AWS EC2 Instance Connect Endpoint. +// +// Deprecated: Marked as deprecated in teleport/integration/v1/awsoidc_service.proto. type CreateEICERequest struct { state protoimpl.MessageState `protogen:"open.v1"` // Integration is the AWS OIDC Integration name. @@ -338,6 +346,8 @@ func (x *CreateEICERequest) GetEndpoints() []*EC2ICEndpoint { } // EC2ICEndpoint contains the information for a single Endpoint to be created. +// +// Deprecated: Marked as deprecated in teleport/integration/v1/awsoidc_service.proto. type EC2ICEndpoint struct { state protoimpl.MessageState `protogen:"open.v1"` // Name is the endpoint name. @@ -403,6 +413,8 @@ func (x *EC2ICEndpoint) GetSecurityGroupIds() []string { } // CreateEICEResponse is a request to create a VPC Endpoint of EC2 Instance Connect Endpoint type. +// +// Deprecated: Marked as deprecated in teleport/integration/v1/awsoidc_service.proto. type CreateEICEResponse struct { state protoimpl.MessageState `protogen:"open.v1"` // Name is the Endpoint ID. @@ -2257,6 +2269,8 @@ func (x *EnrollEKSClustersResponse) GetResults() []*EnrollEKSClusterResult { } // ListEC2Request is a request for a paginated list of AWS EC2 instances. +// +// Deprecated: Marked as deprecated in teleport/integration/v1/awsoidc_service.proto. type ListEC2Request struct { state protoimpl.MessageState `protogen:"open.v1"` // Integration is the AWS OIDC Integration name. @@ -2324,6 +2338,8 @@ func (x *ListEC2Request) GetNextToken() string { } // ListEC2Response contains a page of AWS EC2 instances represented as Nodes. +// +// Deprecated: Marked as deprecated in teleport/integration/v1/awsoidc_service.proto. type ListEC2Response struct { state protoimpl.MessageState `protogen:"open.v1"` // Servers contains the page of EC2. @@ -2748,7 +2764,7 @@ var file_teleport_integration_v1_awsoidc_service_proto_rawDesc = []byte{ 0x17, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x1a, 0x21, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, - 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x83, 0x01, 0x0a, 0x0f, + 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x87, 0x01, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x49, 0x43, 0x45, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, @@ -2757,466 +2773,469 @@ var file_teleport_integration_v1_awsoidc_service_proto_rawDesc = []byte{ 0x5f, 0x69, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x76, 0x70, 0x63, 0x49, 0x64, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x65, 0x78, 0x74, 0x54, 0x6f, 0x6b, 0x65, - 0x6e, 0x22, 0xc6, 0x01, 0x0a, 0x1a, 0x45, 0x43, 0x32, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, - 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, - 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x74, - 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x25, 0x0a, 0x0e, 0x64, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x5f, 0x6c, 0x69, 0x6e, - 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, - 0x72, 0x64, 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, - 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x75, 0x62, 0x6e, 0x65, - 0x74, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x76, 0x70, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x70, 0x63, 0x49, 0x64, 0x22, 0xa7, 0x01, 0x0a, 0x10, 0x4c, - 0x69, 0x73, 0x74, 0x45, 0x49, 0x43, 0x45, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x4d, 0x0a, 0x07, 0x65, 0x63, 0x32, 0x69, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x33, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, - 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x43, 0x32, 0x49, 0x6e, - 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x45, 0x6e, 0x64, - 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x07, 0x65, 0x63, 0x32, 0x69, 0x63, 0x65, 0x73, 0x12, 0x25, - 0x0a, 0x0e, 0x64, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x5f, 0x6c, 0x69, 0x6e, 0x6b, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, - 0x64, 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x74, 0x6f, - 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x65, 0x78, 0x74, 0x54, - 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x93, 0x01, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, - 0x49, 0x43, 0x45, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x6e, - 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, - 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, - 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x44, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, - 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, - 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, - 0x31, 0x2e, 0x45, 0x43, 0x32, 0x49, 0x43, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, - 0x09, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x22, 0x6e, 0x0a, 0x0d, 0x45, 0x43, + 0x6e, 0x3a, 0x02, 0x18, 0x01, 0x22, 0xca, 0x01, 0x0a, 0x1a, 0x45, 0x43, 0x32, 0x49, 0x6e, 0x73, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x45, 0x6e, 0x64, 0x70, + 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x23, + 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, + 0x5f, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x61, 0x73, + 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x75, + 0x62, 0x6e, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, + 0x75, 0x62, 0x6e, 0x65, 0x74, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x76, 0x70, 0x63, 0x5f, 0x69, + 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x70, 0x63, 0x49, 0x64, 0x3a, 0x02, + 0x18, 0x01, 0x22, 0xab, 0x01, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x49, 0x43, 0x45, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x07, 0x65, 0x63, 0x32, 0x69, 0x63, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x76, 0x31, 0x2e, 0x45, 0x43, 0x32, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x07, 0x65, + 0x63, 0x32, 0x69, 0x63, 0x65, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x61, 0x73, 0x68, 0x62, 0x6f, + 0x61, 0x72, 0x64, 0x5f, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, + 0x64, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x1d, 0x0a, + 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x6e, 0x65, 0x78, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x3a, 0x02, 0x18, 0x01, + 0x22, 0x97, 0x01, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x49, 0x43, 0x45, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x6e, 0x74, + 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, + 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, + 0x12, 0x44, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, + 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x43, + 0x32, 0x49, 0x43, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x09, 0x65, 0x6e, 0x64, + 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x3a, 0x02, 0x18, 0x01, 0x22, 0x72, 0x0a, 0x0d, 0x45, 0x43, 0x32, 0x49, 0x43, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x49, 0x64, 0x12, 0x2c, 0x0a, 0x12, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, - 0x74, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x73, 0x22, 0x7d, 0x0a, 0x12, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x45, 0x49, 0x43, 0x45, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x53, 0x0a, 0x11, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, - 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x26, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x43, 0x32, 0x49, 0x43, 0x45, - 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, - 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x22, 0xbb, 0x01, 0x0a, 0x14, 0x4c, 0x69, - 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x08, - 0x72, 0x64, 0x73, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x72, 0x64, 0x73, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x67, 0x69, 0x6e, - 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, - 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x65, 0x78, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, - 0x12, 0x15, 0x0a, 0x06, 0x76, 0x70, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x76, 0x70, 0x63, 0x49, 0x64, 0x22, 0x67, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x44, - 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x2f, 0x0a, 0x09, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x44, 0x61, 0x74, 0x61, - 0x62, 0x61, 0x73, 0x65, 0x56, 0x33, 0x52, 0x09, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, - 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x65, 0x78, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, - 0x22, 0x8b, 0x01, 0x0a, 0x19, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, - 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, - 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x15, 0x0a, 0x06, 0x76, 0x70, 0x63, 0x5f, - 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x70, 0x63, 0x49, 0x64, 0x12, - 0x1d, 0x0a, 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x65, 0x78, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x4d, - 0x0a, 0x15, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, - 0x75, 0x6c, 0x65, 0x43, 0x49, 0x44, 0x52, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x69, 0x64, 0x72, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x69, 0x64, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x64, - 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x57, 0x0a, - 0x18, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x75, - 0x6c, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x72, 0x6f, - 0x75, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x67, 0x72, 0x6f, - 0x75, 0x70, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x80, 0x02, 0x0a, 0x11, 0x53, 0x65, 0x63, 0x75, 0x72, - 0x69, 0x74, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x1f, 0x0a, 0x0b, - 0x69, 0x70, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0a, 0x69, 0x70, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x1b, 0x0a, - 0x09, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x08, 0x66, 0x72, 0x6f, 0x6d, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x6f, - 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x74, 0x6f, 0x50, - 0x6f, 0x72, 0x74, 0x12, 0x44, 0x0a, 0x05, 0x63, 0x69, 0x64, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, - 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x63, - 0x75, 0x72, 0x69, 0x74, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x75, 0x6c, 0x65, 0x43, 0x49, - 0x44, 0x52, 0x52, 0x05, 0x63, 0x69, 0x64, 0x72, 0x73, 0x12, 0x4e, 0x0a, 0x09, 0x67, 0x72, 0x6f, - 0x75, 0x70, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x74, - 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x47, - 0x72, 0x6f, 0x75, 0x70, 0x52, 0x75, 0x6c, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x52, - 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x73, 0x22, 0xf9, 0x01, 0x0a, 0x0d, 0x53, 0x65, - 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 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, - 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, - 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x4f, 0x0a, 0x0d, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x72, 0x75, 0x6c, - 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, - 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x76, 0x31, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, - 0x52, 0x75, 0x6c, 0x65, 0x52, 0x0c, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x75, 0x6c, - 0x65, 0x73, 0x12, 0x51, 0x0a, 0x0e, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x72, - 0x75, 0x6c, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x74, 0x65, 0x6c, - 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x47, 0x72, 0x6f, - 0x75, 0x70, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x0d, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, - 0x52, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x8c, 0x01, 0x0a, 0x1a, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, - 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, 0x0f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, - 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, - 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, - 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x0e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x47, - 0x72, 0x6f, 0x75, 0x70, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x74, 0x6f, - 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x65, 0x78, 0x74, 0x54, - 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x84, 0x01, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, - 0x6e, 0x65, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x69, + 0x74, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x73, 0x3a, 0x02, 0x18, 0x01, 0x22, 0x81, + 0x01, 0x0a, 0x12, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x49, 0x43, 0x45, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x53, 0x0a, 0x11, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, + 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x45, + 0x43, 0x32, 0x49, 0x43, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x64, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x3a, 0x02, + 0x18, 0x01, 0x22, 0xbb, 0x01, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, + 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, - 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x15, 0x0a, 0x06, 0x76, 0x70, 0x63, 0x5f, 0x69, 0x64, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x70, 0x63, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, - 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x09, 0x6e, 0x65, 0x78, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x59, 0x0a, 0x06, 0x53, - 0x75, 0x62, 0x6e, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x2b, 0x0a, 0x11, 0x61, 0x76, 0x61, - 0x69, 0x6c, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x5f, 0x7a, 0x6f, 0x6e, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x69, 0x6c, 0x69, - 0x74, 0x79, 0x5a, 0x6f, 0x6e, 0x65, 0x22, 0x6f, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, - 0x62, 0x6e, 0x65, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, - 0x07, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, - 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x52, - 0x07, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x65, 0x78, 0x74, - 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x65, - 0x78, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x6a, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x56, - 0x50, 0x43, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x6e, - 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, - 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, - 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x74, 0x6f, 0x6b, - 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x65, 0x78, 0x74, 0x54, 0x6f, - 0x6b, 0x65, 0x6e, 0x22, 0x29, 0x0a, 0x03, 0x56, 0x50, 0x43, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x0e, - 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x63, - 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x50, 0x43, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x30, 0x0a, 0x04, 0x76, 0x70, 0x63, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x1c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, - 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x50, 0x43, 0x52, 0x04, - 0x76, 0x70, 0x63, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x74, 0x6f, 0x6b, - 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x65, 0x78, 0x74, 0x54, 0x6f, - 0x6b, 0x65, 0x6e, 0x22, 0xc0, 0x02, 0x0a, 0x1c, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x44, 0x61, - 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, + 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x64, 0x73, 0x5f, 0x74, 0x79, 0x70, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x64, 0x73, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x07, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x65, + 0x78, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x6e, 0x65, 0x78, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x15, 0x0a, 0x06, 0x76, 0x70, 0x63, + 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x70, 0x63, 0x49, 0x64, + 0x22, 0x67, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x09, 0x64, 0x61, 0x74, + 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, + 0x79, 0x70, 0x65, 0x73, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x56, 0x33, 0x52, + 0x09, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x65, + 0x78, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x6e, 0x65, 0x78, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x8b, 0x01, 0x0a, 0x19, 0x4c, 0x69, + 0x73, 0x74, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x6e, + 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x67, + 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, + 0x6e, 0x12, 0x15, 0x0a, 0x06, 0x76, 0x70, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x76, 0x70, 0x63, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x65, 0x78, 0x74, + 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x65, + 0x78, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x4d, 0x0a, 0x15, 0x53, 0x65, 0x63, 0x75, 0x72, + 0x69, 0x74, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x75, 0x6c, 0x65, 0x43, 0x49, 0x44, 0x52, + 0x12, 0x12, 0x0a, 0x04, 0x63, 0x69, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x63, 0x69, 0x64, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x57, 0x0a, 0x18, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, + 0x74, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x75, 0x6c, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x49, 0x44, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x20, 0x0a, + 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, + 0x80, 0x02, 0x0a, 0x11, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x47, 0x72, 0x6f, 0x75, + 0x70, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x70, 0x5f, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x70, 0x50, 0x72, + 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x70, + 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x66, 0x72, 0x6f, 0x6d, 0x50, + 0x6f, 0x72, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x6f, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x74, 0x6f, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x44, 0x0a, 0x05, + 0x63, 0x69, 0x64, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x47, 0x72, + 0x6f, 0x75, 0x70, 0x52, 0x75, 0x6c, 0x65, 0x43, 0x49, 0x44, 0x52, 0x52, 0x05, 0x63, 0x69, 0x64, + 0x72, 0x73, 0x12, 0x4e, 0x0a, 0x09, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x73, 0x18, + 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, + 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x75, 0x6c, + 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x52, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, + 0x64, 0x73, 0x22, 0xf9, 0x01, 0x0a, 0x0d, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 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, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4f, 0x0a, 0x0d, 0x69, 0x6e, + 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x2a, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, + 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x63, 0x75, + 0x72, 0x69, 0x74, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x0c, 0x69, + 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x51, 0x0a, 0x0e, 0x6f, + 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x05, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, + 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, + 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x75, 0x6c, 0x65, 0x52, + 0x0d, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x8c, + 0x01, 0x0a, 0x1a, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x47, + 0x72, 0x6f, 0x75, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, + 0x0f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, + 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x0e, + 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x12, 0x1d, + 0x0a, 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x6e, 0x65, 0x78, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x84, 0x01, + 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x22, - 0x0a, 0x0d, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x61, 0x72, 0x6e, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x74, 0x61, 0x73, 0x6b, 0x52, 0x6f, 0x6c, 0x65, 0x41, - 0x72, 0x6e, 0x12, 0x29, 0x0a, 0x10, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x74, 0x65, - 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3b, 0x0a, - 0x1a, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6a, 0x6f, 0x69, 0x6e, - 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x17, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4a, 0x6f, 0x69, - 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x5a, 0x0a, 0x0b, 0x64, 0x65, - 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x38, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, - 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, - 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x0b, 0x64, 0x65, 0x70, 0x6c, 0x6f, - 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xb6, 0x01, 0x0a, 0x1f, 0x44, 0x65, 0x70, 0x6c, 0x6f, - 0x79, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x34, 0x0a, 0x16, 0x74, 0x65, - 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, 0x74, - 0x72, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x74, 0x65, 0x6c, 0x65, - 0x70, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, - 0x12, 0x15, 0x0a, 0x06, 0x76, 0x70, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x76, 0x70, 0x63, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x75, 0x62, 0x6e, 0x65, - 0x74, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x73, 0x75, 0x62, - 0x6e, 0x65, 0x74, 0x49, 0x64, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, - 0x74, 0x79, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x0e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x22, - 0x74, 0x0a, 0x1d, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, - 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x61, 0x72, 0x6e, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x41, 0x72, - 0x6e, 0x12, 0x32, 0x0a, 0x15, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x64, 0x61, 0x73, - 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x13, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x44, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, - 0x72, 0x64, 0x55, 0x72, 0x6c, 0x22, 0x7e, 0x0a, 0x23, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x65, 0x70, - 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, - 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, - 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x74, - 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x65, 0x78, 0x74, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xc2, 0x01, 0x0a, 0x17, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, - 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x32, 0x0a, 0x15, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x5f, 0x64, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x61, 0x73, - 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x55, 0x72, 0x6c, 0x12, 0x32, 0x0a, 0x15, 0x63, 0x6f, 0x6e, - 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x70, 0x6f, 0x69, - 0x6e, 0x74, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, - 0x6e, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x2b, 0x0a, - 0x11, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, - 0x6e, 0x64, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, - 0x6e, 0x65, 0x72, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x22, 0xb5, 0x01, 0x0a, 0x24, 0x4c, - 0x69, 0x73, 0x74, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x62, - 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x6e, 0x0a, 0x1a, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x5f, - 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x15, + 0x0a, 0x06, 0x76, 0x70, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x76, 0x70, 0x63, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x74, 0x6f, + 0x6b, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x65, 0x78, 0x74, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x59, 0x0a, 0x06, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x12, 0x12, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, + 0x69, 0x64, 0x12, 0x2b, 0x0a, 0x11, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x69, 0x6c, 0x69, + 0x74, 0x79, 0x5f, 0x7a, 0x6f, 0x6e, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x61, + 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x5a, 0x6f, 0x6e, 0x65, 0x22, + 0x6f, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, - 0x31, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, - 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x18, 0x64, 0x65, 0x70, 0x6c, 0x6f, - 0x79, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, - 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x65, 0x78, 0x74, 0x54, 0x6f, 0x6b, - 0x65, 0x6e, 0x22, 0x83, 0x03, 0x0a, 0x14, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x69, - 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, - 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, - 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, - 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, - 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x27, - 0x0a, 0x0f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, - 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, - 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x75, 0x62, 0x6e, 0x65, - 0x74, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x73, 0x75, 0x62, - 0x6e, 0x65, 0x74, 0x49, 0x64, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x72, - 0x6f, 0x6c, 0x65, 0x5f, 0x61, 0x72, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x74, - 0x61, 0x73, 0x6b, 0x52, 0x6f, 0x6c, 0x65, 0x41, 0x72, 0x6e, 0x12, 0x29, 0x0a, 0x10, 0x74, 0x65, - 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x56, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3b, 0x0a, 0x1a, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, - 0x65, 0x6e, 0x74, 0x5f, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x17, 0x64, 0x65, 0x70, 0x6c, 0x6f, - 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4a, 0x6f, 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x4e, 0x61, - 0x6d, 0x65, 0x12, 0x34, 0x0a, 0x16, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x63, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x09, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x14, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0xbd, 0x01, 0x0a, 0x15, 0x44, 0x65, 0x70, - 0x6c, 0x6f, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x61, 0x72, - 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, - 0x41, 0x72, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, - 0x72, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x41, 0x72, 0x6e, 0x12, 0x2e, 0x0a, 0x13, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x64, 0x65, 0x66, - 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x72, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x11, 0x74, 0x61, 0x73, 0x6b, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x41, 0x72, 0x6e, 0x12, 0x32, 0x0a, 0x15, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, - 0x64, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x13, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x61, 0x73, 0x68, - 0x62, 0x6f, 0x61, 0x72, 0x64, 0x55, 0x72, 0x6c, 0x22, 0xfe, 0x02, 0x0a, 0x18, 0x45, 0x6e, 0x72, - 0x6f, 0x6c, 0x6c, 0x45, 0x4b, 0x53, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, + 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, + 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x65, 0x78, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x22, 0x6a, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x50, 0x43, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, + 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x6e, 0x65, 0x78, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x29, 0x0a, 0x03, + 0x56, 0x50, 0x43, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x63, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x56, + 0x50, 0x43, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x04, 0x76, + 0x70, 0x63, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x65, 0x6c, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x50, 0x43, 0x52, 0x04, 0x76, 0x70, 0x63, 0x73, 0x12, 0x1d, 0x0a, + 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x6e, 0x65, 0x78, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xc0, 0x02, 0x0a, + 0x1c, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, + 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x16, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0d, 0x74, 0x61, 0x73, 0x6b, 0x5f, + 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x61, 0x72, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x74, 0x61, 0x73, 0x6b, 0x52, 0x6f, 0x6c, 0x65, 0x41, 0x72, 0x6e, 0x12, 0x29, 0x0a, 0x10, 0x74, + 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3b, 0x0a, 0x1a, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, + 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x17, 0x64, 0x65, 0x70, 0x6c, + 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4a, 0x6f, 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x4e, + 0x61, 0x6d, 0x65, 0x12, 0x5a, 0x0a, 0x0b, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x76, 0x31, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, + 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, + 0x6e, 0x74, 0x52, 0x0b, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, + 0xb6, 0x01, 0x0a, 0x1f, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, + 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, + 0x65, 0x6e, 0x74, 0x12, 0x34, 0x0a, 0x16, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x5f, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x14, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x15, 0x0a, 0x06, 0x76, 0x70, 0x63, + 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x70, 0x63, 0x49, 0x64, + 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x49, 0x64, 0x73, 0x12, + 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x67, 0x72, 0x6f, 0x75, + 0x70, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, + 0x74, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x22, 0x74, 0x0a, 0x1d, 0x44, 0x65, 0x70, 0x6c, + 0x6f, 0x79, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6c, 0x75, + 0x73, 0x74, 0x65, 0x72, 0x5f, 0x61, 0x72, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x41, 0x72, 0x6e, 0x12, 0x32, 0x0a, 0x15, 0x63, 0x6c, + 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x64, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x5f, + 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x63, 0x6c, 0x75, 0x73, 0x74, + 0x65, 0x72, 0x44, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x55, 0x72, 0x6c, 0x22, 0x7e, + 0x0a, 0x23, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x44, 0x61, + 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, - 0x2a, 0x0a, 0x11, 0x65, 0x6b, 0x73, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x65, 0x6b, 0x73, 0x43, - 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x30, 0x0a, 0x14, 0x65, - 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x70, 0x70, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, - 0x65, 0x72, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x65, 0x6e, 0x61, 0x62, 0x6c, - 0x65, 0x41, 0x70, 0x70, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x12, 0x23, 0x0a, - 0x0d, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x12, 0x65, 0x0a, 0x0c, 0x65, 0x78, 0x74, 0x72, 0x61, 0x5f, 0x6c, 0x61, 0x62, 0x65, - 0x6c, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x42, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, - 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x45, 0x4b, 0x53, 0x43, 0x6c, 0x75, 0x73, - 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x45, 0x78, 0x74, 0x72, - 0x61, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0b, 0x65, 0x78, - 0x74, 0x72, 0x61, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x1a, 0x3e, 0x0a, 0x10, 0x45, 0x78, 0x74, - 0x72, 0x61, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, - 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, - 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x98, 0x01, 0x0a, 0x16, 0x45, 0x6e, - 0x72, 0x6f, 0x6c, 0x6c, 0x45, 0x4b, 0x53, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x65, 0x6b, 0x73, 0x5f, 0x63, 0x6c, 0x75, 0x73, - 0x74, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, - 0x65, 0x6b, 0x73, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1f, - 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, - 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x5f, 0x74, - 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x73, 0x73, 0x75, 0x65, - 0x54, 0x79, 0x70, 0x65, 0x22, 0x66, 0x0a, 0x19, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x45, 0x4b, - 0x53, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x49, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, - 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x72, - 0x6f, 0x6c, 0x6c, 0x45, 0x4b, 0x53, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, - 0x75, 0x6c, 0x74, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x22, 0x69, 0x0a, 0x0e, - 0x4c, 0x69, 0x73, 0x74, 0x45, 0x43, 0x32, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, - 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x65, 0x78, 0x74, - 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x65, - 0x78, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x5b, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x45, - 0x43, 0x32, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x73, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x74, 0x79, - 0x70, 0x65, 0x73, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x56, 0x32, 0x52, 0x07, 0x73, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x74, 0x6f, - 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x65, 0x78, 0x74, 0x54, - 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x71, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x4b, 0x53, 0x43, + 0x1d, 0x0a, 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x65, 0x78, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xc2, + 0x01, 0x0a, 0x17, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x62, + 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x32, + 0x0a, 0x15, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x64, 0x61, 0x73, 0x68, 0x62, 0x6f, + 0x61, 0x72, 0x64, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x55, + 0x72, 0x6c, 0x12, 0x32, 0x0a, 0x15, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, + 0x65, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x13, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x2b, 0x0a, 0x11, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, + 0x6e, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x04, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x43, 0x6f, 0x6d, 0x6d, + 0x61, 0x6e, 0x64, 0x22, 0xb5, 0x01, 0x0a, 0x24, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x65, 0x70, 0x6c, + 0x6f, 0x79, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6e, 0x0a, 0x1a, + 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, + 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x30, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, + 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, + 0x79, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x52, 0x18, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, + 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, + 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x6e, 0x65, 0x78, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x83, 0x03, 0x0a, 0x14, + 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x27, + 0x0a, 0x0f, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x6f, 0x64, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, + 0x65, 0x6e, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x63, 0x75, 0x72, + 0x69, 0x74, 0x79, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x0e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, + 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x05, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x49, 0x64, 0x73, 0x12, + 0x22, 0x0a, 0x0d, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x61, 0x72, 0x6e, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x74, 0x61, 0x73, 0x6b, 0x52, 0x6f, 0x6c, 0x65, + 0x41, 0x72, 0x6e, 0x12, 0x29, 0x0a, 0x10, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x5f, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x74, + 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3b, + 0x0a, 0x1a, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6a, 0x6f, 0x69, + 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x17, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4a, 0x6f, + 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x34, 0x0a, 0x16, 0x74, + 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, + 0x74, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x74, 0x65, 0x6c, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x22, 0xbd, 0x01, 0x0a, 0x15, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x63, + 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x61, 0x72, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0a, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x41, 0x72, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x72, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x72, 0x6e, 0x12, 0x2e, 0x0a, + 0x13, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x61, 0x72, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x74, 0x61, 0x73, 0x6b, + 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x72, 0x6e, 0x12, 0x32, 0x0a, + 0x15, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x64, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, + 0x72, 0x64, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x55, 0x72, + 0x6c, 0x22, 0xfe, 0x02, 0x0a, 0x18, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x45, 0x4b, 0x53, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x65, 0x78, 0x74, - 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x65, - 0x78, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xe2, 0x03, 0x0a, 0x0a, 0x45, 0x4b, 0x53, 0x43, - 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, - 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, - 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x72, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x03, 0x61, 0x72, 0x6e, 0x12, 0x47, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x04, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, - 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x45, - 0x4b, 0x53, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x54, 0x0a, - 0x0b, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x05, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, - 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x4b, 0x53, - 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x4a, 0x6f, 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x65, - 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x6a, 0x6f, 0x69, 0x6e, 0x4c, 0x61, 0x62, - 0x65, 0x6c, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x34, 0x0a, 0x16, 0x65, - 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x61, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x65, 0x6e, 0x64, - 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x41, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x12, 0x2f, 0x0a, 0x13, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, - 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x6f, - 0x64, 0x65, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x2a, 0x0a, 0x11, 0x65, 0x6b, 0x73, 0x5f, + 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x0f, 0x65, 0x6b, 0x73, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, + 0x61, 0x6d, 0x65, 0x73, 0x12, 0x30, 0x0a, 0x14, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, + 0x70, 0x70, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x12, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x70, 0x70, 0x44, 0x69, 0x73, + 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x12, 0x23, 0x0a, 0x0d, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x61, + 0x67, 0x65, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x65, 0x0a, 0x0c, 0x65, + 0x78, 0x74, 0x72, 0x61, 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x42, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, + 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x72, 0x6f, + 0x6c, 0x6c, 0x45, 0x4b, 0x53, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x2e, 0x45, 0x78, 0x74, 0x72, 0x61, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0b, 0x65, 0x78, 0x74, 0x72, 0x61, 0x4c, 0x61, 0x62, 0x65, + 0x6c, 0x73, 0x1a, 0x3e, 0x0a, 0x10, 0x45, 0x78, 0x74, 0x72, 0x61, 0x4c, 0x61, 0x62, 0x65, 0x6c, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, + 0x38, 0x01, 0x22, 0x98, 0x01, 0x0a, 0x16, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x45, 0x4b, 0x53, + 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x28, 0x0a, + 0x10, 0x65, 0x6b, 0x73, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x65, 0x6b, 0x73, 0x43, 0x6c, 0x75, 0x73, + 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, + 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x1d, + 0x0a, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x69, 0x73, 0x73, 0x75, 0x65, 0x54, 0x79, 0x70, 0x65, 0x22, 0x66, 0x0a, + 0x19, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x45, 0x4b, 0x53, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, + 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x49, 0x0a, 0x07, 0x72, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x45, 0x4b, 0x53, 0x43, + 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x07, 0x72, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x73, 0x22, 0x6d, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x43, 0x32, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x6e, + 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x67, + 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, + 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x65, 0x78, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x3a, 0x02, 0x18, 0x01, 0x22, 0x5f, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x43, 0x32, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, + 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x56, 0x32, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x65, 0x78, 0x74, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x3a, 0x02, 0x18, 0x01, 0x22, 0x71, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x4b, 0x53, + 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x20, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x65, 0x78, + 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, + 0x65, 0x78, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xe2, 0x03, 0x0a, 0x0a, 0x45, 0x4b, 0x53, + 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, + 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x67, + 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x72, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x61, 0x72, 0x6e, 0x12, 0x47, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, + 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, + 0x45, 0x4b, 0x53, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x54, + 0x0a, 0x0b, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x05, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, + 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x4b, + 0x53, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x4a, 0x6f, 0x69, 0x6e, 0x4c, 0x61, 0x62, + 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x6a, 0x6f, 0x69, 0x6e, 0x4c, 0x61, + 0x62, 0x65, 0x6c, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x34, 0x0a, 0x16, + 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, + 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x65, 0x6e, + 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x41, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x12, 0x2f, 0x0a, 0x13, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x12, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, + 0x6f, 0x64, 0x65, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, + 0x0a, 0x0f, 0x4a, 0x6f, 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, 0x0a, - 0x0f, 0x4a, 0x6f, 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, - 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x79, 0x0a, 0x17, - 0x4c, 0x69, 0x73, 0x74, 0x45, 0x4b, 0x53, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x08, 0x63, 0x6c, 0x75, 0x73, 0x74, - 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x65, 0x6c, 0x65, - 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x4b, 0x53, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x08, - 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x65, 0x78, 0x74, - 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x65, - 0x78, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x4a, 0x0a, 0x0b, 0x50, 0x69, 0x6e, 0x67, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x6e, 0x74, - 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x6f, 0x6c, 0x65, - 0x5f, 0x61, 0x72, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x6f, 0x6c, 0x65, - 0x41, 0x72, 0x6e, 0x22, 0x58, 0x0a, 0x0c, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x72, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x03, 0x61, 0x72, 0x6e, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x32, 0xce, 0x0b, - 0x0a, 0x0e, 0x41, 0x57, 0x53, 0x4f, 0x49, 0x44, 0x43, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x12, 0x5f, 0x0a, 0x08, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x49, 0x43, 0x45, 0x12, 0x28, 0x2e, 0x74, - 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x49, 0x43, 0x45, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, - 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, - 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x49, 0x43, 0x45, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x65, 0x0a, 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x49, 0x43, 0x45, 0x12, - 0x2a, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x45, 0x49, 0x43, 0x45, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x74, 0x65, - 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x49, 0x43, 0x45, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6e, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, - 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x12, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, - 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, - 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7d, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, - 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x12, 0x32, - 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x63, - 0x75, 0x72, 0x69, 0x74, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, - 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x68, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x53, - 0x75, 0x62, 0x6e, 0x65, 0x74, 0x73, 0x12, 0x2b, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, - 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, - 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, - 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, - 0x73, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x5f, 0x0a, 0x08, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x50, 0x43, 0x73, 0x12, 0x28, 0x2e, + 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x79, 0x0a, + 0x17, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x4b, 0x53, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x08, 0x63, 0x6c, 0x75, 0x73, + 0x74, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x65, 0x6c, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x4b, 0x53, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, + 0x08, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x65, 0x78, + 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, + 0x65, 0x78, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x4a, 0x0a, 0x0b, 0x50, 0x69, 0x6e, 0x67, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x6e, + 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x6f, 0x6c, + 0x65, 0x5f, 0x61, 0x72, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x6f, 0x6c, + 0x65, 0x41, 0x72, 0x6e, 0x22, 0x58, 0x0a, 0x0c, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x72, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x61, 0x72, 0x6e, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x32, 0xdd, + 0x0b, 0x0a, 0x0e, 0x41, 0x57, 0x53, 0x4f, 0x49, 0x44, 0x43, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x12, 0x64, 0x0a, 0x08, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x49, 0x43, 0x45, 0x12, 0x28, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x50, 0x43, 0x73, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x49, 0x43, 0x45, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, - 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x50, 0x43, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x86, 0x01, 0x0a, 0x15, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x44, 0x61, 0x74, - 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x35, 0x2e, 0x74, - 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x44, 0x61, 0x74, - 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, - 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, - 0x70, 0x6c, 0x6f, 0x79, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x9b, 0x01, 0x0a, 0x1c, - 0x4c, 0x69, 0x73, 0x74, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, - 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x3c, 0x2e, 0x74, - 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x65, 0x70, 0x6c, 0x6f, - 0x79, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3d, 0x2e, 0x74, 0x65, 0x6c, - 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, - 0x64, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6e, 0x0a, 0x0d, 0x44, 0x65, 0x70, - 0x6c, 0x6f, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x2d, 0x2e, 0x74, 0x65, 0x6c, - 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, + 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x49, 0x43, 0x45, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x03, 0x88, 0x02, 0x01, 0x12, 0x6a, 0x0a, 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x45, 0x49, 0x43, 0x45, 0x12, 0x2a, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x49, 0x43, 0x45, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x2b, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, + 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x45, 0x49, 0x43, 0x45, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, + 0x88, 0x02, 0x01, 0x12, 0x6e, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, + 0x61, 0x73, 0x65, 0x73, 0x12, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, + 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, + 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x7d, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x63, 0x75, 0x72, + 0x69, 0x74, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x12, 0x32, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7a, 0x0a, 0x11, 0x45, 0x6e, 0x72, - 0x6f, 0x6c, 0x6c, 0x45, 0x4b, 0x53, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x12, 0x31, + 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, + 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x63, 0x75, + 0x72, 0x69, 0x74, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x68, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, + 0x73, 0x12, 0x2b, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, + 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x45, - 0x4b, 0x53, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x32, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, - 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x72, 0x6f, - 0x6c, 0x6c, 0x45, 0x4b, 0x53, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5c, 0x0a, 0x07, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x43, 0x32, - 0x12, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, - 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x45, - 0x43, 0x32, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x74, 0x65, 0x6c, 0x65, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, + 0x6e, 0x65, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5f, 0x0a, 0x08, + 0x4c, 0x69, 0x73, 0x74, 0x56, 0x50, 0x43, 0x73, 0x12, 0x28, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x50, 0x43, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, + 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, + 0x74, 0x56, 0x50, 0x43, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x86, 0x01, + 0x0a, 0x15, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x35, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, + 0x31, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, + 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x44, + 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x9b, 0x01, 0x0a, 0x1c, 0x4c, 0x69, 0x73, 0x74, 0x44, + 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x3c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, + 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x44, 0x61, + 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, + 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6e, 0x0a, 0x0d, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, + 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, + 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x44, + 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7a, 0x0a, 0x11, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x45, 0x4b, + 0x53, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x12, 0x31, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x43, 0x32, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x74, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x4b, 0x53, 0x43, 0x6c, + 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x45, 0x4b, 0x53, 0x43, 0x6c, 0x75, + 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x74, + 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x45, 0x4b, 0x53, + 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x61, 0x0a, 0x07, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x43, 0x32, 0x12, 0x27, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x43, 0x32, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, + 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x45, 0x43, 0x32, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, + 0x88, 0x02, 0x01, 0x12, 0x74, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x4b, 0x53, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x12, 0x2f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x4b, 0x53, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, diff --git a/api/gen/proto/go/teleport/integration/v1/awsoidc_service_grpc.pb.go b/api/gen/proto/go/teleport/integration/v1/awsoidc_service_grpc.pb.go index ad42b279f26f3..6e3313ceb331f 100644 --- a/api/gen/proto/go/teleport/integration/v1/awsoidc_service_grpc.pb.go +++ b/api/gen/proto/go/teleport/integration/v1/awsoidc_service_grpc.pb.go @@ -54,11 +54,13 @@ const ( // // AWSOIDCService provides access to AWS APIs using the AWS OIDC Integration. type AWSOIDCServiceClient interface { + // Deprecated: Do not use. // ListEICE returns a list of EC2 Instance Connect Endpoints. // An optional NextToken that can be used to fetch the next page. // It uses the following API: // https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeInstanceConnectEndpoints.html ListEICE(ctx context.Context, in *ListEICERequest, opts ...grpc.CallOption) (*ListEICEResponse, error) + // Deprecated: Do not use. // CreateEICE creates multiple EC2 Instance Connect Endpoint using the provided Subnets and Security Group IDs. // It uses the following API: // https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateInstanceConnectEndpoint.html @@ -88,6 +90,7 @@ type AWSOIDCServiceClient interface { DeployService(ctx context.Context, in *DeployServiceRequest, opts ...grpc.CallOption) (*DeployServiceResponse, error) // EnrollEKSClusters enrolls EKS clusters by installing kube agent Helm chart. EnrollEKSClusters(ctx context.Context, in *EnrollEKSClustersRequest, opts ...grpc.CallOption) (*EnrollEKSClustersResponse, error) + // Deprecated: Do not use. // ListEC2 lists the EC2 instances of the AWS account per region. // It uses the following API: // https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeInstances.html @@ -112,6 +115,7 @@ func NewAWSOIDCServiceClient(cc grpc.ClientConnInterface) AWSOIDCServiceClient { return &aWSOIDCServiceClient{cc} } +// Deprecated: Do not use. func (c *aWSOIDCServiceClient) ListEICE(ctx context.Context, in *ListEICERequest, opts ...grpc.CallOption) (*ListEICEResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListEICEResponse) @@ -122,6 +126,7 @@ func (c *aWSOIDCServiceClient) ListEICE(ctx context.Context, in *ListEICERequest return out, nil } +// Deprecated: Do not use. func (c *aWSOIDCServiceClient) CreateEICE(ctx context.Context, in *CreateEICERequest, opts ...grpc.CallOption) (*CreateEICEResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(CreateEICEResponse) @@ -212,6 +217,7 @@ func (c *aWSOIDCServiceClient) EnrollEKSClusters(ctx context.Context, in *Enroll return out, nil } +// Deprecated: Do not use. func (c *aWSOIDCServiceClient) ListEC2(ctx context.Context, in *ListEC2Request, opts ...grpc.CallOption) (*ListEC2Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListEC2Response) @@ -248,11 +254,13 @@ func (c *aWSOIDCServiceClient) Ping(ctx context.Context, in *PingRequest, opts . // // AWSOIDCService provides access to AWS APIs using the AWS OIDC Integration. type AWSOIDCServiceServer interface { + // Deprecated: Do not use. // ListEICE returns a list of EC2 Instance Connect Endpoints. // An optional NextToken that can be used to fetch the next page. // It uses the following API: // https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeInstanceConnectEndpoints.html ListEICE(context.Context, *ListEICERequest) (*ListEICEResponse, error) + // Deprecated: Do not use. // CreateEICE creates multiple EC2 Instance Connect Endpoint using the provided Subnets and Security Group IDs. // It uses the following API: // https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateInstanceConnectEndpoint.html @@ -282,6 +290,7 @@ type AWSOIDCServiceServer interface { DeployService(context.Context, *DeployServiceRequest) (*DeployServiceResponse, error) // EnrollEKSClusters enrolls EKS clusters by installing kube agent Helm chart. EnrollEKSClusters(context.Context, *EnrollEKSClustersRequest) (*EnrollEKSClustersResponse, error) + // Deprecated: Do not use. // ListEC2 lists the EC2 instances of the AWS account per region. // It uses the following API: // https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeInstances.html diff --git a/api/proto/teleport/integration/v1/awsoidc_service.proto b/api/proto/teleport/integration/v1/awsoidc_service.proto index fed5a7ffb63a8..28f81c87b5060 100644 --- a/api/proto/teleport/integration/v1/awsoidc_service.proto +++ b/api/proto/teleport/integration/v1/awsoidc_service.proto @@ -26,12 +26,18 @@ service AWSOIDCService { // An optional NextToken that can be used to fetch the next page. // It uses the following API: // https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeInstanceConnectEndpoints.html - rpc ListEICE(ListEICERequest) returns (ListEICEResponse); + rpc ListEICE(ListEICERequest) returns (ListEICEResponse) { + // TODO(marco): DELETE IN v19.0.0 + option deprecated = true; + } // CreateEICE creates multiple EC2 Instance Connect Endpoint using the provided Subnets and Security Group IDs. // It uses the following API: // https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateInstanceConnectEndpoint.html - rpc CreateEICE(CreateEICERequest) returns (CreateEICEResponse); + rpc CreateEICE(CreateEICERequest) returns (CreateEICEResponse) { + // TODO(marco): DELETE IN v19.0.0 + option deprecated = true; + } // ListDatabases calls the following AWS API: // https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_DescribeDBClusters.html @@ -69,7 +75,10 @@ service AWSOIDCService { // ListEC2 lists the EC2 instances of the AWS account per region. // It uses the following API: // https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeInstances.html - rpc ListEC2(ListEC2Request) returns (ListEC2Response); + rpc ListEC2(ListEC2Request) returns (ListEC2Response) { + // TODO(marco): DELETE IN v19.0.0 + option deprecated = true; + } // ListEKSClusters retrieves a paginated list of EKS clusters in the specified AWS region for a specific account. // It uses the following APIs: @@ -86,6 +95,7 @@ service AWSOIDCService { // ListEICERequest is a request for a paginated list of AWS EC2 Instance Connect Endpoints. message ListEICERequest { + option deprecated = true; // Integration is the AWS OIDC Integration name. // Required. string integration = 1; @@ -102,6 +112,7 @@ message ListEICERequest { // EC2InstanceConnectEndpoint is a representation of a Amazon VPC EC2 Instance Connect Endpoint. message EC2InstanceConnectEndpoint { + option deprecated = true; // Name is the endpoint name. string name = 1; // State is the endpoint state. @@ -120,6 +131,7 @@ message EC2InstanceConnectEndpoint { // ListEICEResponse contains a page of AWS EC2 Instance Connect Endpoints. message ListEICEResponse { + option deprecated = true; // EC2ICEs contains the page of EC2 Instance Connect Endpoints. repeated EC2InstanceConnectEndpoint ec2ices = 1; // DashboardLink is the URL for AWS Web Console that lists all the Endpoints for the queries VPCs. @@ -131,6 +143,7 @@ message ListEICEResponse { // CreateEICERequest contains the required fields to create an AWS EC2 Instance Connect Endpoint. message CreateEICERequest { + option deprecated = true; // Integration is the AWS OIDC Integration name. // Required. string integration = 1; @@ -144,6 +157,7 @@ message CreateEICERequest { // EC2ICEndpoint contains the information for a single Endpoint to be created. message EC2ICEndpoint { + option deprecated = true; // Name is the endpoint name. string name = 1; // SubnetID is the Subnet where the Endpoint will be created. @@ -155,6 +169,7 @@ message EC2ICEndpoint { // CreateEICEResponse is a request to create a VPC Endpoint of EC2 Instance Connect Endpoint type. message CreateEICEResponse { + option deprecated = true; // Name is the Endpoint ID. string name = 1; // CreatedEndpoints contains the name of created endpoints and their Subnet. @@ -514,6 +529,7 @@ message EnrollEKSClustersResponse { // ListEC2Request is a request for a paginated list of AWS EC2 instances. message ListEC2Request { + option deprecated = true; // Integration is the AWS OIDC Integration name. // Required. string integration = 1; @@ -527,6 +543,7 @@ message ListEC2Request { // ListEC2Response contains a page of AWS EC2 instances represented as Nodes. message ListEC2Response { + option deprecated = true; // Servers contains the page of EC2. repeated types.ServerV2 servers = 1; // NextToken is used for pagination. diff --git a/lib/auth/integration/integrationv1/awsoidc.go b/lib/auth/integration/integrationv1/awsoidc.go index bcdff34276968..229b2a9e443ad 100644 --- a/lib/auth/integration/integrationv1/awsoidc.go +++ b/lib/auth/integration/integrationv1/awsoidc.go @@ -200,6 +200,8 @@ func (s *AWSOIDCService) awsClientReq(ctx context.Context, integrationName, regi } // ListEICE returns a paginated list of EC2 Instance Connect Endpoints. +// +// Deprecated: Marked as deprecated in teleport/integration/v1/awsoidc_service.proto. func (s *AWSOIDCService) ListEICE(ctx context.Context, req *integrationpb.ListEICERequest) (*integrationpb.ListEICEResponse, error) { authCtx, err := s.authorizer.Authorize(ctx) if err != nil { @@ -249,6 +251,8 @@ func (s *AWSOIDCService) ListEICE(ctx context.Context, req *integrationpb.ListEI } // CreateEICE creates multiple EC2 Instance Connect Endpoint using the provided Subnets and Security Group IDs. +// +// Deprecated: Marked as deprecated in teleport/integration/v1/awsoidc_service.proto. func (s *AWSOIDCService) CreateEICE(ctx context.Context, req *integrationpb.CreateEICERequest) (*integrationpb.CreateEICEResponse, error) { authCtx, err := s.authorizer.Authorize(ctx) if err != nil { @@ -661,6 +665,8 @@ func (s *AWSOIDCService) DeployService(ctx context.Context, req *integrationpb.D } // ListEC2 returns a paginated list of AWS EC2 instances. +// +// Deprecated: Marked as deprecated in teleport/integration/v1/awsoidc_service.proto. func (s *AWSOIDCService) ListEC2(ctx context.Context, req *integrationpb.ListEC2Request) (*integrationpb.ListEC2Response, error) { authCtx, err := s.authorizer.Authorize(ctx) if err != nil { diff --git a/lib/auth/integration/integrationv1/awsoidc_test.go b/lib/auth/integration/integrationv1/awsoidc_test.go index 6a2497229ab38..f5fff709faabb 100644 --- a/lib/auth/integration/integrationv1/awsoidc_test.go +++ b/lib/auth/integration/integrationv1/awsoidc_test.go @@ -240,18 +240,6 @@ func TestRBAC(t *testing.T) { userCtx := authorizerForDummyUser(t, ctx, role, localClient) for _, tt := range []endpointSubtest{ - { - name: "ListEICE", - fn: func() error { - _, err := awsoidService.ListEICE(userCtx, &integrationv1.ListEICERequest{ - Integration: integrationName, - Region: "my-region", - VpcIds: []string{"vpc-123"}, - NextToken: "", - }) - return err - }, - }, { name: "ListDatabases", fn: func() error { @@ -347,18 +335,6 @@ func TestRBAC(t *testing.T) { userCtx := authorizerForDummyUser(t, ctx, role, localClient) for _, tt := range []endpointSubtest{ - { - name: "ListEICE", - fn: func() error { - _, err := awsoidService.ListEICE(userCtx, &integrationv1.ListEICERequest{ - Integration: integrationName, - Region: "my-region", - VpcIds: []string{"vpc-123"}, - NextToken: "", - }) - return err - }, - }, { name: "ListDatabases", fn: func() error { diff --git a/lib/config/configuration.go b/lib/config/configuration.go index ee377cd41f8bb..fbe9a1d5ddf40 100644 --- a/lib/config/configuration.go +++ b/lib/config/configuration.go @@ -210,10 +210,6 @@ type CommandLineFlags struct { // `teleport integration configure deployservice-iam` command IntegrationConfDeployServiceIAMArguments IntegrationConfDeployServiceIAM - // IntegrationConfEICEIAMArguments contains the arguments of - // `teleport integration configure eice-iam` command - IntegrationConfEICEIAMArguments IntegrationConfEICEIAM - // IntegrationConfAWSAppAccessIAMArguments contains the arguments of // `teleport integration configure aws-app-access-iam` command IntegrationConfAWSAppAccessIAMArguments IntegrationConfAWSAppAccessIAM @@ -329,19 +325,6 @@ type IntegrationConfDeployServiceIAM struct { AutoConfirm bool } -// IntegrationConfEICEIAM contains the arguments of -// `teleport integration configure eice-iam` command -type IntegrationConfEICEIAM struct { - // Region is the AWS Region used to set up the client. - Region string - // Role is the AWS Role associated with the Integration - Role string - // AccountID is the AWS account ID. - AccountID string - // AutoConfirm skips user confirmation of the operation plan if true. - AutoConfirm bool -} - // IntegrationConfAWSAppAccessIAM contains the arguments of // `teleport integration configure aws-app-access-iam` command type IntegrationConfAWSAppAccessIAM struct { diff --git a/lib/integrations/awsoidc/eice_iam_config.go b/lib/integrations/awsoidc/eice_iam_config.go deleted file mode 100644 index 7026fa97fef5e..0000000000000 --- a/lib/integrations/awsoidc/eice_iam_config.go +++ /dev/null @@ -1,160 +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 . - */ - -package awsoidc - -import ( - "context" - "io" - - "github.com/aws/aws-sdk-go-v2/config" - "github.com/aws/aws-sdk-go-v2/service/iam" - "github.com/aws/aws-sdk-go-v2/service/sts" - "github.com/gravitational/trace" - - awslib "github.com/gravitational/teleport/lib/cloud/aws" - "github.com/gravitational/teleport/lib/cloud/provisioning" - "github.com/gravitational/teleport/lib/cloud/provisioning/awsactions" -) - -const ( - // defaultPolicyNameForEICE is the default name for the Inline Policy added to the IntegrationRole. - defaultPolicyNameForEICE = "EC2InstanceConnectEndpoint" -) - -// EICEIAMConfigureRequest is a request to configure the required Policies to use the EC2 Instance Connect Endpoint feature. -type EICEIAMConfigureRequest struct { - // Region is the AWS Region. - // Used to set up the AWS SDK Client. - Region string - - // IntegrationRole is the Integration's AWS Role used to set up Teleport as an OIDC IdP. - IntegrationRole string - - // IntegrationRoleEICEPolicy is the Policy Name that is created to allow access to call AWS APIs. - // Defaults to EC2InstanceConnectEndpoint - IntegrationRoleEICEPolicy string - - // AccountID is the AWS Account ID. - AccountID string - - // AutoConfirm skips user confirmation of the operation plan if true. - AutoConfirm bool - - // stdout is used to override stdout output in tests. - stdout io.Writer -} - -// CheckAndSetDefaults ensures the required fields are present. -func (r *EICEIAMConfigureRequest) CheckAndSetDefaults() error { - if r.Region == "" { - return trace.BadParameter("region is required") - } - - if r.IntegrationRole == "" { - return trace.BadParameter("integration role is required") - } - - if r.IntegrationRoleEICEPolicy == "" { - r.IntegrationRoleEICEPolicy = defaultPolicyNameForEICE - } - - return nil -} - -// EICEIAMConfigureClient describes the required methods to create the IAM Policies required for accessing EC2 instances usine EICE. -type EICEIAMConfigureClient interface { - CallerIdentityGetter - awsactions.RolePolicyPutter -} - -type defaultEICEIAMConfigureClient struct { - CallerIdentityGetter - *iam.Client -} - -// NewEICEIAMConfigureClient creates a new EICEIAMConfigureClient. -func NewEICEIAMConfigureClient(ctx context.Context, region string) (EICEIAMConfigureClient, error) { - if region == "" { - return nil, trace.BadParameter("region is required") - } - - cfg, err := config.LoadDefaultConfig(ctx, config.WithRegion(region)) - if err != nil { - return nil, trace.Wrap(err) - } - - return &defaultEICEIAMConfigureClient{ - CallerIdentityGetter: sts.NewFromConfig(cfg), - Client: iam.NewFromConfig(cfg), - }, nil -} - -// ConfigureEICEIAM set ups the roles required for accessing an EC2 Instance using EICE. -// It creates an embedded policy with the following permissions: -// -// Action: List EC2 instances to add them as Teleport Nodes -// - ec2:DescribeInstances -// -// Action: List EC2 Instance Connect Endpoints so that knows if they must create one Endpoint. -// - ec2:DescribeInstanceConnectEndpoints -// -// Action: Select one or more SecurityGroups to apply to the EC2 Instance Connect Endpoints (the VPC's default SG is applied if no SG is provided). -// - ec2:DescribeSecurityGroups -// -// Action: Create EC2 Instance Connect Endpoint so the user can open a tunnel to the EC2 instance. -// More info: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/permissions-for-ec2-instance-connect-endpoint.html -// - ec2:CreateInstanceConnectEndpoint -// - ec2:CreateTags -// - ec2:CreateNetworkInterface -// - iam:CreateServiceLinkedRole -// -// Action: Send a temporary SSH Key to the target host. -// - ec2-instance-connect:SendSSHPublicKey -// -// Action: Open a Tunnel to the EC2 using the Endpoint -// - ec2-instance-connect:OpenTunnel -// -// The following actions must be allowed by the IAM Role assigned in the Client. -// - iam:PutRolePolicy -func ConfigureEICEIAM(ctx context.Context, clt EICEIAMConfigureClient, req EICEIAMConfigureRequest) error { - if err := req.CheckAndSetDefaults(); err != nil { - return trace.Wrap(err) - } - - if err := CheckAccountID(ctx, clt, req.AccountID); err != nil { - return trace.Wrap(err) - } - - policy := awslib.NewPolicyDocument( - awslib.StatementForEC2InstanceConnectEndpoint(), - ) - putRolePolicy, err := awsactions.PutRolePolicy(clt, req.IntegrationRoleEICEPolicy, req.IntegrationRole, policy) - if err != nil { - return trace.Wrap(err) - } - - return trace.Wrap(provisioning.Run(ctx, provisioning.OperationConfig{ - Name: "eice-iam", - Actions: []provisioning.Action{ - *putRolePolicy, - }, - AutoConfirm: req.AutoConfirm, - Output: req.stdout, - })) -} diff --git a/lib/integrations/awsoidc/eice_iam_config_test.go b/lib/integrations/awsoidc/eice_iam_config_test.go deleted file mode 100644 index db7bc840f7e5d..0000000000000 --- a/lib/integrations/awsoidc/eice_iam_config_test.go +++ /dev/null @@ -1,199 +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 . - */ - -package awsoidc - -import ( - "bytes" - "context" - "fmt" - "slices" - "testing" - - "github.com/aws/aws-sdk-go-v2/service/iam" - iamtypes "github.com/aws/aws-sdk-go-v2/service/iam/types" - "github.com/stretchr/testify/require" - - "github.com/gravitational/teleport/lib/utils/testutils/golden" -) - -func TestEICEIAMConfigReqDefaults(t *testing.T) { - baseReq := func() EICEIAMConfigureRequest { - return EICEIAMConfigureRequest{ - Region: "us-east-1", - IntegrationRole: "integrationrole", - AccountID: "123456789012", - AutoConfirm: true, - } - } - - for _, tt := range []struct { - name string - req func() EICEIAMConfigureRequest - errCheck require.ErrorAssertionFunc - expected EICEIAMConfigureRequest - }{ - { - name: "set defaults", - req: baseReq, - errCheck: require.NoError, - expected: EICEIAMConfigureRequest{ - AccountID: "123456789012", - Region: "us-east-1", - IntegrationRole: "integrationrole", - IntegrationRoleEICEPolicy: "EC2InstanceConnectEndpoint", - AutoConfirm: true, - }, - }, - { - name: "missing region", - req: func() EICEIAMConfigureRequest { - req := baseReq() - req.Region = "" - return req - }, - errCheck: badParameterCheck, - }, - { - name: "missing integration role", - req: func() EICEIAMConfigureRequest { - req := baseReq() - req.IntegrationRole = "" - return req - }, - errCheck: badParameterCheck, - }, - { - name: "missing account id is ok", - req: func() EICEIAMConfigureRequest { - req := baseReq() - req.AccountID = "" - return req - }, - errCheck: require.NoError, - expected: EICEIAMConfigureRequest{ - Region: "us-east-1", - IntegrationRole: "integrationrole", - IntegrationRoleEICEPolicy: "EC2InstanceConnectEndpoint", - AutoConfirm: true, - }, - }, - } { - t.Run(tt.name, func(t *testing.T) { - req := tt.req() - err := req.CheckAndSetDefaults() - tt.errCheck(t, err) - if err != nil { - return - } - - require.Equal(t, tt.expected, req) - }) - } -} - -func TestEICEIAMConfig(t *testing.T) { - ctx := context.Background() - baseReq := func() EICEIAMConfigureRequest { - return EICEIAMConfigureRequest{ - Region: "us-east-1", - IntegrationRole: "integrationrole", - AccountID: "123456789012", - AutoConfirm: true, - } - } - - for _, tt := range []struct { - name string - mockAccountID string - mockExistingRoles []string - req func() EICEIAMConfigureRequest - errCheck require.ErrorAssertionFunc - }{ - { - name: "valid", - req: baseReq, - mockAccountID: "123456789012", - mockExistingRoles: []string{"integrationrole"}, - errCheck: require.NoError, - }, - { - name: "integration role does not exist", - mockAccountID: "123456789012", - mockExistingRoles: []string{}, - req: baseReq, - errCheck: notFoundCheck, - }, - { - name: "account does not match expected account", - req: baseReq, - mockAccountID: "222222222222", - mockExistingRoles: []string{"integrationrole"}, - errCheck: badParameterCheck, - }, - } { - t.Run(tt.name, func(t *testing.T) { - clt := mockEICEIAMConfigClient{ - CallerIdentityGetter: mockSTSClient{accountID: tt.mockAccountID}, - existingRoles: tt.mockExistingRoles, - } - - err := ConfigureEICEIAM(ctx, &clt, tt.req()) - tt.errCheck(t, err) - }) - } -} - -func TestEICEIAMConfigOutput(t *testing.T) { - ctx := context.Background() - var buf bytes.Buffer - req := EICEIAMConfigureRequest{ - Region: "us-east-1", - IntegrationRole: "integrationrole", - AccountID: "123456789012", - AutoConfirm: true, - stdout: &buf, - } - - clt := mockEICEIAMConfigClient{ - CallerIdentityGetter: mockSTSClient{accountID: req.AccountID}, - existingRoles: []string{req.IntegrationRole}, - } - - require.NoError(t, ConfigureEICEIAM(ctx, &clt, req)) - if golden.ShouldSet() { - golden.Set(t, buf.Bytes()) - } - require.Equal(t, string(golden.Get(t)), buf.String()) -} - -type mockEICEIAMConfigClient struct { - CallerIdentityGetter - existingRoles []string -} - -// PutRolePolicy creates or replaces a Policy by its name in a IAM Role. -func (m *mockEICEIAMConfigClient) PutRolePolicy(ctx context.Context, params *iam.PutRolePolicyInput, optFns ...func(*iam.Options)) (*iam.PutRolePolicyOutput, error) { - if !slices.Contains(m.existingRoles, *params.RoleName) { - noSuchEntityMessage := fmt.Sprintf("role %q does not exist.", *params.RoleName) - return nil, &iamtypes.NoSuchEntityException{ - Message: &noSuchEntityMessage, - } - } - return nil, nil -} diff --git a/lib/integrations/awsoidc/testdata/TestEICEIAMConfigOutput.golden b/lib/integrations/awsoidc/testdata/TestEICEIAMConfigOutput.golden deleted file mode 100644 index 318067357a97c..0000000000000 --- a/lib/integrations/awsoidc/testdata/TestEICEIAMConfigOutput.golden +++ /dev/null @@ -1,28 +0,0 @@ -"eice-iam" will perform the following action: - -Attach an inline IAM policy named "EC2InstanceConnectEndpoint" to IAM role "integrationrole". -PutRolePolicy: { - "PolicyDocument": { - "Version": "2012-10-17", - "Statement": [ - { - "Effect": "Allow", - "Action": [ - "ec2:DescribeInstances", - "ec2:DescribeInstanceConnectEndpoints", - "ec2:DescribeSecurityGroups", - "ec2:CreateInstanceConnectEndpoint", - "ec2:CreateTags", - "ec2:CreateNetworkInterface", - "iam:CreateServiceLinkedRole", - "ec2-instance-connect:SendSSHPublicKey", - "ec2-instance-connect:OpenTunnel" - ], - "Resource": "*" - } - ] - }, - "PolicyName": "EC2InstanceConnectEndpoint", - "RoleName": "integrationrole" -} - diff --git a/lib/usagereporter/web/userevent.go b/lib/usagereporter/web/userevent.go index aab5706db84ca..5af970b7ce6b5 100644 --- a/lib/usagereporter/web/userevent.go +++ b/lib/usagereporter/web/userevent.go @@ -58,9 +58,6 @@ const ( uiDiscoverDesktopActiveDirectoryToolsInstallEvent = "tp.ui.discover.desktop.activeDirectory.tools.install" uiDiscoverDesktopActiveDirectoryConfigureEvent = "tp.ui.discover.desktop.activeDirectory.configure" uiDiscoverAutoDiscoveredResourcesEvent = "tp.ui.discover.autoDiscoveredResources" - uiDiscoverEC2InstanceSelectionEvent = "tp.ui.discover.selectedEC2Instance" - uiDiscoverDeployEICEEvent = "tp.ui.discover.deployEICE" - uiDiscoverCreateNodeEvent = "tp.ui.discover.createNode" uiDiscoverCreateAppServerEvent = "tp.ui.discover.createAppServer" uiDiscoverCreateDiscoveryConfigEvent = "tp.ui.discover.createDiscoveryConfig" uiDiscoverPrincipalsConfigureEvent = "tp.ui.discover.principals.configure" @@ -302,9 +299,6 @@ func ConvertUserEventRequestToUsageEvent(req CreateUserEventRequest) (*usageeven uiDiscoverAutoDiscoveredResourcesEvent, uiDiscoverPrincipalsConfigureEvent, uiDiscoverTestConnectionEvent, - uiDiscoverEC2InstanceSelectionEvent, - uiDiscoverDeployEICEEvent, - uiDiscoverCreateNodeEvent, uiDiscoverCreateAppServerEvent, uiDiscoverCreateDiscoveryConfigEvent, uiDiscoverCompletedEvent: diff --git a/lib/usagereporter/web/userevent_discover.go b/lib/usagereporter/web/userevent_discover.go index fb96620e26bb7..2a31bf7cdaf6f 100644 --- a/lib/usagereporter/web/userevent_discover.go +++ b/lib/usagereporter/web/userevent_discover.go @@ -219,33 +219,6 @@ func (d *DiscoverEventData) ToUsageEvent(eventName string) (*usageeventsv1.Usage }, }}, nil - case uiDiscoverEC2InstanceSelectionEvent: - return &usageeventsv1.UsageEventOneOf{Event: &usageeventsv1.UsageEventOneOf_UiDiscoverEc2InstanceSelection{ - UiDiscoverEc2InstanceSelection: &usageeventsv1.UIDiscoverEC2InstanceSelectionEvent{ - Metadata: metadata, - Resource: resource, - Status: status, - }, - }}, nil - - case uiDiscoverDeployEICEEvent: - return &usageeventsv1.UsageEventOneOf{Event: &usageeventsv1.UsageEventOneOf_UiDiscoverDeployEice{ - UiDiscoverDeployEice: &usageeventsv1.UIDiscoverDeployEICEEvent{ - Metadata: metadata, - Resource: resource, - Status: status, - }, - }}, nil - - case uiDiscoverCreateNodeEvent: - return &usageeventsv1.UsageEventOneOf{Event: &usageeventsv1.UsageEventOneOf_UiDiscoverCreateNode{ - UiDiscoverCreateNode: &usageeventsv1.UIDiscoverCreateNodeEvent{ - Metadata: metadata, - Resource: resource, - Status: status, - }, - }}, nil - case uiDiscoverCreateAppServerEvent: return &usageeventsv1.UsageEventOneOf{Event: &usageeventsv1.UsageEventOneOf_UiDiscoverCreateAppServerEvent{ UiDiscoverCreateAppServerEvent: &usageeventsv1.UIDiscoverCreateAppServerEvent{ diff --git a/lib/web/apiserver.go b/lib/web/apiserver.go index d28b29f109aa3..86b073588f27b 100644 --- a/lib/web/apiserver.go +++ b/lib/web/apiserver.go @@ -1022,20 +1022,16 @@ func (h *Handler) bindDefaultEndpoints() { h.POST("/webapi/sites/:site/integrations/aws-oidc/:name/deploydatabaseservices", h.WithClusterAuth(h.awsOIDCDeployDatabaseServices)) h.POST("/webapi/sites/:site/integrations/aws-oidc/:name/listdeployeddatabaseservices", h.WithClusterAuth(h.awsOIDCListDeployedDatabaseService)) h.GET("/webapi/scripts/integrations/configure/deployservice-iam.sh", h.WithLimiter(h.awsOIDCConfigureDeployServiceIAM)) - h.POST("/webapi/sites/:site/integrations/aws-oidc/:name/ec2", h.WithClusterAuth(h.awsOIDCListEC2)) h.POST("/webapi/sites/:site/integrations/aws-oidc/:name/eksclusters", h.WithClusterAuth(h.awsOIDCListEKSClusters)) // TODO(kimlisa): DELETE IN 19.0 - replaced by /v2/webapi/sites/:site/integrations/aws-oidc/:name/enrolleksclusters // MUST delete with related code found in web/packages/teleport/src/services/integrations/integrations.ts(enrollEksClusters) h.POST("/webapi/sites/:site/integrations/aws-oidc/:name/enrolleksclusters", h.WithClusterAuth(h.awsOIDCEnrollEKSClusters)) // v2 endpoint introduces "extraLabels" field. h.POST("/v2/webapi/sites/:site/integrations/aws-oidc/:name/enrolleksclusters", h.WithClusterAuth(h.awsOIDCEnrollEKSClusters)) - h.POST("/webapi/sites/:site/integrations/aws-oidc/:name/ec2ice", h.WithClusterAuth(h.awsOIDCListEC2ICE)) - h.POST("/webapi/sites/:site/integrations/aws-oidc/:name/deployec2ice", h.WithClusterAuth(h.awsOIDCDeployEC2ICE)) h.POST("/webapi/sites/:site/integrations/aws-oidc/:name/securitygroups", h.WithClusterAuth(h.awsOIDCListSecurityGroups)) h.POST("/webapi/sites/:site/integrations/aws-oidc/:name/databasevpcs", h.WithClusterAuth(h.awsOIDCListDatabaseVPCs)) h.POST("/webapi/sites/:site/integrations/aws-oidc/:name/subnets", h.WithClusterAuth(h.awsOIDCListSubnets)) h.POST("/webapi/sites/:site/integrations/aws-oidc/:name/requireddatabasesvpcs", h.WithClusterAuth(h.awsOIDCRequiredDatabasesVPCS)) - h.GET("/webapi/scripts/integrations/configure/eice-iam.sh", h.WithLimiter(h.awsOIDCConfigureEICEIAM)) h.GET("/webapi/scripts/integrations/configure/eks-iam.sh", h.WithLimiter(h.awsOIDCConfigureEKSIAM)) h.GET("/webapi/scripts/integrations/configure/access-graph-cloud-sync-iam.sh", h.WithLimiter(h.accessGraphCloudSyncOIDC)) h.GET("/webapi/scripts/integrations/configure/aws-app-access-iam.sh", h.WithLimiter(h.awsOIDCConfigureAWSAppAccessIAM)) diff --git a/lib/web/integrations_awsoidc.go b/lib/web/integrations_awsoidc.go index 028cd8635121d..27261a1fa6570 100644 --- a/lib/web/integrations_awsoidc.go +++ b/lib/web/integrations_awsoidc.go @@ -555,48 +555,6 @@ func (h *Handler) awsOIDCConfigureDeployServiceIAM(w http.ResponseWriter, r *htt return nil, trace.Wrap(err) } -// awsOIDCConfigureEICEIAM returns a script that configures the required IAM permissions to enable the usage of EC2 Instance Connect Endpoint -// to access EC2 instances. -func (h *Handler) awsOIDCConfigureEICEIAM(w http.ResponseWriter, r *http.Request, p httprouter.Params) (any, error) { - queryParams := r.URL.Query() - - awsRegion := queryParams.Get("awsRegion") - if err := aws.IsValidRegion(awsRegion); err != nil { - return nil, trace.BadParameter("invalid awsRegion") - } - - awsAccountID := queryParams.Get("awsAccountID") - if err := aws.IsValidAccountID(awsAccountID); err != nil { - return nil, trace.Wrap(err, "invalid awsAccountID") - } - - role := queryParams.Get("role") - if err := aws.IsValidIAMRoleName(role); err != nil { - return nil, trace.BadParameter("invalid role %q", role) - } - - // The script must execute the following command: - // teleport integration configure eice-iam - argsList := []string{ - "integration", "configure", "eice-iam", - fmt.Sprintf("--aws-region=%s", shsprintf.EscapeDefaultContext(awsRegion)), - fmt.Sprintf("--role=%s", shsprintf.EscapeDefaultContext(role)), - fmt.Sprintf("--aws-account-id=%s", shsprintf.EscapeDefaultContext(awsAccountID)), - } - script, err := oneoff.BuildScript(oneoff.OneOffScriptParams{ - TeleportArgs: strings.Join(argsList, " "), - SuccessMessage: "Success! You can now go back to the Teleport Web UI to complete the EC2 enrollment.", - }) - if err != nil { - return nil, trace.Wrap(err) - } - - httplib.SetScriptHeaders(w.Header()) - _, err = fmt.Fprint(w, script) - - return nil, trace.Wrap(err) -} - // awsOIDCConfigureAppAccessIAM returns a script that configures the required IAM permissions to enable App Access // using the AWS OIDC Credentials. // Only IAM Roles with `teleport.dev/integration: Allowed` Tag can be used. @@ -833,56 +791,6 @@ func (h *Handler) awsOIDCListEKSClusters(w http.ResponseWriter, r *http.Request, }, nil } -// awsOIDCListEC2 returns a list of EC2 Instances using the ListEC2 action of the AWS OIDC Integration. -func (h *Handler) awsOIDCListEC2(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (any, error) { - ctx := r.Context() - - var req ui.AWSOIDCListEC2Request - if err := httplib.ReadJSON(r, &req); err != nil { - return nil, trace.Wrap(err) - } - - integrationName := p.ByName("name") - if integrationName == "" { - return nil, trace.BadParameter("an integration name is required") - } - - clt, err := sctx.GetUserClient(ctx, site) - if err != nil { - return nil, trace.Wrap(err) - } - - listResp, err := clt.IntegrationAWSOIDCClient().ListEC2(ctx, &integrationv1.ListEC2Request{ - Integration: integrationName, - Region: req.Region, - NextToken: req.NextToken, - }) - if err != nil { - return nil, trace.Wrap(err) - } - - accessChecker, err := sctx.GetUserAccessChecker() - if err != nil { - return nil, trace.Wrap(err) - } - - servers := make([]ui.Server, 0, len(listResp.Servers)) - for _, s := range listResp.Servers { - logins, err := accessChecker.GetAllowedLoginsForResource(s) - if err != nil { - return nil, trace.Wrap(err) - } - slices.Sort(logins) - - servers = append(servers, ui.MakeServer(h.auth.clusterName, s, logins, false /* requiresRequest */)) - } - - return ui.AWSOIDCListEC2Response{ - NextToken: listResp.NextToken, - Servers: servers, - }, nil -} - // awsOIDCListSecurityGroups returns a list of VPC Security Groups using the ListSecurityGroups action of the AWS OIDC Integration. func (h *Handler) awsOIDCListSecurityGroups(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (any, error) { ctx := r.Context() @@ -1088,117 +996,6 @@ func awsOIDCRequiredVPCSHelper(ctx context.Context, clt client.GetResourcesClien }, nil } -// awsOIDCListEC2ICE returns a list of EC2 Instance Connect Endpoints using the ListEC2ICE action of the AWS OIDC Integration. -func (h *Handler) awsOIDCListEC2ICE(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (any, error) { - ctx := r.Context() - - var req ui.AWSOIDCListEC2ICERequest - if err := httplib.ReadJSON(r, &req); err != nil { - return nil, trace.Wrap(err) - } - - integrationName := p.ByName("name") - if integrationName == "" { - return nil, trace.BadParameter("an integration name is required") - } - - clt, err := sctx.GetUserClient(ctx, site) - if err != nil { - return nil, trace.Wrap(err) - } - - vpcIds := req.VPCIDs - if len(vpcIds) == 0 { - vpcIds = []string{req.VPCID} - } - - resp, err := clt.IntegrationAWSOIDCClient().ListEICE(ctx, &integrationv1.ListEICERequest{ - Integration: integrationName, - Region: req.Region, - VpcIds: vpcIds, - NextToken: req.NextToken, - }) - if err != nil { - return nil, trace.Wrap(err) - } - - endpoints := make([]awsoidc.EC2InstanceConnectEndpoint, 0, len(resp.Ec2Ices)) - for _, e := range resp.Ec2Ices { - endpoints = append(endpoints, awsoidc.EC2InstanceConnectEndpoint{ - Name: e.Name, - State: e.State, - StateMessage: e.StateMessage, - DashboardLink: e.DashboardLink, - SubnetID: e.SubnetId, - VPCID: e.VpcId, - }) - } - - return ui.AWSOIDCListEC2ICEResponse{ - NextToken: resp.NextToken, - DashboardLink: resp.DashboardLink, - EC2ICEs: endpoints, - }, nil -} - -// awsOIDCDeployC2ICE creates an EC2 Instance Connect Endpoint. -func (h *Handler) awsOIDCDeployEC2ICE(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (any, error) { - ctx := r.Context() - - var req ui.AWSOIDCDeployEC2ICERequest - if err := httplib.ReadJSON(r, &req); err != nil { - return nil, trace.Wrap(err) - } - - integrationName := p.ByName("name") - if integrationName == "" { - return nil, trace.BadParameter("an integration name is required") - } - - clt, err := sctx.GetUserClient(ctx, site) - if err != nil { - return nil, trace.Wrap(err) - } - - endpoints := make([]*integrationv1.EC2ICEndpoint, 0, len(req.Endpoints)) - for _, endpoint := range req.Endpoints { - endpoints = append(endpoints, &integrationv1.EC2ICEndpoint{ - SubnetId: endpoint.SubnetID, - SecurityGroupIds: endpoint.SecurityGroupIDs, - }) - } - - // Backwards compatible: get the endpoint from the deprecated fields. - if len(endpoints) == 0 { - endpoints = append(endpoints, &integrationv1.EC2ICEndpoint{ - SubnetId: req.SubnetID, - SecurityGroupIds: req.SecurityGroupIDs, - }) - } - - createResp, err := clt.IntegrationAWSOIDCClient().CreateEICE(ctx, &integrationv1.CreateEICERequest{ - Integration: integrationName, - Region: req.Region, - Endpoints: endpoints, - }) - if err != nil { - return nil, trace.Wrap(err) - } - - respEndpoints := make([]ui.AWSOIDCDeployEC2ICEResponseEndpoint, 0, len(createResp.CreatedEndpoints)) - for _, endpoint := range createResp.CreatedEndpoints { - respEndpoints = append(respEndpoints, ui.AWSOIDCDeployEC2ICEResponseEndpoint{ - Name: endpoint.Name, - SubnetID: endpoint.SubnetId, - }) - } - - return ui.AWSOIDCDeployEC2ICEResponse{ - Name: createResp.Name, - Endpoints: respEndpoints, - }, nil -} - // awsOIDCCreateAWSAppAccess creates an AppServer that uses an AWS OIDC Integration for proxying access. // v2 endpoint introduces "labels" field func (h *Handler) awsOIDCCreateAWSAppAccess(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (any, error) { diff --git a/lib/web/integrations_awsoidc_test.go b/lib/web/integrations_awsoidc_test.go index 8bff3a13ab45f..60221151b0c66 100644 --- a/lib/web/integrations_awsoidc_test.go +++ b/lib/web/integrations_awsoidc_test.go @@ -179,110 +179,6 @@ func TestBuildDeployServiceConfigureIAMScript(t *testing.T) { } } -func TestBuildEICEConfigureIAMScript(t *testing.T) { - t.Parallel() - isBadParamErrFn := func(tt require.TestingT, err error, i ...any) { - require.True(tt, trace.IsBadParameter(err), "expected bad parameter, got %v", err) - } - - ctx := context.Background() - env := newWebPack(t, 1) - - // Unauthenticated client for script downloading. - publicClt := env.proxies[0].newClient(t) - pathVars := []string{ - "webapi", - "scripts", - "integrations", - "configure", - "eice-iam.sh", - } - endpoint := publicClt.Endpoint(pathVars...) - - tests := []struct { - name string - reqRelativeURL string - reqQuery url.Values - errCheck require.ErrorAssertionFunc - expectedTeleportArgs string - }{ - { - name: "valid", - reqQuery: url.Values{ - "awsRegion": []string{"us-east-1"}, - "role": []string{"myRole"}, - "awsAccountID": []string{"123456789012"}, - }, - errCheck: require.NoError, - expectedTeleportArgs: "integration configure eice-iam " + - "--aws-region=us-east-1 " + - "--role=myRole " + - "--aws-account-id=123456789012", - }, - { - name: "valid with symbols in role", - reqQuery: url.Values{ - "awsRegion": []string{"us-east-1"}, - "role": []string{"Test+1=2,3.4@5-6_7"}, - "awsAccountID": []string{"123456789012"}, - }, - errCheck: require.NoError, - expectedTeleportArgs: "integration configure eice-iam " + - "--aws-region=us-east-1 " + - "--role=Test\\+1=2,3.4\\@5-6_7 " + - "--aws-account-id=123456789012", - }, - { - name: "missing aws-region", - reqQuery: url.Values{ - "role": []string{"myRole"}, - "awsAccountID": []string{"123456789012"}, - }, - errCheck: isBadParamErrFn, - }, - { - name: "missing account id", - reqQuery: url.Values{ - "awsRegion": []string{"us-east-1"}, - "role": []string{"myRole"}, - }, - errCheck: isBadParamErrFn, - }, - { - name: "missing role", - reqQuery: url.Values{ - "awsRegion": []string{"us-east-1"}, - "awsAccountID": []string{"123456789012"}, - }, - errCheck: isBadParamErrFn, - }, - { - name: "trying to inject escape sequence into query params", - reqQuery: url.Values{ - "awsRegion": []string{"'; rm -rf /tmp/dir; echo '"}, - "role": []string{"role"}, - "awsAccountID": []string{"123456789012"}, - }, - errCheck: isBadParamErrFn, - }, - } - - for _, tc := range tests { - tc := tc - t.Run(tc.name, func(t *testing.T) { - resp, err := publicClt.Get(ctx, endpoint, tc.reqQuery) - tc.errCheck(t, err) - if err != nil { - return - } - - require.Contains(t, string(resp.Bytes()), - fmt.Sprintf("teleportArgs='%s'\n", tc.expectedTeleportArgs), - ) - }) - } -} - func TestBuildEC2SSMIAMScript(t *testing.T) { t.Parallel() isBadParamErrFn := func(tt require.TestingT, err error, i ...any) { diff --git a/lib/web/ui/integration.go b/lib/web/ui/integration.go index ce8f527a8cbd5..b7b93470f67ae 100644 --- a/lib/web/ui/integration.go +++ b/lib/web/ui/integration.go @@ -439,25 +439,6 @@ type AWSOIDCListEKSClustersResponse struct { NextToken string `json:"nextToken,omitempty"` } -// AWSOIDCListEC2Request is a request to ListEC2s using the AWS OIDC Integration. -type AWSOIDCListEC2Request struct { - // Region is the AWS Region. - Region string `json:"region"` - // NextToken is the token to be used to fetch the next page. - // If empty, the first page is fetched. - NextToken string `json:"nextToken"` -} - -// AWSOIDCListEC2Response contains a list of Servers and a next token if more pages are available. -type AWSOIDCListEC2Response struct { - // Servers contains the page of Servers - Servers []Server `json:"servers"` - - // NextToken is used for pagination. - // If non-empty, it can be used to request the next page. - NextToken string `json:"nextToken,omitempty"` -} - // AWSOIDCListSecurityGroupsRequest is a request to ListSecurityGroups using the AWS OIDC Integration. type AWSOIDCListSecurityGroupsRequest struct { // Region is the AWS Region. @@ -549,78 +530,6 @@ type AWSOIDCRequiredVPCSResponse struct { VPCMapOfSubnets map[string][]string `json:"vpcMapOfSubnets"` } -// AWSOIDCListEC2ICERequest is a request to ListEC2ICEs using the AWS OIDC Integration. -type AWSOIDCListEC2ICERequest struct { - // Region is the AWS Region. - Region string `json:"region"` - // VPCID is the VPC to filter EC2 Instance Connect Endpoints. - // Deprecated: use VPCIDs instead. - VPCID string `json:"vpcId"` - // VPCIDs is a list of VPCs to filter EC2 Instance Connect Endpoints. - VPCIDs []string `json:"vpcIds"` - // NextToken is the token to be used to fetch the next page. - // If empty, the first page is fetched. - NextToken string `json:"nextToken"` -} - -// AWSOIDCListEC2ICEResponse contains a list of AWS Instance Connect Endpoints and a next token if more pages are available. -type AWSOIDCListEC2ICEResponse struct { - // EC2ICEs contains the page of Endpoints - EC2ICEs []awsoidc.EC2InstanceConnectEndpoint `json:"ec2Ices"` - - // DashboardLink is the URL for AWS Web Console that lists all the Endpoints for the queries VPCs. - DashboardLink string `json:"dashboardLink,omitempty"` - - // NextToken is used for pagination. - // If non-empty, it can be used to request the next page. - NextToken string `json:"nextToken,omitempty"` -} - -// AWSOIDCDeployEC2ICERequest is a request to create an AWS EC2 Instance Connect Endpoint. -type AWSOIDCDeployEC2ICERequest struct { - // Region is the AWS Region. - Region string `json:"region"` - // Endpoints is a list of endpoinst to create. - Endpoints []AWSOIDCDeployEC2ICERequestEndpoint `json:"endpoints"` - - // SubnetID is the subnet id for the EC2 Instance Connect Endpoint. - // Deprecated: use Endpoints instead. - SubnetID string `json:"subnetId"` - // SecurityGroupIDs is the list of SecurityGroups to apply to the Endpoint. - // If not specified, the Endpoint will receive the default SG for the Subnet's VPC. - // Deprecated: use Endpoints instead. - SecurityGroupIDs []string `json:"securityGroupIds"` -} - -// AWSOIDCDeployEC2ICERequestEndpoint is a single Endpoint that should be created. -type AWSOIDCDeployEC2ICERequestEndpoint struct { - // SubnetID is the subnet id for the EC2 Instance Connect Endpoint. - SubnetID string `json:"subnetId"` - // SecurityGroupIDs is the list of SecurityGroups to apply to the Endpoint. - // If not specified, the Endpoint will receive the default SG for the Subnet's VPC. - SecurityGroupIDs []string `json:"securityGroupIds"` -} - -// AWSOIDCDeployEC2ICEResponse is the response after creating an AWS EC2 Instance Connect Endpoint. -type AWSOIDCDeployEC2ICEResponse struct { - // Name is the name of the endpoint that was created. - // If multiple endpoints were created, this will contain all of them joined by a `,`. - // Eg, eice-1,eice-2 - // Deprecated: use Endpoints instead. - Name string `json:"name"` - - // Endpoints is a list of created endpoints - Endpoints []AWSOIDCDeployEC2ICEResponseEndpoint `json:"endpoints"` -} - -// AWSOIDCDeployEC2ICEResponseEndpoint describes a single endpoint that was created. -type AWSOIDCDeployEC2ICEResponseEndpoint struct { - // Name is the EC2 Instance Connect Endpoint name. - Name string `json:"name"` - // SubnetID is the subnet where this endpoint was created. - SubnetID string `json:"subnetId"` -} - // AWSOIDCPingResponse contains the result of the Ping request. // This response contains meta information about the current state of the Integration. type AWSOIDCPingResponse struct { diff --git a/tool/teleport/common/integration_configure.go b/tool/teleport/common/integration_configure.go index 26f8d93896853..514f61b2ab84b 100644 --- a/tool/teleport/common/integration_configure.go +++ b/tool/teleport/common/integration_configure.go @@ -64,24 +64,6 @@ func onIntegrationConfDeployService(ctx context.Context, params config.Integrati return trace.Wrap(awsoidc.ConfigureDeployServiceIAM(ctx, iamClient, confReq)) } -func onIntegrationConfEICEIAM(ctx context.Context, params config.IntegrationConfEICEIAM) error { - // Ensure we print output to the user. LogLevel at this point was set to Error. - utils.InitLogger(utils.LoggingForDaemon, slog.LevelInfo) - - clt, err := awsoidc.NewEICEIAMConfigureClient(ctx, params.Region) - if err != nil { - return trace.Wrap(err) - } - - confReq := awsoidc.EICEIAMConfigureRequest{ - Region: params.Region, - IntegrationRole: params.Role, - AccountID: params.AccountID, - AutoConfirm: params.AutoConfirm, - } - return trace.Wrap(awsoidc.ConfigureEICEIAM(ctx, clt, confReq)) -} - func onIntegrationConfEC2SSMIAM(ctx context.Context, params config.IntegrationConfEC2SSMIAM) error { // Ensure we print output to the user. LogLevel at this point was set to Error. utils.InitLogger(utils.LoggingForDaemon, slog.LevelInfo) diff --git a/tool/teleport/common/teleport.go b/tool/teleport/common/teleport.go index 02d45ed828632..6c5b673bf5147 100644 --- a/tool/teleport/common/teleport.go +++ b/tool/teleport/common/teleport.go @@ -479,12 +479,6 @@ func Run(options Options) (app *kingpin.Application, executedCommand string, con integrationConfDeployServiceCmd.Flag("aws-account-id", "The AWS account ID.").StringVar(&ccf.IntegrationConfDeployServiceIAMArguments.AccountID) integrationConfDeployServiceCmd.Flag("confirm", "Apply changes without confirmation prompt.").BoolVar(&ccf.IntegrationConfDeployServiceIAMArguments.AutoConfirm) - integrationConfEICECmd := integrationConfigureCmd.Command("eice-iam", "Adds required IAM permissions to connect to EC2 Instances using EC2 Instance Connect Endpoint.") - integrationConfEICECmd.Flag("aws-region", "AWS Region.").Required().StringVar(&ccf.IntegrationConfEICEIAMArguments.Region) - integrationConfEICECmd.Flag("role", "The AWS Role used by the AWS OIDC Integration.").Required().StringVar(&ccf.IntegrationConfEICEIAMArguments.Role) - integrationConfEICECmd.Flag("aws-account-id", "The AWS account ID.").StringVar(&ccf.IntegrationConfEICEIAMArguments.AccountID) - integrationConfEICECmd.Flag("confirm", "Apply changes without confirmation prompt.").BoolVar(&ccf.IntegrationConfEICEIAMArguments.AutoConfirm) - integrationConfEC2SSMCmd := integrationConfigureCmd.Command("ec2-ssm-iam", "Adds required IAM permissions and SSM Document to enable EC2 Auto Discover using SSM.") integrationConfEC2SSMCmd.Flag("role", "The AWS Role name used by the AWS OIDC Integration.").Required().StringVar(&ccf.IntegrationConfEC2SSMIAMArguments.RoleName) integrationConfEC2SSMCmd.Flag("aws-region", "AWS Region.").Required().StringVar(&ccf.IntegrationConfEC2SSMIAMArguments.Region) @@ -713,8 +707,6 @@ Examples: err = onJoinOpenSSH(ccf, conf) case integrationConfDeployServiceCmd.FullCommand(): err = onIntegrationConfDeployService(ctx, ccf.IntegrationConfDeployServiceIAMArguments) - case integrationConfEICECmd.FullCommand(): - err = onIntegrationConfEICEIAM(ctx, ccf.IntegrationConfEICEIAMArguments) case integrationConfEC2SSMCmd.FullCommand(): err = onIntegrationConfEC2SSMIAM(ctx, ccf.IntegrationConfEC2SSMIAMArguments) case integrationConfAWSAppAccessCmd.FullCommand(): diff --git a/web/packages/teleport/src/Discover/Server/CreateEc2Ice/CreateEc2Ice.story.tsx b/web/packages/teleport/src/Discover/Server/CreateEc2Ice/CreateEc2Ice.story.tsx deleted file mode 100644 index 185575a1fc8e1..0000000000000 --- a/web/packages/teleport/src/Discover/Server/CreateEc2Ice/CreateEc2Ice.story.tsx +++ /dev/null @@ -1,496 +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 { delay, http, HttpResponse } from 'msw'; -import { MemoryRouter } from 'react-router'; - -import { Info } from 'design/Alert'; - -import { ContextProvider } from 'teleport'; -import cfg from 'teleport/config'; -import { - DiscoverContextState, - DiscoverProvider, -} from 'teleport/Discover/useDiscover'; -import { createTeleportContext } from 'teleport/mocks/contexts'; -import { - Ec2InstanceConnectEndpoint, - IntegrationKind, - IntegrationStatusCode, -} from 'teleport/services/integrations'; - -import { CreateEc2Ice } from './CreateEc2Ice'; - -export default { - title: 'Teleport/Discover/Server/EC2/CreateEICE', -}; - -const mockedCreatedEc2Ice: Ec2InstanceConnectEndpoint = { - name: 'test-eice', - state: 'create-complete', - stateMessage: '', - dashboardLink: 'goteleport.com', - subnetId: 'test-subnetid', - vpcId: 'test', -}; - -const deployEndpointSuccess = http.post( - cfg.getDeployEc2InstanceConnectEndpointUrl('test-oidc'), - () => HttpResponse.json({ name: 'test-eice' }) -); - -let tick = 0; -const ec2IceEndpointWithTick = http.post( - cfg.getListEc2InstanceConnectEndpointsUrl('test-oidc'), - () => { - if (tick == 1) { - tick = 0; // reset, the polling will be finished by this point. - return HttpResponse.json({ - ec2Ices: [mockedCreatedEc2Ice], - }); - } - tick += 1; - return HttpResponse.json({ - ec2Ices: [{ ...mockedCreatedEc2Ice, state: 'create-in-progress' }], - }); - } -); - -export const AutoDiscoverEnabled = () => ( - <> - - Devs: after clicking next, wait 10 seconds for in progress to change to - created - - - -); -AutoDiscoverEnabled.parameters = { - msw: { - handlers: [deployEndpointSuccess, ec2IceEndpointWithTick], - }, -}; - -export const ListSecurityGroupsLoading = () => ; - -ListSecurityGroupsLoading.parameters = { - msw: { - handlers: [ - http.post(cfg.getListSecurityGroupsUrl('test-oidc'), () => - delay('infinite') - ), - ], - }, -}; - -export const ListSecurityGroupsFail = () => ; - -ListSecurityGroupsFail.parameters = { - msw: { - handlers: [ - http.post(cfg.getListSecurityGroupsUrl('test-oidc'), () => - HttpResponse.json( - { - message: 'some error when trying to list security groups', - }, - { status: 403 } - ) - ), - ], - }, -}; - -export const DeployEiceFail = () => ( - <> - To trigger this Story's state, click on "Next." - - -); - -DeployEiceFail.parameters = { - msw: { - handlers: [ - http.post(cfg.getListSecurityGroupsUrl('test-oidc'), () => - HttpResponse.json({ securityGroups: securityGroupsResponse }) - ), - http.post(cfg.getDeployEc2InstanceConnectEndpointUrl('test-oidc'), () => - HttpResponse.json( - { - message: 'some error when trying to initiate the deployment', - }, - { status: 403 } - ) - ), - ], - }, -}; - -export const CreatingInProgress = () => ( - <> - To trigger this Story's state, click on "Next." - - -); - -CreatingInProgress.parameters = { - msw: { - handlers: [ - http.post(cfg.getListSecurityGroupsUrl('test-oidc'), () => - HttpResponse.json({ securityGroups: securityGroupsResponse }) - ), - http.post(cfg.getListEc2InstanceConnectEndpointsUrl('test-oidc'), () => - HttpResponse.json({ - ec2Ices: [ - { - name: 'test-eice', - state: 'create-in-progress', - stateMessage: '', - dashboardLink: 'goteleport.com', - subnetId: 'test-subnetid', - }, - ], - nextToken: '', - }) - ), - deployEndpointSuccess, - ], - }, -}; - -export const CreatingFailed = () => ( - <> - {' '} - - To trigger this Story's state, click on "Next" and wait 10 seconds. - - - -); - -CreatingFailed.parameters = { - msw: { - handlers: [ - http.post(cfg.getListSecurityGroupsUrl('test-oidc'), () => - HttpResponse.json({ securityGroups: securityGroupsResponse }) - ), - http.post(cfg.getListEc2InstanceConnectEndpointsUrl('test-oidc'), () => - HttpResponse.json({ - ec2Ices: [ - { - name: 'test-eice', - state: 'create-failed', - stateMessage: '', - dashboardLink: 'goteleport.com', - subnetId: 'test-subnetid', - }, - ], - nextToken: '', - }) - ), - deployEndpointSuccess, - ], - }, -}; - -export const CreatingComplete = () => ( - <> - - To trigger this Story's state, click on "Next" and wait 10 seconds. - - - -); - -CreatingComplete.parameters = { - msw: { - handlers: [ - http.post(cfg.getListSecurityGroupsUrl('test-oidc'), () => - HttpResponse.json({ securityGroups: securityGroupsResponse }) - ), - http.post(cfg.getDeployEc2InstanceConnectEndpointUrl('test-oidc'), () => - HttpResponse.json({ name: 'test-eice' }) - ), - http.post(cfg.getListEc2InstanceConnectEndpointsUrl('test-oidc'), () => - HttpResponse.json({ - ec2Ices: [ - { - name: 'test-eice', - state: 'create-complete', - stateMessage: '', - dashboardLink: 'goteleport.com', - subnetId: 'test-subnetid', - }, - ], - nextToken: '', - }) - ), - http.post(cfg.getClusterNodesUrlNoParams('localhost'), async () => { - await delay(2000); - return HttpResponse.json({ - id: 'ec2-instance-1', - kind: 'node', - clusterId: 'cluster', - hostname: 'ec2-hostname-1', - labels: [{ name: 'instance', value: 'ec2-1' }], - addr: 'ec2.1.com', - tunnel: false, - subKind: 'openssh-ec2-ice', - sshLogins: ['test'], - aws: { - accountId: 'test-account', - instanceId: 'instance-ec2-1', - region: 'us-east-1', - vpcId: 'test', - integration: 'test', - subnetId: 'test', - }, - }); - }), - ], - }, -}; - -const Component = ({ autoDiscover = false }: { autoDiscover?: boolean }) => { - const ctx = createTeleportContext(); - const discoverCtx: DiscoverContextState = { - agentMeta: { - awsRegion: 'us-east-1', - resourceName: 'node-name', - agentMatcherLabels: [], - node: { - kind: 'node', - subKind: 'openssh-ec2-ice', - id: 'test-node', - hostname: 'test-node-hostname', - clusterId: 'localhost', - labels: [], - addr: 'test', - tunnel: false, - sshLogins: [], - awsMetadata: { - accountId: 'test-account', - integration: 'test-oidc', - instanceId: 'i-test', - subnetId: 'test', - vpcId: 'test-vpc', - region: 'us-east-1', - }, - }, - awsIntegration: { - kind: IntegrationKind.AwsOidc, - name: 'test-oidc', - resourceType: 'integration', - spec: { - roleArn: 'arn-123', - issuerS3Bucket: '', - issuerS3Prefix: '', - }, - statusCode: IntegrationStatusCode.Running, - }, - autoDiscovery: autoDiscover - ? { - config: { name: '', discoveryGroup: '', aws: [] }, - requiredVpcsAndSubnets: { - 'vpc-1': ['subnet-1'], - 'vpc-2': ['subnet-2'], - }, - } - : undefined, - }, - updateAgentMeta: agentMeta => { - discoverCtx.agentMeta = agentMeta; - }, - currentStep: 0, - nextStep: () => null, - prevStep: () => null, - onSelectResource: () => null, - resourceSpec: {} as any, - exitFlow: () => null, - viewConfig: null, - indexedViews: [], - setResourceSpec: () => null, - emitErrorEvent: () => null, - emitEvent: () => null, - eventState: null, - }; - - cfg.proxyCluster = 'localhost'; - return ( - - - - - - - - ); -}; - -const securityGroupsResponse = [ - { - name: 'security-group-1', - id: 'sg-1', - description: 'this is security group 1', - inboundRules: [ - { - ipProtocol: 'tcp', - fromPort: '0', - toPort: '0', - cidrs: [{ cidr: '0.0.0.0/0', description: 'Everything' }], - }, - { - ipProtocol: 'tcp', - fromPort: '443', - toPort: '443', - cidrs: [{ cidr: '0.0.0.0/0', description: 'Everything' }], - }, - { - ipProtocol: 'tcp', - fromPort: '2000', - toPort: '5000', - cidrs: [ - { cidr: '192.168.1.0/24', description: 'Subnet Mask 255.255.255.0' }, - ], - }, - ], - outboundRules: [ - { - ipProtocol: 'tcp', - fromPort: '0', - toPort: '0', - cidrs: [{ cidr: '0.0.0.0/0', description: 'Everything' }], - }, - { - ipProtocol: 'tcp', - fromPort: '22', - toPort: '22', - cidrs: [{ cidr: '0.0.0.0/0', description: 'Everything' }], - }, - { - ipProtocol: 'tcp', - fromPort: '2000', - toPort: '5000', - cidrs: [ - { cidr: '10.0.0.0/16', description: 'Subnet Mask 255.255.0.0"' }, - ], - }, - ], - }, - { - name: 'security-group-2', - id: 'sg-2', - description: 'this is security group 2', - inboundRules: [ - { - ipProtocol: 'tcp', - fromPort: '0', - toPort: '0', - cidrs: [{ cidr: '0.0.0.0/0', description: 'Everything' }], - }, - { - ipProtocol: 'tcp', - fromPort: '443', - toPort: '443', - cidrs: [{ cidr: '0.0.0.0/0', description: 'Everything' }], - }, - { - ipProtocol: 'tcp', - fromPort: '2000', - toPort: '5000', - cidrs: [ - { cidr: '192.168.1.0/24', description: 'Subnet Mask 255.255.255.0' }, - ], - }, - ], - outboundRules: [ - { - ipProtocol: 'tcp', - fromPort: '0', - toPort: '0', - cidrs: [{ cidr: '0.0.0.0/0', description: 'Everything' }], - }, - { - ipProtocol: 'tcp', - fromPort: '22', - toPort: '22', - cidrs: [{ cidr: '0.0.0.0/0', description: 'Everything' }], - }, - { - ipProtocol: 'tcp', - fromPort: '2000', - toPort: '5000', - cidrs: [ - { cidr: '10.0.0.0/16', description: 'Subnet Mask 255.255.0.0"' }, - ], - }, - ], - }, - { - name: 'security-group-3', - id: 'sg-3', - description: 'this is security group 3', - inboundRules: [ - { - ipProtocol: 'tcp', - fromPort: '0', - toPort: '0', - cidrs: [{ cidr: '0.0.0.0/0', description: 'Everything' }], - }, - { - ipProtocol: 'tcp', - fromPort: '443', - toPort: '443', - cidrs: [{ cidr: '0.0.0.0/0', description: 'Everything' }], - }, - { - ipProtocol: 'tcp', - fromPort: '2000', - toPort: '5000', - cidrs: [ - { cidr: '192.168.1.0/24', description: 'Subnet Mask 255.255.255.0' }, - ], - }, - ], - outboundRules: [ - { - ipProtocol: 'tcp', - fromPort: '0', - toPort: '0', - cidrs: [{ cidr: '0.0.0.0/0', description: 'Everything' }], - }, - { - ipProtocol: 'tcp', - fromPort: '22', - toPort: '22', - cidrs: [{ cidr: '0.0.0.0/0', description: 'Everything' }], - }, - { - ipProtocol: 'tcp', - fromPort: '2000', - toPort: '5000', - cidrs: [ - { cidr: '10.0.0.0/16', description: 'Subnet Mask 255.255.0.0"' }, - ], - }, - ], - }, -]; diff --git a/web/packages/teleport/src/Discover/Server/CreateEc2Ice/CreateEc2Ice.tsx b/web/packages/teleport/src/Discover/Server/CreateEc2Ice/CreateEc2Ice.tsx deleted file mode 100644 index b3f23146fcb84..0000000000000 --- a/web/packages/teleport/src/Discover/Server/CreateEc2Ice/CreateEc2Ice.tsx +++ /dev/null @@ -1,320 +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 React, { useEffect, useState } from 'react'; - -import { Box, Flex, H3, Indicator, Text } from 'design'; -import { Danger } from 'design/Alert'; -import Table from 'design/DataTable'; -import { FetchStatus } from 'design/DataTable/types'; -import { Warning } from 'design/Icon'; -import useAttempt, { Attempt } from 'shared/hooks/useAttemptNext'; -import { getErrMessage } from 'shared/utils/errorType'; - -import { - ActionButtons, - ButtonBlueText, - Header, - SecurityGroupPicker, -} from 'teleport/Discover/Shared'; -import { NodeMeta, useDiscover } from 'teleport/Discover/useDiscover'; -import { - AwsOidcDeployEc2InstanceConnectEndpointRequest, - integrationService, - SecurityGroup, -} from 'teleport/services/integrations'; -import { - DiscoverEvent, - DiscoverEventStatus, -} from 'teleport/services/userEvent'; - -import { CreateEc2IceDialog } from './CreateEc2IceDialog'; - -type TableData = { - items: SecurityGroup[]; - nextToken?: string; - fetchStatus: FetchStatus; -}; - -export function CreateEc2Ice() { - const [showCreatingDialog, setShowCreatingDialog] = useState(false); - const [selectedSecurityGroups, setSelectedSecurityGroups] = useState< - string[] - >([]); - const [tableData, setTableData] = useState({ - items: [], - nextToken: '', - fetchStatus: 'disabled', - }); - - const { - attempt: fetchSecurityGroupsAttempt, - setAttempt: setFetchSecurityGroupsAttempt, - } = useAttempt(''); - - const { attempt: deployEc2IceAttempt, setAttempt: setDeployEc2IceAttempt } = - useAttempt(''); - - const { emitErrorEvent, agentMeta, prevStep, nextStep, emitEvent } = - useDiscover(); - - const autoDiscoverEnabled = !!agentMeta.autoDiscovery; - - useEffect(() => { - // It has been decided for now that with auto discover, - // default security groups will be used (in the request - // this is depicted as an empty value) - if (!autoDiscoverEnabled) { - fetchSecurityGroups(); - } - }, []); - - function onSelectSecurityGroup( - sg: SecurityGroup, - e: React.ChangeEvent - ) { - if (e.target.checked) { - return setSelectedSecurityGroups([...selectedSecurityGroups, sg.id]); - } else { - setSelectedSecurityGroups( - selectedSecurityGroups.filter(id => id !== sg.id) - ); - } - } - - async function fetchSecurityGroups() { - const integration = agentMeta.awsIntegration; - - setFetchSecurityGroupsAttempt({ status: 'processing' }); - try { - const { securityGroups, nextToken } = - await integrationService.fetchSecurityGroups(integration.name, { - vpcId: (agentMeta as NodeMeta).node.awsMetadata.vpcId, - region: (agentMeta as NodeMeta).node.awsMetadata.region, - nextToken: tableData.nextToken, - }); - - setFetchSecurityGroupsAttempt({ status: 'success' }); - setTableData({ - nextToken: nextToken, - fetchStatus: nextToken ? '' : 'disabled', - items: [...tableData.items, ...securityGroups], - }); - } catch (err) { - const errMsg = getErrMessage(err); - setFetchSecurityGroupsAttempt({ status: 'failed', statusText: errMsg }); - emitErrorEvent(`fetch security groups error: ${errMsg}`); - } - } - - async function deployEc2InstanceConnectEndpoint() { - const integration = agentMeta.awsIntegration; - - let endpoints: AwsOidcDeployEc2InstanceConnectEndpointRequest[] = []; - if (autoDiscoverEnabled) { - endpoints = Object.values( - agentMeta.autoDiscovery.requiredVpcsAndSubnets - ).map(subnets => ({ - // Being in this step of the flow means - // the requiredVpcsAndSubnets will always - // be defined. - subnetId: subnets[0], - })); - } else { - endpoints = [ - { - subnetId: (agentMeta as NodeMeta).node.awsMetadata.subnetId, - ...(selectedSecurityGroups.length && { - securityGroupIds: selectedSecurityGroups, - }), - }, - ]; - } - - setDeployEc2IceAttempt({ status: 'processing' }); - setShowCreatingDialog(true); - try { - await integrationService.deployAwsEc2InstanceConnectEndpoints( - integration.name, - { - region: agentMeta.awsRegion, - endpoints, - } - ); - // Capture event for deploying EICE. - emitEvent( - { stepStatus: DiscoverEventStatus.Success }, - { - eventName: DiscoverEvent.EC2DeployEICE, - } - ); - setDeployEc2IceAttempt({ status: 'success' }); - } catch (err) { - const errMsg = getErrMessage(err); - setShowCreatingDialog(false); - setDeployEc2IceAttempt({ status: 'failed', statusText: errMsg }); - // Capture error event for failing to deploy EICE. - emitEvent( - { stepStatus: DiscoverEventStatus.Error, stepStatusError: errMsg }, - { - eventName: DiscoverEvent.EC2DeployEICE, - } - ); - } - } - - function handleOnProceed() { - deployEc2InstanceConnectEndpoint(); - } - - return ( - <> - -
- {autoDiscoverEnabled - ? 'Create EC2 Instance Connect Endpoints' - : 'Create an EC2 Instance Connect Endpoint'} -
- - {deployEc2IceAttempt.status === 'failed' && ( - {deployEc2IceAttempt.statusText} - )} - {autoDiscoverEnabled ? ( - - ) : ( - - )} - - handleOnProceed()} - disableProceed={deployEc2IceAttempt.status === 'processing'} - /> -
- {showCreatingDialog && ( - deployEc2InstanceConnectEndpoint()} - /> - )} - - ); -} - -function CreateEndpointsForAutoDiscover({ - requiredVpcIdsAndSubnets, -}: { - requiredVpcIdsAndSubnets: Record; -}) { - const items = Object.keys(requiredVpcIdsAndSubnets).map(key => ({ - vpcId: key, - subnetId: requiredVpcIdsAndSubnets[key][0], - })); - - return ( - - - EC2 Instance Connect Endpoints will be created for the following VPC - ID's: - - - - ); -} - -function SecurityGroups({ - fetchSecurityGroupsAttempt, - fetchSecurityGroups, - tableData, - onSelectSecurityGroup, - selectedSecurityGroups, -}: { - fetchSecurityGroupsAttempt: Attempt; - fetchSecurityGroups(): Promise; - tableData: TableData; - onSelectSecurityGroup( - sg: SecurityGroup, - e: React.ChangeEvent - ): void; - selectedSecurityGroups: string[]; -}) { - return ( - <> -

- Select AWS Security Groups to assign to the new EC2 Instance Connect - Endpoint: -

- - The security groups you pick should allow outbound connectivity for the - agent to be able to dial Teleport clusters. If you don't select any - security groups, the default one for the VPC will be used. - - {fetchSecurityGroupsAttempt.status === 'failed' && ( - <> - - - {fetchSecurityGroupsAttempt.statusText} - - - Retry - - - )} - {fetchSecurityGroupsAttempt.status === 'processing' && ( - - - - )} - {fetchSecurityGroupsAttempt.status === 'success' && ( - - fetchSecurityGroups()} - fetchStatus={tableData.fetchStatus} - onSelectSecurityGroup={onSelectSecurityGroup} - selectedSecurityGroups={selectedSecurityGroups} - /> - - )} - - ); -} diff --git a/web/packages/teleport/src/Discover/Server/CreateEc2Ice/CreateEc2IceDialog.tsx b/web/packages/teleport/src/Discover/Server/CreateEc2Ice/CreateEc2IceDialog.tsx deleted file mode 100644 index 5751259bc2c19..0000000000000 --- a/web/packages/teleport/src/Discover/Server/CreateEc2Ice/CreateEc2IceDialog.tsx +++ /dev/null @@ -1,378 +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 { useEffect, useState } from 'react'; - -import { - AnimatedProgressBar, - Box, - ButtonPrimary, - Flex, - Link, - Mark, - Text, -} from 'design'; -import Dialog, { DialogContent } from 'design/DialogConfirmation'; -import * as Icons from 'design/Icon'; -import useAttempt, { Attempt } from 'shared/hooks/useAttemptNext'; -import { getErrMessage } from 'shared/utils/errorType'; - -import cfg from 'teleport/config'; -import { TextIcon } from 'teleport/Discover/Shared'; -import { usePoll } from 'teleport/Discover/Shared/usePoll'; -import { NodeMeta, useDiscover } from 'teleport/Discover/useDiscover'; -import { - Ec2InstanceConnectEndpoint, - integrationService, -} from 'teleport/services/integrations'; -import { - DiscoverEvent, - DiscoverEventStatus, -} from 'teleport/services/userEvent'; -import useTeleport from 'teleport/useTeleport'; - -export function CreateEc2IceDialog({ - nextStep, - retry, - existingEices = null, -}: { - nextStep: () => void; - retry?: () => void; - // Only supplied if there exists all the required ec2 - // instance connect endpoints, resulting in the user - // being able to skip the `eice deployment` step. - // Though the endpoints might all exist they may not all be - // in the `create-complete` state, which means polling - // for this endpoint is required until it becomes - // `create-complete`. - // If this field is NOT supplied, then new endpoints - // have been deployed which also needs to be polled - // until `create-complete`. - existingEices?: Ec2InstanceConnectEndpoint[]; -}) { - const { nodeService } = useTeleport(); - - // If the EICE already exists from the previous step and is - // create-complete, we don't need to do any polling for the EICE. - const [isPollingActive, setIsPollingActive] = useState(() => - existingEices - ? existingEices.some(e => e.state !== 'create-complete') - : true - ); - const [mainDashboardLink, setMainDashboardLink] = useState(''); - - const { emitErrorEvent, updateAgentMeta, agentMeta, emitEvent } = - useDiscover(); - const typedAgentMeta = agentMeta as NodeMeta; - const autoDiscoverEnabled = !!typedAgentMeta.autoDiscovery; - - const { attempt: fetchEc2IceAttempt, setAttempt: setFetchEc2IceAttempt } = - useAttempt(''); - const { attempt: createNodeAttempt, setAttempt: setCreateNodeAttempt } = - useAttempt(''); - - // When the EICE's state is 'create-complete', create the node. - useEffect(() => { - // Auto discovery will automatically create the discovered - // nodes in the backend. - if (autoDiscoverEnabled) return; - - if (typedAgentMeta.ec2Ices?.every(e => e.state === 'create-complete')) { - createNode(); - } - }, [typedAgentMeta.ec2Ices]); - - let ec2Ices = usePoll( - () => - fetchEc2InstanceConnectEndpoints().then(endpoints => { - if (endpoints?.every(e => e.state === 'create-complete')) { - setIsPollingActive(false); - updateAgentMeta({ - ...typedAgentMeta, - ec2Ices: endpoints, - }); - } - return endpoints; - }), - isPollingActive, - 10000 // poll every 10 seconds - ); - - // If the EICE already existed from the previous step and was create-complete, we set - // `ec2Ice` to it. - if (existingEices?.every(e => e.state === 'create-complete')) { - ec2Ices = existingEices; - } - - async function fetchEc2InstanceConnectEndpoints() { - let vpcIds: string[] = []; - if (autoDiscoverEnabled) { - const requiredVpcs = Object.keys( - typedAgentMeta.autoDiscovery.requiredVpcsAndSubnets - ); - const inprogressExistingEndpoints = - typedAgentMeta.ec2Ices - ?.filter(e => e.state === 'create-in-progress') - .map(e => e.vpcId) ?? []; - vpcIds = [...requiredVpcs, ...inprogressExistingEndpoints]; - } else { - vpcIds = [typedAgentMeta.node.awsMetadata.vpcId]; - } - - setFetchEc2IceAttempt({ status: 'processing' }); - try { - const resp = await integrationService.fetchAwsEc2InstanceConnectEndpoints( - typedAgentMeta.awsIntegration.name, - { - region: typedAgentMeta.awsRegion, - vpcIds, - } - ); - - setMainDashboardLink(resp.dashboardLink); - setFetchEc2IceAttempt({ status: 'success' }); - - const endpoints = resp.endpoints.filter( - e => - e.state === 'create-complete' || - e.state === 'create-in-progress' || - e.state === 'create-failed' - ); - - if (endpoints.length > 0) { - return endpoints; - } - } catch { - // eslint-disable-next-line no-empty - // Ignore any errors, as the poller will keep re-trying. - } - } - - async function createNode() { - setCreateNodeAttempt({ status: 'processing' }); - try { - const node = await nodeService.createNode(cfg.proxyCluster, { - hostname: typedAgentMeta.node.hostname, - addr: typedAgentMeta.node.addr, - labels: typedAgentMeta.node.labels, - aws: typedAgentMeta.node.awsMetadata, - name: typedAgentMeta.node.id, - subKind: 'openssh-ec2-ice', - }); - - updateAgentMeta({ - ...typedAgentMeta, - node, - resourceName: node.id, - }); - setCreateNodeAttempt({ status: 'success' }); - - // Capture event for creating the Node. - emitEvent( - { stepStatus: DiscoverEventStatus.Success }, - { - eventName: DiscoverEvent.CreateNode, - } - ); - } catch (err) { - const errMsg = getErrMessage(err); - setCreateNodeAttempt({ status: 'failed', statusText: errMsg }); - setIsPollingActive(false); - emitErrorEvent(`error creating teleport node: ${errMsg}`); - } - } - - const endpointsCreated = ec2Ices?.every(e => e.state === 'create-complete'); - - let content: JSX.Element; - if ( - fetchEc2IceAttempt.status === 'failed' || - createNodeAttempt.status === 'failed' - ) { - content = ( - <> - - {' '} - - - {fetchEc2IceAttempt.status === 'failed' - ? fetchEc2IceAttempt.statusText - : createNodeAttempt.statusText} - - - - {!!retry && ( - - Retry - - )} - - - ); - } else { - if (ec2Ices?.some(e => e.state === 'create-failed')) { - content = ( - <> - - - - - We couldn't create some EC2 Instance Connect Endpoints. -
- Please visit your{' '} - - dashboard{' '} - - to troubleshoot. -
- We'll keep looking for the endpoint until it becomes available. -
-
- - Next - - - ); - } else if (createNodeAttempt.status === 'success' && endpointsCreated) { - content = ( - <> - - - - The EC2 instance [{typedAgentMeta?.node.awsMetadata.instanceId}] has - been added to Teleport. - - nextStep()}> - Next - - - ); - } else if (autoDiscoverEnabled && endpointsCreated) { - content = ( - <> - - - - - All endpoints required are created. The discovery service can take - a few minutes to finish auto-enrolling resources found in region{' '} - {typedAgentMeta.awsRegion}. - - - nextStep()}> - Next - - - ); - } else { - content = ( - <> - - - - - This may take a few minutes.. - - {!endpointsCreated && mainDashboardLink && ( - - Meanwhile, visit your{' '} - - dashboard - {' '} - to view the status of{' '} - {autoDiscoverEnabled ? 'each endpoint' : 'this endpoint'} - - )} - - - Next - - - ); - } - } - - let title = 'Creating EC2 Instance Connect Endpoints'; - - if (!autoDiscoverEnabled && endpointsCreated) { - if (createNodeAttempt.status === 'success') { - title = 'Created Teleport Node'; - } else { - title = 'Creating Teleport Node'; - } - } - - return ( - - - - {title} - - {content} - - - ); -} - -export type CreateEc2IceDialogProps = { - ec2Ice: Ec2InstanceConnectEndpoint; - fetchEc2IceAttempt: Attempt; - createNodeAttempt: Attempt; - retry: () => void; - next: () => void; -}; - -function EndpointSuccessfullyDeployed({ - existingEices, -}: { - existingEices: Ec2InstanceConnectEndpoint[]; -}) { - // Don't show this message if the EICE had already been deployed before this step. - if (!existingEices?.every(e => e.state === 'create-complete')) { - return ( - - - The EC2 Instance Connect Endpoints are successfully deployed. - - ); - } -} diff --git a/web/packages/teleport/src/Discover/Server/EnrollEc2Instance/Ec2InstanceList.tsx b/web/packages/teleport/src/Discover/Server/EnrollEc2Instance/Ec2InstanceList.tsx deleted file mode 100644 index fa824991e2ac0..0000000000000 --- a/web/packages/teleport/src/Discover/Server/EnrollEc2Instance/Ec2InstanceList.tsx +++ /dev/null @@ -1,154 +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 { Text } from 'design'; -import Table from 'design/DataTable'; -import { FetchStatus } from 'design/DataTable/types'; -import { Attempt } from 'shared/hooks/useAttemptNext'; - -import { - DisableableCell as Cell, - labelMatcher, - Labels, - RadioCell, -} from 'teleport/Discover/Shared'; - -import { CheckedEc2Instance } from './EnrollEc2Instance'; - -type Props = { - attempt: Attempt; - items: CheckedEc2Instance[]; - fetchStatus: FetchStatus; - fetchNextPage(): void; - onSelectInstance(item: CheckedEc2Instance): void; - selectedInstance?: CheckedEc2Instance; - wantAutoDiscover: boolean; -}; - -export const Ec2InstanceList = ({ - attempt, - items = [], - fetchStatus = '', - fetchNextPage, - onSelectInstance, - selectedInstance, - wantAutoDiscover, -}: Props) => { - const hasError = attempt.status === 'failed'; - - return ( - <> - {!hasError && ( -
{ - const isChecked = - item.awsMetadata.instanceId === - selectedInstance?.awsMetadata.instanceId; - return ( - - item={item} - key={item.awsMetadata.instanceId} - isChecked={isChecked} - onChange={onSelectInstance} - value={item.awsMetadata.instanceId} - {...disabledStates( - item.ec2InstanceExists, - wantAutoDiscover - )} - /> - ); - }, - }, - { - altKey: 'name', - headerText: 'Name', - render: ({ labels, ec2InstanceExists }) => ( - - {labels.find(label => label.name === 'Name')?.value} - - ), - }, - { - key: 'hostname', - headerText: 'Hostname', - render: ({ hostname, ec2InstanceExists }) => ( - - {hostname} - - ), - }, - { - key: 'addr', - headerText: 'Address', - render: ({ addr, ec2InstanceExists }) => ( - - {addr} - - ), - }, - { - altKey: 'instanceId', - headerText: 'AWS Instance ID', - render: ({ awsMetadata, ec2InstanceExists }) => ( - - - {awsMetadata.instanceId} - - - ), - }, - { - key: 'labels', - headerText: 'Labels', - render: ({ labels, ec2InstanceExists }) => ( - - - - ), - }, - ]} - emptyText="No Results" - pagination={{ pageSize: 10 }} - customSearchMatchers={[labelMatcher]} - fetching={{ onFetchMore: fetchNextPage, fetchStatus }} - isSearchable - /> - )} - - ); -}; - -function disabledStates(ec2InstanceExists: boolean, wantAutoDiscover: boolean) { - const disabled = wantAutoDiscover || ec2InstanceExists; - - let disabledText = `This EC2 instance is already enrolled and is a part of this cluster`; - if (wantAutoDiscover) { - disabledText = 'All eligible EC2 instances will be enrolled automatically'; - } - - return { disabled, disabledText }; -} diff --git a/web/packages/teleport/src/Discover/Server/EnrollEc2Instance/EnrollEc2Instance.story.tsx b/web/packages/teleport/src/Discover/Server/EnrollEc2Instance/EnrollEc2Instance.story.tsx deleted file mode 100644 index 5ec6df825e5d7..0000000000000 --- a/web/packages/teleport/src/Discover/Server/EnrollEc2Instance/EnrollEc2Instance.story.tsx +++ /dev/null @@ -1,417 +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 { delay, http, HttpResponse } from 'msw'; -import { useEffect } from 'react'; -import { MemoryRouter } from 'react-router'; - -import { Info } from 'design/Alert'; - -import { ContextProvider } from 'teleport'; -import cfg from 'teleport/config'; -import { - DiscoverContextState, - DiscoverProvider, -} from 'teleport/Discover/useDiscover'; -import { createTeleportContext } from 'teleport/mocks/contexts'; -import { - Ec2InstanceConnectEndpoint, - IntegrationKind, - IntegrationStatusCode, -} from 'teleport/services/integrations'; - -import { EnrollEc2Instance } from './EnrollEc2Instance'; - -const defaultIsCloud = cfg.isCloud; -export default { - title: 'Teleport/Discover/Server/EC2/InstanceList', - decorators: [ - Story => { - useEffect(() => { - // Clean up - return () => { - cfg.isCloud = defaultIsCloud; - }; - }, []); - return ; - }, - ], -}; - -const baseHandlers = [ - http.post(cfg.getListEc2InstancesUrl('test-oidc'), () => - HttpResponse.json({ servers: ec2InstancesResponse }) - ), - http.get(cfg.getClusterNodesUrl('localhost'), () => - HttpResponse.json({ items: [ec2InstancesResponse[2]] }) - ), - http.post(cfg.api.discoveryConfigPath, () => HttpResponse.json({})), -]; - -let tick = 0; -const ec2IceEndpointWithTick = http.post( - cfg.getListEc2InstanceConnectEndpointsUrl('test-oidc'), - () => { - if (tick == 1) { - tick = 0; // reset, the polling will be finished by this point. - return HttpResponse.json({ - ec2Ices: [mockedCreatedEc2Ice], - }); - } - tick += 1; - return HttpResponse.json({ - ec2Ices: [{ ...mockedCreatedEc2Ice, state: 'create-in-progress' }], - }); - } -); - -const mockedCreatedEc2Ice: Ec2InstanceConnectEndpoint = { - name: 'test-eice', - state: 'create-complete', - stateMessage: '', - dashboardLink: 'goteleport.com', - subnetId: 'test-subnetid', - vpcId: 'test', -}; - -const mockedNode = { - id: '', - siteId: '', - subKind: 'teleport', - hostname: 'hostname', - addr: '', - tunnel: false, - tags: [], - sshLogins: [], - aws: {}, -}; - -export const SingleInstanceListCreated = () => ; -SingleInstanceListCreated.parameters = { - msw: { - handlers: [ - ...baseHandlers, - http.post(cfg.getListEc2InstanceConnectEndpointsUrl('test-oidc'), () => - HttpResponse.json({ - ec2Ices: [mockedCreatedEc2Ice], - }) - ), - http.post(cfg.api.nodesPathNoParams, () => HttpResponse.json(mockedNode)), - ], - }, -}; - -export const SingleInstanceListForCloudPending = () => { - cfg.isCloud = true; - return ( - <> - - Devs: Select region, after clicking next, wait 10 seconds for pending - state to go into created state - - - - ); -}; -SingleInstanceListForCloudPending.parameters = { - msw: { - handlers: [ - ...baseHandlers, - ec2IceEndpointWithTick, - http.post(cfg.api.nodesPathNoParams, () => HttpResponse.json(mockedNode)), - ], - }, -}; - -export const AutoDiscoverInstanceListForCloudCreated = () => { - cfg.isCloud = true; - return ; -}; -AutoDiscoverInstanceListForCloudCreated.parameters = { - msw: { - handlers: [ - ...baseHandlers, - http.post(cfg.getListEc2InstanceConnectEndpointsUrl('test-oidc'), () => - HttpResponse.json({ - ec2Ices: [mockedCreatedEc2Ice], - }) - ), - ], - }, -}; - -export const AutoDiscoverInstanceListForCloudPending = () => { - cfg.isCloud = true; - return ( - <> - - Devs: Select region, after clicking next, wait 10 seconds for pending - state to go into created state - - - - ); -}; -AutoDiscoverInstanceListForCloudPending.parameters = { - msw: { - handlers: [...baseHandlers, ec2IceEndpointWithTick], - }, -}; - -export const InstanceListLoading = () => ; -InstanceListLoading.parameters = { - msw: { - handlers: [ - http.post(cfg.getListEc2InstancesUrl('test-oidc'), () => - delay('infinite') - ), - ], - }, -}; - -export const WithAwsPermissionsError = () => ; - -WithAwsPermissionsError.parameters = { - msw: { - handlers: [ - http.post(cfg.api.ec2InstancesListPath, () => - HttpResponse.json( - { - message: 'StatusCode: 403, RequestID: operation error', - }, - { status: 403 } - ) - ), - ], - }, -}; - -export const WithOtherError = () => ; - -WithOtherError.parameters = { - msw: { - handlers: [ - http.post(cfg.getListEc2InstancesUrl('test-oidc'), () => - HttpResponse.json( - { - message: 'Some kind of error message', - }, - { status: 404 } - ) - ), - ], - }, -}; - -const Component = ({ - autoDiscover = false, - ec2Ices = [], -}: { - autoDiscover?: boolean; - ec2Ices?: Ec2InstanceConnectEndpoint[]; -}) => { - const ctx = createTeleportContext(); - const discoverCtx: DiscoverContextState = { - agentMeta: { - awsRegion: 'us-east-1', - resourceName: 'node-name', - agentMatcherLabels: [], - node: { - kind: 'node', - id: 'some-id', - clusterId: 'cluster-id', - hostname: 'some-hostname', - labels: [], - addr: '', - tunnel: false, - subKind: 'teleport', - sshLogins: [], - awsMetadata: { - accountId: 'aws-account-id', - instanceId: 'instance-id', - region: 'us-east-1', - vpcId: 'instance-vpc-id', - integration: 'integration-name', - subnetId: 'subnet-id', - }, - }, - ec2Ices: ec2Ices, - awsIntegration: { - kind: IntegrationKind.AwsOidc, - name: 'test-oidc', - resourceType: 'integration', - spec: { - roleArn: 'arn-123', - issuerS3Bucket: '', - issuerS3Prefix: '', - }, - statusCode: IntegrationStatusCode.Running, - }, - autoDiscovery: autoDiscover - ? { - config: { name: '', discoveryGroup: '', aws: [] }, - requiredVpcsAndSubnets: {}, - } - : undefined, - }, - currentStep: 0, - nextStep: () => null, - prevStep: () => null, - onSelectResource: () => null, - resourceSpec: {} as any, - exitFlow: () => null, - viewConfig: null, - indexedViews: [], - setResourceSpec: () => null, - updateAgentMeta: () => null, - emitErrorEvent: () => null, - emitEvent: () => null, - eventState: null, - }; - - cfg.proxyCluster = 'localhost'; - return ( - - - - - - - - ); -}; - -const ec2InstancesResponse = [ - { - id: 'ec2-instance-1', - kind: 'node', - clusterId: 'cluster', - hostname: 'ec2-hostname-1', - tags: [ - { name: 'teleport.dev/instance-id', value: 'instance-ec2-1' }, - { name: 'Name', value: 'My EC2 Box 1' }, - ], - addr: 'ec2.1.com', - tunnel: false, - subKind: 'openssh-ec2-ice', - sshLogins: ['test'], - aws: { - accountId: 'test-account', - instanceId: 'instance-ec2-1', - region: 'us-west-1', - vpcId: 'test', - integration: 'test', - subnetId: 'test', - }, - }, - { - id: 'ec2-instance-2', - kind: 'node', - clusterId: 'cluster', - hostname: 'ec2-hostname-2', - tags: [ - { name: 'teleport.dev/instance-id', value: 'instance-ec2-2' }, - { name: 'Name', value: 'My EC2 Box 2' }, - ], - addr: 'ec2.2.com', - tunnel: false, - subKind: 'openssh-ec2-ice', - sshLogins: ['test'], - aws: { - accountId: 'test-account', - instanceId: 'instance-ec2-2', - region: 'us-west-1', - vpcId: 'test', - integration: 'test', - subnetId: 'test', - }, - }, - { - id: 'ec2-instance-3', - kind: 'node', - clusterId: 'cluster', - hostname: 'ec2-hostname-3', - tags: [ - { name: 'teleport.dev/instance-id', value: 'instance-ec2-3' }, - { name: 'Name', value: 'My EC2 Box 3' }, - ], - addr: 'ec2.3.com', - tunnel: false, - subKind: 'openssh-ec2-ice', - sshLogins: ['test'], - aws: { - accountId: 'test-account', - instanceId: 'instance-ec2-3', - region: 'us-west-1', - vpcId: 'test', - integration: 'test', - subnetId: 'test', - }, - }, - { - id: 'ec2-instance-4', - kind: 'node', - clusterId: 'cluster', - hostname: 'ec2-hostname-4', - tags: [ - { name: 'teleport.dev/instance-id', value: 'instance-ec2-4' }, - { name: 'Name', value: 'My EC2 Box 4' }, - ], - addr: 'ec2.4.com', - tunnel: false, - subKind: 'openssh-ec2-ice', - sshLogins: ['test'], - aws: { - accountId: 'test-account', - instanceId: 'instance-ec2-4', - region: 'us-west-1', - vpcId: 'test', - integration: 'test', - subnetId: 'test', - }, - }, - { - id: 'ec2-instance-5', - kind: 'node', - clusterId: 'cluster', - hostname: 'ec2-hostname-5', - tags: [ - { name: 'teleport.dev/instance-id', value: 'instance-ec2-5' }, - { name: 'Name', value: 'My EC2 Box 5' }, - ], - addr: 'ec2.5.com', - tunnel: false, - subKind: 'openssh-ec2-ice', - sshLogins: ['test'], - aws: { - accountId: 'test-account', - instanceId: 'instance-ec2-5', - region: 'us-west-1', - vpcId: 'test', - integration: 'test', - subnetId: 'test', - }, - }, -]; diff --git a/web/packages/teleport/src/Discover/Server/EnrollEc2Instance/EnrollEc2Instance.test.tsx b/web/packages/teleport/src/Discover/Server/EnrollEc2Instance/EnrollEc2Instance.test.tsx deleted file mode 100644 index 0c9ab2a958cf3..0000000000000 --- a/web/packages/teleport/src/Discover/Server/EnrollEc2Instance/EnrollEc2Instance.test.tsx +++ /dev/null @@ -1,726 +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 { MemoryRouter } from 'react-router'; - -import { - act, - fireEvent, - render, - screen, - userEvent, -} from 'design/utils/testing'; - -import { ContextProvider } from 'teleport'; -import cfg from 'teleport/config'; -import { - DiscoverContextState, - DiscoverProvider, - NodeMeta, -} from 'teleport/Discover/useDiscover'; -import { FeaturesContextProvider } from 'teleport/FeaturesContext'; -import { createTeleportContext } from 'teleport/mocks/contexts'; -import * as discoveryApi from 'teleport/services/discovery/discovery'; -import { DEFAULT_DISCOVERY_GROUP_NON_CLOUD } from 'teleport/services/discovery/discovery'; -import { - Ec2InstanceConnectEndpoint, - IntegrationKind, - integrationService, - IntegrationStatusCode, -} from 'teleport/services/integrations'; -import { Node } from 'teleport/services/nodes'; -import { - DiscoverEvent, - DiscoverEventStatus, - userEventService, -} from 'teleport/services/userEvent'; -import TeleportContext from 'teleport/teleportContext'; - -import { EnrollEc2Instance } from './EnrollEc2Instance'; - -const defaultIsCloud = cfg.isCloud; - -describe('test EnrollEc2Instance.tsx', () => { - afterEach(() => { - cfg.isCloud = defaultIsCloud; - jest.restoreAllMocks(); - }); - - const selectedRegion = 'us-west-1'; - - async function selectARegion({ - waitForSelfHosted, - waitForTable, - }: { - waitForTable?: boolean; - waitForSelfHosted?: boolean; - }) { - const regionSelectorElement = screen.getByLabelText(/aws region/i); - fireEvent.focus(regionSelectorElement); - fireEvent.keyDown(regionSelectorElement, { key: 'ArrowDown', keyCode: 40 }); - fireEvent.click(screen.getByText(selectedRegion)); - - if (waitForTable) { - return await screen.findAllByText(/My EC2 Box 1/i); - } - - if (waitForSelfHosted) { - return await screen.findAllByText(/create a join token/i); - } - } - - test('a cloudshell script should be shown if there is an aws permissions error', async () => { - const { ctx, discoverCtx } = getMockedContexts(); - - jest - .spyOn(integrationService, 'fetchAwsEc2Instances') - .mockRejectedValue( - new Error('StatusCode: 403, RequestID: operation error') - ); - // Prevent noise in the test output caused by the error. - jest.spyOn(console, 'error').mockImplementation(); - - renderEc2Instances(ctx, discoverCtx); - await selectARegion({}); - - // Wait for results to be listed. - await screen.findAllByText( - /We were unable to list your EC2 instances. Run the command below/i - ); - - expect(integrationService.fetchAwsEc2Instances).toHaveBeenCalledTimes(1); - expect(ctx.nodeService.fetchNodes).not.toHaveBeenCalled(); - }); - - test('single instance, an instance that is already enrolled should be disabled', async () => { - const { ctx, discoverCtx } = getMockedContexts(); - - jest - .spyOn(integrationService, 'fetchAwsEc2Instances') - .mockResolvedValue({ instances: mockEc2Instances }); - - jest - .spyOn(ctx.nodeService, 'fetchNodes') - .mockResolvedValue({ agents: mockFetchedNodes }); - - renderEc2Instances(ctx, discoverCtx); - await selectARegion({ waitForTable: true }); - - expect(integrationService.fetchAwsEc2Instances).toHaveBeenCalledTimes(1); - expect(ctx.nodeService.fetchNodes).toHaveBeenCalledTimes(1); - - // Get the disabled table rows. - const disabledRowElements = screen - .getAllByTitle( - 'This EC2 instance is already enrolled and is a part of this cluster' - ) - // Only select the radio elements, this is to prevent duplicates since every - // column in the row will have the title we're querying for. - .filter(el => el.innerHTML.includes('type="radio"')) - // Get the row that the radio element is in. - .map(el => el.closest('tr')); - - // Expect the disabled row to be EC2 Box 2. - expect(disabledRowElements[0].innerHTML).toContain('My EC2 Box 2'); - // There should only be one disabled row. - expect(disabledRowElements).toHaveLength(1); - }); - - test('single instance, there should be no disabled rows if the fetchNodes response is empty', async () => { - const { ctx, discoverCtx } = getMockedContexts(); - - jest - .spyOn(integrationService, 'fetchAwsEc2Instances') - .mockResolvedValue({ instances: mockEc2Instances }); - - renderEc2Instances(ctx, discoverCtx); - await selectARegion({ waitForTable: true }); - - expect(integrationService.fetchAwsEc2Instances).toHaveBeenCalledTimes(1); - expect(ctx.nodeService.fetchNodes).toHaveBeenCalledTimes(1); - - // There should be no disabled rows. - expect( - screen.queryAllByTitle( - 'This EC2 instance is already enrolled and is a part of this cluster' - ) - ).toHaveLength(0); - }); - - test('self-hosted, auto discover toggling', async () => { - const { ctx, discoverCtx } = getMockedContexts(); - - jest - .spyOn(integrationService, 'fetchAwsEc2Instances') - .mockResolvedValue({ instances: mockEc2Instances }); - - renderEc2Instances(ctx, discoverCtx); - await selectARegion({ waitForTable: true }); - - // default toggler should not be checked. - expect(screen.getByTestId('toggle')).not.toBeChecked(); - expect(screen.getByText(/next/i, { selector: 'button' })).toBeDisabled(); - - // toggle on auto enroll, should render table. - await userEvent.click(screen.getByText(/auto-enroll all/i)); - expect(screen.getByTestId('toggle')).toBeChecked(); - expect(screen.getByText(/next/i, { selector: 'button' })).toBeEnabled(); - expect(screen.queryByText(/My EC2 Box 1/i)).not.toBeInTheDocument(); - expect(screen.getByText(/create a join token/i)).toBeInTheDocument(); - }); - - test('cloud, auto discover toggling', async () => { - cfg.isCloud = true; - - const { ctx, discoverCtx } = getMockedContexts(); - - jest - .spyOn(integrationService, 'fetchAwsEc2Instances') - .mockResolvedValue({ instances: mockEc2Instances }); - - renderEc2Instances(ctx, discoverCtx); - await selectARegion({ waitForTable: true }); - - // default toggler should be off. - expect(screen.getByTestId('toggle')).not.toBeChecked(); - - await userEvent.click(screen.getByText(/auto-enroll all/i)); - expect(screen.getByText(/next/i, { selector: 'button' })).toBeEnabled(); - expect(screen.queryByText(/create a join token/i)).not.toBeInTheDocument(); - }); - - test('self-hosted, auto discover without existing endpoints', async () => { - const { ctx, discoverCtx } = getMockedContexts(); - - jest - .spyOn(integrationService, 'fetchAwsEc2Instances') - .mockResolvedValue({ instances: mockEc2Instances }); - - jest - .spyOn(integrationService, 'fetchAwsEc2InstanceConnectEndpoints') - .mockResolvedValue({ endpoints: [], dashboardLink: '' }); - - const createDiscoveryConfig = jest - .spyOn(discoveryApi, 'createDiscoveryConfig') - .mockResolvedValue({ - name: 'discovery-cfg', - discoveryGroup: '', - aws: [], - }); - - renderEc2Instances(ctx, discoverCtx); - await selectARegion({ waitForTable: true }); - - // Toggle on. - await userEvent.click(screen.getByText(/auto-enroll all/i)); - - await userEvent.click(screen.getByText(/next/i, { selector: 'button' })); - expect(integrationService.fetchAwsEc2Instances).toHaveBeenCalledWith( - discoverCtx.agentMeta.awsIntegration.name, - { region: selectedRegion, nextToken: '' } - ); - expect(createDiscoveryConfig.mock.calls[0][1]['discoveryGroup']).toBe( - DEFAULT_DISCOVERY_GROUP_NON_CLOUD - ); - expect(discoverCtx.nextStep).toHaveBeenCalledTimes(1); - }); - - test('self-hosted, auto discover without all existing endpoints, creates node resource', async () => { - const { ctx, discoverCtx } = getMockedContexts(); - (discoverCtx.agentMeta as NodeMeta).ec2Ices = endpoints; - - jest - .spyOn(integrationService, 'fetchAwsEc2Instances') - .mockResolvedValue({ instances: mockEc2Instances }); - - jest - .spyOn(integrationService, 'fetchAwsEc2InstanceConnectEndpoints') - .mockResolvedValue({ endpoints, dashboardLink: '' }); - - jest.spyOn(discoveryApi, 'createDiscoveryConfig').mockResolvedValue({ - name: 'discovery-cfg', - discoveryGroup: '', - aws: [], - }); - - renderEc2Instances(ctx, discoverCtx); - await selectARegion({ waitForTable: true }); - - // Toggle on. - await userEvent.click(screen.getByText(/auto-enroll all/i)); - - await userEvent.click(screen.getByText(/next/i, { selector: 'button' })); - expect(integrationService.fetchAwsEc2Instances).toHaveBeenCalledTimes(1); - expect(discoveryApi.createDiscoveryConfig).toHaveBeenCalledTimes(1); - expect(discoverCtx.nextStep).not.toHaveBeenCalled(); - expect(discoverCtx.emitEvent).toHaveBeenCalledWith( - { stepStatus: DiscoverEventStatus.Skipped }, - { - eventName: DiscoverEvent.EC2DeployEICE, - } - ); - - await screen.findByText(/created teleport node/i); - expect(ctx.nodeService.createNode).toHaveBeenCalledTimes(1); - }); - - test('cloud, auto discover with all existing created endpoints and no auto discovery config', async () => { - cfg.isCloud = true; - - let { ctx, discoverCtx } = getMockedContexts(); - - jest - .spyOn(integrationService, 'fetchAwsEc2Instances') - .mockResolvedValue({ instances: mockEc2Instances }); - - jest - .spyOn(integrationService, 'fetchAwsEc2InstanceConnectEndpoints') - .mockResolvedValue({ - endpoints, - dashboardLink: '', - }); - - const createDiscoveryConfig = jest - .spyOn(discoveryApi, 'createDiscoveryConfig') - .mockResolvedValue({ - name: 'discovery-cfg', - discoveryGroup: '', - aws: [], - }); - - renderEc2Instances(ctx, discoverCtx); - await selectARegion({ waitForTable: true }); - - // Toggle on. - await userEvent.click(screen.getByText(/auto-enroll all/i)); - - await userEvent.click(screen.getByText(/next/i, { selector: 'button' })); - expect(integrationService.fetchAwsEc2Instances).toHaveBeenCalledWith( - discoverCtx.agentMeta.awsIntegration.name, - { region: selectedRegion, nextToken: '' } - ); - expect(createDiscoveryConfig.mock.calls[0][1]['discoveryGroup']).toBe( - discoveryApi.DISCOVERY_GROUP_CLOUD - ); - expect(discoverCtx.nextStep).not.toHaveBeenCalled(); - expect(discoverCtx.emitEvent).toHaveBeenCalledWith( - { stepStatus: DiscoverEventStatus.Skipped }, - { - eventName: DiscoverEvent.EC2DeployEICE, - } - ); - }); - - test('cloud, auto discover with all existing created endpoints, with already set discovery config', async () => { - cfg.isCloud = true; - - let { ctx, discoverCtx } = getMockedContexts(true /* withAutoDiscovery */); - - jest - .spyOn(integrationService, 'fetchAwsEc2Instances') - .mockResolvedValue({ instances: mockEc2Instances }); - - jest - .spyOn(integrationService, 'fetchAwsEc2InstanceConnectEndpoints') - .mockResolvedValue({ - endpoints: [ - { - name: 'endpoint-1', - state: 'create-complete', - dashboardLink: '', - subnetId: 'subnet-1', - vpcId: 'vpc-1', - }, - { - name: 'endpoint-2', - state: 'create-complete', - dashboardLink: '', - subnetId: 'subnet-2', - vpcId: 'vpc-2', - }, - { - name: 'endpoint-3', - state: 'create-complete', - dashboardLink: '', - subnetId: 'subnet-3', - vpcId: 'vpc-3', - }, - ], - dashboardLink: '', - }); - - jest.spyOn(discoveryApi, 'createDiscoveryConfig').mockResolvedValue({ - name: 'discovery-cfg', - discoveryGroup: '', - aws: [], - }); - - jest.spyOn(ctx.nodeService, 'createNode').mockResolvedValue({} as any); - - renderEc2Instances(ctx, discoverCtx); - await selectARegion({ waitForTable: true }); - - // Toggle on. - await userEvent.click(screen.getByText(/auto-enroll all/i)); - - await userEvent.click(screen.getByText(/next/i, { selector: 'button' })); - expect(integrationService.fetchAwsEc2Instances).toHaveBeenCalledWith( - discoverCtx.agentMeta.awsIntegration.name, - { region: selectedRegion, nextToken: '' } - ); - expect(discoveryApi.createDiscoveryConfig).not.toHaveBeenCalled(); - expect(discoverCtx.nextStep).not.toHaveBeenCalled(); - expect(ctx.nodeService.createNode).not.toHaveBeenCalled(); - - expect(discoverCtx.emitEvent).toHaveBeenCalledWith( - { stepStatus: DiscoverEventStatus.Skipped }, - { - eventName: DiscoverEvent.EC2DeployEICE, - } - ); - - await screen.findByText(/All endpoints required are created/i); - }); - - test('cloud, with partially created endpoints, with already set discovery config', async () => { - cfg.isCloud = true; - - const { ctx, discoverCtx } = getMockedContexts( - true /* withAutoDiscovery */ - ); - - jest - .spyOn(integrationService, 'fetchAwsEc2Instances') - .mockResolvedValue({ instances: mockEc2Instances }); - - const fetchEndpoints = jest - .spyOn(integrationService, 'fetchAwsEc2InstanceConnectEndpoints') - .mockResolvedValueOnce({ - endpoints: [ - { - name: 'endpoint-1', - state: 'create-complete', - dashboardLink: '', - subnetId: 'subnet-1', - vpcId: 'vpc-1', - }, - { - name: 'endpoint-2', - state: 'create-in-progress', // <-- should trigger polling - dashboardLink: '', - subnetId: 'subnet-2', - vpcId: 'vpc-2', - }, - { - name: 'endpoint-3', - state: 'create-complete', - dashboardLink: '', - subnetId: 'subnet-3', - vpcId: 'vpc-3', - }, - ], - dashboardLink: '', - }) - .mockResolvedValueOnce({ - endpoints: [ - { - name: 'endpoint-2', - state: 'create-complete', // <-- should stop polling - dashboardLink: '', - subnetId: 'subnet-2', - vpcId: 'vpc-2', - }, - ], - dashboardLink: '', - }); - jest.spyOn(discoveryApi, 'createDiscoveryConfig').mockResolvedValue({ - name: 'discovery-cfg', - discoveryGroup: '', - aws: [], - }); - jest.spyOn(ctx.nodeService, 'createNode').mockResolvedValue({} as any); - - renderEc2Instances(ctx, discoverCtx); - await selectARegion({ waitForTable: true }); - - await userEvent.click(screen.getByText(/auto-enroll all/i)); - expect(screen.getByTestId('toggle')).toBeChecked(); - - // Test it's polling. - jest.useFakeTimers(); - fireEvent.click(screen.getByText(/next/i, { selector: 'button' })); - await screen.findByText(/this may take a few minutes/i); - - expect(integrationService.fetchAwsEc2Instances).toHaveBeenCalledTimes(1); - expect(discoveryApi.createDiscoveryConfig).not.toHaveBeenCalled(); - expect(ctx.nodeService.createNode).not.toHaveBeenCalled(); - expect(discoverCtx.nextStep).not.toHaveBeenCalled(); - expect(discoverCtx.emitEvent).toHaveBeenCalledWith( - { stepStatus: DiscoverEventStatus.Skipped }, - { - eventName: DiscoverEvent.EC2DeployEICE, - } - ); - expect(fetchEndpoints).toHaveBeenCalledTimes(1); - fetchEndpoints.mockClear(); - - // advance timer to call the endpoint with completed state - await act(async () => jest.advanceTimersByTime(10000)); - await screen.findByText(/All endpoints required are created/i); - expect(fetchEndpoints).toHaveBeenCalledTimes(1); - - jest.useRealTimers(); - }); -}); - -function getMockedContexts(withAutoDiscovery = false) { - const ctx = createTeleportContext(); - const discoverCtx: DiscoverContextState = { - agentMeta: { - resourceName: 'node-name', - awsRegion: 'us-west-1', - agentMatcherLabels: [], - db: {} as any, - selectedAwsRdsDb: {} as any, - node: mockFetchedNodes[0], - awsIntegration: { - kind: IntegrationKind.AwsOidc, - name: 'test-oidc', - resourceType: 'integration', - spec: { - roleArn: 'arn:aws:iam::123456789012:role/test-role-arn', - issuerS3Bucket: '', - issuerS3Prefix: '', - }, - statusCode: IntegrationStatusCode.Running, - }, - autoDiscovery: withAutoDiscovery - ? { - config: { name: '', discoveryGroup: '', aws: [] }, - requiredVpcsAndSubnets: {}, - } - : undefined, - }, - currentStep: 0, - nextStep: jest.fn(), - prevStep: () => null, - onSelectResource: () => null, - resourceSpec: {} as any, - exitFlow: () => null, - viewConfig: null, - indexedViews: [], - setResourceSpec: () => null, - updateAgentMeta: () => null, - emitErrorEvent: () => null, - emitEvent: jest.fn(), - eventState: null, - }; - - jest.spyOn(ctx.nodeService, 'fetchNodes').mockResolvedValue({ agents: [] }); - jest - .spyOn(ctx.nodeService, 'createNode') - .mockResolvedValue(mockFetchedNodes[0]); - jest - .spyOn(userEventService, 'captureDiscoverEvent') - .mockResolvedValue(undefined as never); - - return { ctx, discoverCtx }; -} - -function renderEc2Instances( - ctx: TeleportContext, - discoverCtx: DiscoverContextState -) { - return render( - - - - - - - - - - ); -} - -const mockEc2Instances: Node[] = [ - { - id: 'ec2-instance-1', - kind: 'node', - clusterId: 'cluster', - hostname: 'ec2-hostname-1', - labels: [ - { name: 'teleport.dev/instance-id', value: 'instance-ec2-1' }, - { name: 'Name', value: 'My EC2 Box 1' }, - ], - addr: 'ec2.1.com', - tunnel: false, - subKind: 'openssh-ec2-ice', - sshLogins: ['test'], - awsMetadata: { - accountId: 'test-account', - instanceId: 'instance-ec2-1', - region: 'us-west-1', - vpcId: 'vpc-1', - integration: 'test', - subnetId: 'subnet-1', - }, - }, - { - id: 'ec2-instance-2', - kind: 'node', - clusterId: 'cluster', - hostname: 'ec2-hostname-2', - labels: [ - { name: 'teleport.dev/instance-id', value: 'instance-ec2-2' }, - { name: 'Name', value: 'My EC2 Box 2' }, - ], - addr: 'ec2.2.com', - tunnel: false, - subKind: 'openssh-ec2-ice', - sshLogins: ['test'], - awsMetadata: { - accountId: 'test-account', - instanceId: 'instance-ec2-2', - region: 'us-west-1', - vpcId: 'vpc-2', - integration: 'test', - subnetId: 'subnet-2', - }, - }, - { - id: 'ec2-instance-3', - kind: 'node', - clusterId: 'cluster', - hostname: 'ec2-hostname-3', - labels: [ - { name: 'teleport.dev/instance-id', value: 'instance-ec2-3' }, - { name: 'Name', value: 'My EC2 Box 3' }, - ], - addr: 'ec2.3.com', - tunnel: false, - subKind: 'openssh-ec2-ice', - sshLogins: ['test'], - awsMetadata: { - accountId: 'test-account', - instanceId: 'instance-ec2-3', - region: 'us-west-1', - vpcId: 'vpc-1', - integration: 'test', - subnetId: 'subnet-2', - }, - }, - { - id: 'ec2-instance-4', - kind: 'node', - clusterId: 'cluster', - hostname: 'ec2-hostname-4', - labels: [ - { name: 'teleport.dev/instance-id', value: 'instance-ec2-4' }, - { name: 'Name', value: 'My EC2 Box 4' }, - ], - addr: 'ec2.4.com', - tunnel: false, - subKind: 'openssh-ec2-ice', - sshLogins: ['test'], - awsMetadata: { - accountId: 'test-account', - instanceId: 'instance-ec2-4', - region: 'us-west-1', - vpcId: 'vpc-2', - integration: 'test', - subnetId: 'subnet-2', - }, - }, - { - id: 'ec2-instance-5', - kind: 'node', - clusterId: 'cluster', - hostname: 'ec2-hostname-5', - labels: [ - { name: 'teleport.dev/instance-id', value: 'instance-ec2-5' }, - { name: 'Name', value: 'My EC2 Box 5' }, - ], - addr: 'ec2.5.com', - tunnel: false, - subKind: 'openssh-ec2-ice', - sshLogins: ['test'], - awsMetadata: { - accountId: 'test-account', - instanceId: 'instance-ec2-5', - region: 'us-west-1', - vpcId: 'vpc-3', - integration: 'test', - subnetId: 'subnet-3', - }, - }, -]; - -const mockFetchedNodes: Node[] = [ - { - id: 'ec2-instance-2', - kind: 'node', - clusterId: 'cluster', - hostname: 'ec2-hostname-2', - labels: [ - { name: 'teleport.dev/instance-id', value: 'instance-ec2-2' }, - { name: 'Name', value: 'My EC2 Box 2' }, - ], - addr: 'ec2.2.com', - tunnel: false, - subKind: 'openssh-ec2-ice', - sshLogins: ['test'], - awsMetadata: { - instanceId: 'some-id', - accountId: '', - region: 'us-east-1', - vpcId: '', - integration: '', - subnetId: '', - }, - }, -]; - -const endpoints: Ec2InstanceConnectEndpoint[] = [ - { - name: 'endpoint-1', - state: 'create-complete', - dashboardLink: '', - subnetId: 'subnet-1', - vpcId: 'vpc-1', - }, - { - name: 'endpoint-2', - state: 'create-complete', - dashboardLink: '', - subnetId: 'subnet-2', - vpcId: 'vpc-2', - }, - { - name: 'endpoint-3', - state: 'create-complete', - dashboardLink: '', - subnetId: 'subnet-3', - vpcId: 'vpc-3', - }, -]; diff --git a/web/packages/teleport/src/Discover/Server/EnrollEc2Instance/EnrollEc2Instance.tsx b/web/packages/teleport/src/Discover/Server/EnrollEc2Instance/EnrollEc2Instance.tsx deleted file mode 100644 index e836c1e05d42c..0000000000000 --- a/web/packages/teleport/src/Discover/Server/EnrollEc2Instance/EnrollEc2Instance.tsx +++ /dev/null @@ -1,565 +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 } from 'react'; -import { Link as InternalLink } from 'react-router-dom'; - -import { Box, Link as ExternalLink, Text, Toggle } from 'design'; -import { Danger } from 'design/Alert'; -import { OutlineInfo } from 'design/Alert/Alert'; -import { FetchStatus } from 'design/DataTable/types'; -import { IconTooltip } from 'design/Tooltip'; -import useAttempt from 'shared/hooks/useAttemptNext'; -import { getErrMessage } from 'shared/utils/errorType'; - -import cfg from 'teleport/config'; -import { ConfigureIamPerms } from 'teleport/Discover/Shared/Aws/ConfigureIamPerms'; -import { - getAttemptsOneOfErrorMsg, - isIamPermError, -} from 'teleport/Discover/Shared/Aws/error'; -import { AwsRegionSelector } from 'teleport/Discover/Shared/AwsRegionSelector'; -import { ConfigureDiscoveryServiceDirections } from 'teleport/Discover/Shared/ConfigureDiscoveryService'; -import { NodeMeta, useDiscover } from 'teleport/Discover/useDiscover'; -import { - createDiscoveryConfig, - DEFAULT_DISCOVERY_GROUP_NON_CLOUD, - DISCOVERY_GROUP_CLOUD, - DiscoveryConfig, -} from 'teleport/services/discovery'; -import { - Ec2InstanceConnectEndpoint, - integrationService, - Regions, -} from 'teleport/services/integrations'; -import { Node } from 'teleport/services/nodes'; -import { - DiscoverEvent, - DiscoverEventStatus, -} from 'teleport/services/userEvent'; -import useTeleport from 'teleport/useTeleport'; - -import { ActionButtons, Header } from '../../Shared'; -import { CreateEc2IceDialog } from '../CreateEc2Ice/CreateEc2IceDialog'; -import { Ec2InstanceList } from './Ec2InstanceList'; -import { NoEc2IceRequiredDialog } from './NoEc2IceRequiredDialog'; - -// CheckedEc2Instance is a type to describe that an EC2 instance -// has been checked to determine whether or not it is already enrolled in the cluster. -export type CheckedEc2Instance = Node & { - ec2InstanceExists?: boolean; -}; - -type TableData = { - items: CheckedEc2Instance[]; - fetchStatus: FetchStatus; - nextToken?: string; -}; - -const emptyTableData: TableData = { - items: [], - fetchStatus: 'disabled', - nextToken: '', -}; - -export function EnrollEc2Instance() { - const { agentMeta, emitErrorEvent, nextStep, updateAgentMeta, emitEvent } = - useDiscover(); - const { nodeService, storeUser } = useTeleport(); - - const [currRegion, setCurrRegion] = useState(); - const [foundAllRequiredEices, setFoundAllRequiredEices] = - useState(); - const [selectedInstance, setSelectedInstance] = - useState(); - - const [tableData, setTableData] = useState({ - items: [], - nextToken: '', - fetchStatus: 'disabled', - }); - - const [autoDiscoveryCfg, setAutoDiscoveryCfg] = useState(); - const [wantAutoDiscover, setWantAutoDiscover] = useState(false); - const [discoveryGroupName, setDiscoveryGroupName] = useState(() => - cfg.isCloud ? '' : DEFAULT_DISCOVERY_GROUP_NON_CLOUD - ); - - const { - attempt: fetchEc2InstancesAttempt, - setAttempt: setFetchEc2InstancesAttempt, - } = useAttempt(''); - - const { attempt: fetchEc2IceAttempt, setAttempt: setFetchEc2IceAttempt } = - useAttempt(''); - - function fetchEc2InstancesWithNewRegion(region: Regions) { - if (region) { - setCurrRegion(region); - fetchEc2Instances({ ...emptyTableData }, region); - } - } - - function fetchNextPage() { - fetchEc2Instances({ ...tableData }, currRegion); - } - - function refreshEc2Instances() { - setSelectedInstance(null); - setFetchEc2IceAttempt({ status: '' }); - // When refreshing, start the table back at page 1. - fetchEc2Instances({ ...tableData, items: [] }, currRegion); - } - - async function fetchEc2Instances(data: TableData, region: Regions) { - const integrationName = agentMeta.awsIntegration.name; - - setTableData({ ...data, fetchStatus: 'loading' }); - setFetchEc2InstancesAttempt({ status: 'processing' }); - - try { - let fetchedEc2Instances: Node[] = []; - let nextPage = ''; - // Requires list of all ec2 instances - // to formulate map of VPCs and its subnets. - do { - const { instances, nextToken } = - await integrationService.fetchAwsEc2Instances(integrationName, { - region: region, - nextToken: nextPage, - }); - - fetchedEc2Instances = [...fetchedEc2Instances, ...instances]; - nextPage = nextToken; - } while (nextPage); - // Abort if there were no EC2 instances for the selected region. - if (fetchedEc2Instances.length <= 0) { - setFetchEc2InstancesAttempt({ status: 'success' }); - setTableData({ ...data, fetchStatus: 'disabled' }); - return; - } - - // Check if fetched EC2 instances are already in the cluster - // so that they can be disabled in the table. - - // Builds the predicate string that will query for - // all the fetched EC2 instances by searching by the AWS instance ID label. - const instanceIdPredicateQueries: string[] = fetchedEc2Instances.map( - d => - `labels["teleport.dev/instance-id"] == "${d.awsMetadata.instanceId}"` - ); - const fullPredicateQuery = instanceIdPredicateQueries.join(' || '); - const { agents: fetchedNodes } = await nodeService.fetchNodes( - cfg.proxyCluster, - { - query: fullPredicateQuery, - limit: fetchedEc2Instances.length, - } - ); - - const ec2InstancesLookupByInstanceId: Record = {}; - fetchedNodes.forEach(d => { - // Extract the instanceId of the fetched node from its label. - const instanceId = d.labels.find( - label => label.name === 'teleport.dev/instance-id' - )?.value; - - ec2InstancesLookupByInstanceId[instanceId] = d; - }); - - // Check for already existing EC2 instances. - const checkedEc2Instances: CheckedEc2Instance[] = fetchedEc2Instances.map( - ec2 => { - const instance = - ec2InstancesLookupByInstanceId[ec2.awsMetadata.instanceId]; - if (instance) { - return { - ...ec2, - ec2InstanceExists: true, - }; - } - return ec2; - } - ); - - setFetchEc2InstancesAttempt({ status: 'success' }); - setTableData({ - ...data, - fetchStatus: 'disabled', - items: checkedEc2Instances, - }); - } catch (err) { - const errMsg = getErrMessage(err); - setTableData(data); - setFetchEc2InstancesAttempt({ status: 'failed', statusText: errMsg }); - emitErrorEvent(`ec2 instance fetch error: ${errMsg}`); - } - } - - /** - * @returns - * - undefined: if there was an error from request - * - array: list of ec2 instance connect endpoints or, - * empty list if no endpoints - */ - async function fetchEc2InstanceConnectEndpointsWithErrorHandling( - vpcIds: string[] - ) { - const integrationName = agentMeta.awsIntegration.name; - - try { - const { endpoints: fetchedEc2Ices } = - await integrationService.fetchAwsEc2InstanceConnectEndpoints( - integrationName, - { - region: currRegion, - vpcIds, - } - ); - return fetchedEc2Ices; - } catch (err) { - const errMsg = getErrMessage(err); - setFetchEc2IceAttempt({ status: 'failed', statusText: errMsg }); - emitErrorEvent(`ec2 instance connect endpoint fetch error: ${errMsg}`); - } - } - - function clear() { - setFetchEc2InstancesAttempt({ status: '' }); - setFetchEc2IceAttempt({ status: '' }); - setTableData(emptyTableData); - setSelectedInstance(null); - setAutoDiscoveryCfg(null); - setFoundAllRequiredEices(null); - } - - /** - * @returns - * - undefined: if there was an error from request or - * - object: the created discovery config object - */ - async function createAutoDiscoveryConfigWithErrorHandling() { - // We check the agentmeta because a user could've returned - // to this step from the deploy step (clicking "back" button) - const alreadyCreatedCfg = - agentMeta?.autoDiscovery && agentMeta.awsRegion === currRegion; - - if (!autoDiscoveryCfg && !alreadyCreatedCfg) { - try { - const discoveryConfig = await createDiscoveryConfig( - storeUser.getClusterId(), - { - name: crypto.randomUUID(), - discoveryGroup: cfg.isCloud - ? DISCOVERY_GROUP_CLOUD - : discoveryGroupName, - aws: [ - { - types: ['ec2'], - regions: [currRegion], - tags: { '*': ['*'] }, - integration: agentMeta.awsIntegration.name, - }, - ], - } - ); - return discoveryConfig; - } catch (err) { - const errMsg = getErrMessage(err); - setFetchEc2IceAttempt({ status: 'failed', statusText: errMsg }); - emitErrorEvent(`failed to create discovery config: ${errMsg}`); - } - } - - if (agentMeta.autoDiscovery) { - return agentMeta.autoDiscovery.config; - } - - return autoDiscoveryCfg; - } - - /** - * Note: takes about 1 minute to go from `create-in-progress` to `create-complete` - * `create-in-progress` can be polled until it reaches `create-complete` - */ - function getCompleteOrInProgressEndpoints( - endpoints: Ec2InstanceConnectEndpoint[] - ) { - return endpoints.filter( - e => e.state === 'create-complete' || e.state === 'create-in-progress' - ); - } - - async function enableAutoDiscovery() { - // Collect unique vpcIds and its subnet for instances. - const seenVpcIdAndSubnets: Record = {}; - tableData.items.forEach(i => { - const vpcId = i.awsMetadata.vpcId; - if (!seenVpcIdAndSubnets[vpcId]) { - // Instances can have the same vpcId and be assigned - // different subnetIds, but each subnet belongs to a - // single VPC, so it does not matter which subnet we - // assign to this vpc. - seenVpcIdAndSubnets[vpcId] = i.awsMetadata.subnetId; - } - }); - - // Check if an instance connect endpoint exist for the collected vpcs. - - // instancesVpcIds can be zero if if no ec2 instances are enrolled. - const instancesVpcIds = Object.keys(seenVpcIdAndSubnets); - const gotEc2Ices = - await fetchEc2InstanceConnectEndpointsWithErrorHandling(instancesVpcIds); - if (!gotEc2Ices) { - // errored - return; - } - - const listOfExistingEndpoints = - getCompleteOrInProgressEndpoints(gotEc2Ices); - - // Determine which instance vpc needs a ec2 instance connect endpoint. - const requiredVpcsAndSubnets: Record = {}; - if (instancesVpcIds.length != gotEc2Ices.length) { - instancesVpcIds.forEach(instanceVpcId => { - const found = gotEc2Ices.some( - endpoint => endpoint.vpcId == instanceVpcId - ); - if (!found) { - requiredVpcsAndSubnets[instanceVpcId] = [ - seenVpcIdAndSubnets[instanceVpcId], - ]; - } - }); - } - - const discoveryConfig = await createAutoDiscoveryConfigWithErrorHandling(); - if (!discoveryConfig) { - // errored - return; - } - setFetchEc2IceAttempt({ status: 'success' }); - setAutoDiscoveryCfg(discoveryConfig); - updateAgentMeta({ - ...(agentMeta as NodeMeta), - ec2Ices: listOfExistingEndpoints, - autoDiscovery: { - config: discoveryConfig, - requiredVpcsAndSubnets, - }, - awsRegion: currRegion, - }); - - // Check if creating endpoints is required. - - const allRequiredEndpointsExists = - listOfExistingEndpoints.length > 0 && - Object.keys(requiredVpcsAndSubnets).length === 0; - - if (allRequiredEndpointsExists || instancesVpcIds.length === 0) { - setFoundAllRequiredEices(listOfExistingEndpoints); - emitEvent( - { stepStatus: DiscoverEventStatus.Skipped }, - { - eventName: DiscoverEvent.EC2DeployEICE, - } - ); - } else { - nextStep(); - } - } - - async function handleOnProceed() { - setFetchEc2IceAttempt({ status: 'processing' }); - - if (wantAutoDiscover) { - enableAutoDiscovery(); - } else { - const ec2Ices = await fetchEc2InstanceConnectEndpointsWithErrorHandling([ - selectedInstance.awsMetadata.vpcId, - ]); - if (!ec2Ices) { - return; - } - setFetchEc2IceAttempt({ status: 'success' }); - - const existingEndpoint = getCompleteOrInProgressEndpoints(ec2Ices); - - // If we find existing EICE's that are either create-complete or create-in-progress, we skip the step where we create the EICE. - - // We first check for any EICE's that are create-complete, if we find one, the dialog will go straight to creating the node. - // If we don't find any, we check if there are any that are create-in-progress, if we find one, the dialog will wait until - // it's create-complete and then create the node. - if (existingEndpoint.length > 0) { - setFoundAllRequiredEices(existingEndpoint); - // Since the EICE had already been deployed before the flow, emit an event for EC2DeployEICE as `Skipped`. - emitEvent( - { stepStatus: DiscoverEventStatus.Skipped }, - { - eventName: DiscoverEvent.EC2DeployEICE, - } - ); - updateAgentMeta({ - ...(agentMeta as NodeMeta), - node: selectedInstance, - ec2Ices: existingEndpoint, - awsRegion: currRegion, - }); - // If we find neither, then we go to the next step to create the EICE. - } else { - updateAgentMeta({ - ...(agentMeta as NodeMeta), - node: selectedInstance, - awsRegion: currRegion, - }); - nextStep(); - } - } - } - - // (Temp) - // Self hosted auto enroll is different from cloud. - // For cloud, we already run the discovery service for customer. - // For on-prem, user has to run their own discovery service. - // We hide the table for on-prem if they are wanting auto discover - // because it takes up so much space to give them instructions. - // Future work will simply provide user a script so we can show the table then. - const showTable = cfg.isCloud || !wantAutoDiscover; - - const errorMsg = getAttemptsOneOfErrorMsg( - fetchEc2InstancesAttempt, - fetchEc2IceAttempt - ); - - const hasIamPermError = - isIamPermError(fetchEc2IceAttempt) || - isIamPermError(fetchEc2InstancesAttempt); - - const showContent = !hasIamPermError && currRegion; - const showAutoEnrollToggle = - !errorMsg && fetchEc2InstancesAttempt.status === 'success'; - - return ( - -
Enroll an EC2 instance
- - Select the AWS Region you would like to see EC2 instances for: - - - {!hasIamPermError && errorMsg && {errorMsg}} - {showContent && ( - <> - {showAutoEnrollToggle && ( - - setWantAutoDiscover(b => !b)} - disabled={tableData.items.length === 0} // necessary? - > - - Auto-enroll all EC2 instances for selected region - - - Auto-enroll will automatically identify all EC2 instances from - the selected region and register them as node resources in - your infrastructure. - - - {wantAutoDiscover && ( - - AWS enforces{' '} - - strict quotas - {' '} - on auto-enrolled EC2 instances, particularly for the maximum - number of allowed concurrent connections per EC2 Instance - Connect Endpoint. If these quotas restrict your needs, - consider following the{' '} - - Teleport service installation - {' '} - flow instead. - - )} - {!cfg.isCloud && wantAutoDiscover && ( - - )} - - )} - {showTable && ( - - )} - - )} - {foundAllRequiredEices?.length > 0 && ( - nextStep(2)} - existingEices={foundAllRequiredEices} - /> - )} - {foundAllRequiredEices?.length === 0 && ( - nextStep(2)} /> - )} - {hasIamPermError && ( - - - - )} - -
- ); -} diff --git a/web/packages/teleport/src/Discover/Server/EnrollEc2Instance/NoEc2IceRequiredDialog.tsx b/web/packages/teleport/src/Discover/Server/EnrollEc2Instance/NoEc2IceRequiredDialog.tsx deleted file mode 100644 index f1050435df708..0000000000000 --- a/web/packages/teleport/src/Discover/Server/EnrollEc2Instance/NoEc2IceRequiredDialog.tsx +++ /dev/null @@ -1,51 +0,0 @@ -/** - * 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 { ButtonPrimary, Flex, Mark, Text } from 'design'; -import Dialog, { DialogContent } from 'design/DialogConfirmation'; -import * as Icons from 'design/Icon'; - -import { NodeMeta, useDiscover } from 'teleport/Discover/useDiscover'; - -export function NoEc2IceRequiredDialog({ nextStep }: { nextStep: () => void }) { - const { agentMeta } = useDiscover(); - const typedAgentMeta = agentMeta as NodeMeta; - - return ( - - - - - - The discovery service can take a few minutes to finish - auto-enrolling resources found in region{' '} - {typedAgentMeta.awsRegion}. - - - nextStep()}> - Next - - - - ); -} diff --git a/web/packages/teleport/src/Discover/Server/index.tsx b/web/packages/teleport/src/Discover/Server/index.tsx index 143344921839c..4f31ab999965d 100644 --- a/web/packages/teleport/src/Discover/Server/index.tsx +++ b/web/packages/teleport/src/Discover/Server/index.tsx @@ -31,9 +31,7 @@ import { import { ResourceSpec, ServerLocation } from '../SelectResource'; import { ConfigureDiscoveryService } from '../Shared/ConfigureDiscoveryService'; -import { CreateEc2Ice } from './CreateEc2Ice/CreateEc2Ice'; import { DiscoveryConfigSsm } from './DiscoveryConfigSsm/DiscoveryConfigSsm'; -import { EnrollEc2Instance } from './EnrollEc2Instance/EnrollEc2Instance'; import { ServerWrapper } from './ServerWrapper'; export const ServerResource: ResourceViewConfig = { @@ -57,29 +55,6 @@ export const ServerResource: ResourceViewConfig = { let configureResourceViews; const { nodeMeta } = resource; if ( - nodeMeta?.location === ServerLocation.Aws && - nodeMeta.discoveryConfigMethod === - DiscoverDiscoveryConfigMethod.AwsEc2Eice - ) { - configureResourceViews = [ - { - title: 'Connect AWS Account', - component: AwsAccount, - eventName: DiscoverEvent.IntegrationAWSOIDCConnectEvent, - }, - { - title: 'Enroll EC2 Instance', - component: EnrollEc2Instance, - eventName: DiscoverEvent.EC2InstanceSelection, - }, - { - title: 'Create EC2 Instance Connect Endpoint', - component: CreateEc2Ice, - eventName: DiscoverEvent.CreateNode, - manuallyEmitSuccessEvent: true, - }, - ]; - } else if ( nodeMeta?.location === ServerLocation.Aws && nodeMeta.discoveryConfigMethod === DiscoverDiscoveryConfigMethod.AwsEc2Ssm ) { diff --git a/web/packages/teleport/src/Discover/Shared/Aws/ConfigureIamPerms.tsx b/web/packages/teleport/src/Discover/Shared/Aws/ConfigureIamPerms.tsx index cb4670e649f05..99f0f851b001d 100644 --- a/web/packages/teleport/src/Discover/Shared/Aws/ConfigureIamPerms.tsx +++ b/web/packages/teleport/src/Discover/Shared/Aws/ConfigureIamPerms.tsx @@ -51,44 +51,7 @@ export function ConfigureIamPerms({ switch (kind) { case 'ec2': { - iamPolicyName = 'EC2InstanceConnectEndpoint'; - msg = 'We were unable to list your EC2 instances.'; - scriptUrl = cfg.getEc2InstanceConnectIAMConfigureScriptUrl({ - region, - iamRoleName, - accountID, - }); - - const json = `{ - "Version": "2012-10-17", - "Statement": [ - { - "Effect": "Allow", - "Action": [ - "ec2:DescribeInstances", - "ec2:DescribeInstanceConnectEndpoints", - "ec2:DescribeSecurityGroups", - "ec2:CreateInstanceConnectEndpoint", - "ec2:CreateTags", - "ec2:CreateNetworkInterface", - "iam:CreateServiceLinkedRole", - "ec2-instance-connect:SendSSHPublicKey", - "ec2-instance-connect:OpenTunnel" - ], - "Resource": "*" - } - ] -}`; - - editor = ( - - - - ); + // TODO(marco): should we remove `ec2` from the AwsResourceKind? break; } case 'eks': { diff --git a/web/packages/teleport/src/Discover/useDiscover.tsx b/web/packages/teleport/src/Discover/useDiscover.tsx index 2b353eb0d4f3d..11185ab4aaa2f 100644 --- a/web/packages/teleport/src/Discover/useDiscover.tsx +++ b/web/packages/teleport/src/Discover/useDiscover.tsx @@ -30,7 +30,6 @@ import type { Database } from 'teleport/services/databases'; import { DiscoveryConfig } from 'teleport/services/discovery'; import type { AwsRdsDatabase, - Ec2InstanceConnectEndpoint, Integration, Regions, } from 'teleport/services/integrations'; @@ -544,7 +543,6 @@ export type AutoDiscovery = { // that needs to be preserved throughout the flow. export type NodeMeta = BaseMeta & { node: Node; - ec2Ices?: Ec2InstanceConnectEndpoint[]; }; // DbMeta describes the fields for a db resource diff --git a/web/packages/teleport/src/config.ts b/web/packages/teleport/src/config.ts index af98acebdcde5..3078a118780ac 100644 --- a/web/packages/teleport/src/config.ts +++ b/web/packages/teleport/src/config.ts @@ -353,8 +353,6 @@ const cfg = { '/v1/webapi/scripts/integrations/configure/deployservice-iam.sh?integrationName=:integrationName&awsRegion=:region&role=:awsOidcRoleArn&taskRole=:taskRoleArn&awsAccountID=:accountID', awsConfigureIamScriptListDatabasesPath: '/v1/webapi/scripts/integrations/configure/listdatabases-iam.sh?awsRegion=:region&role=:iamRoleName&awsAccountID=:accountID', - awsConfigureIamScriptEc2InstanceConnectPath: - '/v1/webapi/scripts/integrations/configure/eice-iam.sh?awsRegion=:region&role=:iamRoleName&awsAccountID=:accountID', awsConfigureIamEksScriptPath: '/v1/webapi/scripts/integrations/configure/eks-iam.sh?awsRegion=:region&role=:iamRoleName&awsAccountID=:accountID', @@ -396,14 +394,6 @@ const cfg = { '/v2/webapi/sites/:clusterId/integrations/aws-oidc/:name/enrolleksclusters', }, - ec2InstancesListPath: - '/v1/webapi/sites/:clusterId/integrations/aws-oidc/:name/ec2', - ec2InstanceConnectEndpointsListPath: - '/v1/webapi/sites/:clusterId/integrations/aws-oidc/:name/ec2ice', - // Returns a script that configures the required IAM permissions to enable the usage of EC2 Instance Connect Endpoint to access EC2 instances. - ec2InstanceConnectDeployPath: - '/v1/webapi/sites/:clusterId/integrations/aws-oidc/:name/deployec2ice', - userGroupsListPath: '/v1/webapi/sites/:clusterId/user-groups?searchAsRoles=:searchAsRoles?&limit=:limit?&startKey=:startKey?&query=:query?&search=:search?&sort=:sort?', @@ -1156,33 +1146,6 @@ const cfg = { }); }, - getListEc2InstancesUrl(integrationName: string) { - const clusterId = cfg.proxyCluster; - - return generatePath(cfg.api.ec2InstancesListPath, { - clusterId, - name: integrationName, - }); - }, - - getListEc2InstanceConnectEndpointsUrl(integrationName: string) { - const clusterId = cfg.proxyCluster; - - return generatePath(cfg.api.ec2InstanceConnectEndpointsListPath, { - clusterId, - name: integrationName, - }); - }, - - getDeployEc2InstanceConnectEndpointUrl(integrationName: string) { - const clusterId = cfg.proxyCluster; - - return generatePath(cfg.api.ec2InstanceConnectDeployPath, { - clusterId, - name: integrationName, - }); - }, - getListSecurityGroupsUrl(integrationName: string) { const clusterId = cfg.proxyCluster; @@ -1199,17 +1162,6 @@ const cfg = { }); }, - getEc2InstanceConnectIAMConfigureScriptUrl( - params: UrlAwsConfigureIamScriptParams - ) { - return ( - cfg.baseUrl + - generatePath(cfg.api.awsConfigureIamScriptEc2InstanceConnectPath, { - ...params, - }) - ); - }, - getEksIamConfigureScriptUrl(params: UrlAwsConfigureIamScriptParams) { return ( cfg.baseUrl + diff --git a/web/packages/teleport/src/services/discovery/types.ts b/web/packages/teleport/src/services/discovery/types.ts index c30da28855aa9..2c37c33d025f2 100644 --- a/web/packages/teleport/src/services/discovery/types.ts +++ b/web/packages/teleport/src/services/discovery/types.ts @@ -33,7 +33,6 @@ type AwsMatcherTypes = 'rds' | 'eks' | 'ec2'; export enum InstallParamEnrollMode { Script = 1, - Eice = 2, } // AWSMatcher matches AWS EC2 instances, AWS EKS clusters and AWS Databases diff --git a/web/packages/teleport/src/services/integrations/integrations.ts b/web/packages/teleport/src/services/integrations/integrations.ts index baaa45c9d9b45..33da3cf2787e9 100644 --- a/web/packages/teleport/src/services/integrations/integrations.ts +++ b/web/packages/teleport/src/services/integrations/integrations.ts @@ -22,7 +22,6 @@ import api from 'teleport/services/api'; import { App } from '../apps'; import makeApp from '../apps/makeApps'; import auth, { MfaChallengeScope } from '../auth/auth'; -import makeNode from '../nodes/makeNode'; import { withUnsupportedLabelFeatureErrorConversion } from '../version/unsupported'; import { AwsDatabaseVpcsResponse, @@ -33,9 +32,6 @@ import { AwsOidcPingResponse, AwsRdsDatabase, CreateAwsAppAccessRequest, - DeployEc2InstanceConnectEndpointRequest, - DeployEc2InstanceConnectEndpointResponse, - Ec2InstanceConnectEndpoint, EnrollEksClustersRequest, EnrollEksClustersResponse, Integration, @@ -50,10 +46,6 @@ import { ListAwsSecurityGroupsResponse, ListAwsSubnetsRequest, ListAwsSubnetsResponse, - ListEc2InstanceConnectEndpointsRequest, - ListEc2InstanceConnectEndpointsResponse, - ListEc2InstancesRequest, - ListEc2InstancesResponse, ListEksClustersRequest, ListEksClustersResponse, RdsEngineIdentifier, @@ -380,52 +372,6 @@ export const integrationService = { }); }, - // Returns a list of EC2 Instances using the ListEC2ICE action of the AWS OIDC Integration. - fetchAwsEc2Instances( - integrationName, - req: ListEc2InstancesRequest - ): Promise { - return api - .post(cfg.getListEc2InstancesUrl(integrationName), req) - .then(json => { - const instances = json?.servers ?? []; - return { - instances: instances.map(makeNode), - nextToken: json?.nextToken, - }; - }); - }, - - // Returns a list of EC2 Instance Connect Endpoints using the ListEC2ICE action of the AWS OIDC Integration. - fetchAwsEc2InstanceConnectEndpoints( - integrationName, - req: ListEc2InstanceConnectEndpointsRequest - ): Promise { - return api - .post(cfg.getListEc2InstanceConnectEndpointsUrl(integrationName), req) - .then(json => { - const endpoints = json?.ec2Ices ?? []; - - return { - endpoints: endpoints.map(makeEc2InstanceConnectEndpoint), - nextToken: json?.nextToken, - dashboardLink: json?.dashboardLink, - }; - }); - }, - - // Deploys an EC2 Instance Connect Endpoint. - deployAwsEc2InstanceConnectEndpoints( - integrationName, - req: DeployEc2InstanceConnectEndpointRequest - ): Promise { - return api - .post(cfg.getDeployEc2InstanceConnectEndpointUrl(integrationName), req) - .then(resp => { - return resp ?? []; - }); - }, - // Returns a list of VPC Security Groups using the ListSecurityGroups action of the AWS OIDC Integration. fetchSecurityGroups( integrationName, @@ -516,20 +462,6 @@ export function makeAwsDatabase(json: any): AwsRdsDatabase { }; } -function makeEc2InstanceConnectEndpoint(json: any): Ec2InstanceConnectEndpoint { - json = json ?? {}; - const { name, state, stateMessage, dashboardLink, subnetId, vpcId } = json; - - return { - name, - state, - stateMessage, - dashboardLink, - subnetId, - vpcId, - }; -} - function makeSecurityGroup(json: any): SecurityGroup { json = json ?? {}; diff --git a/web/packages/teleport/src/services/integrations/types.ts b/web/packages/teleport/src/services/integrations/types.ts index 6fa11432c6af9..9e631c7caf506 100644 --- a/web/packages/teleport/src/services/integrations/types.ts +++ b/web/packages/teleport/src/services/integrations/types.ts @@ -19,7 +19,6 @@ import { Label } from 'teleport/types'; import { ResourceLabel } from '../agents'; -import { Node } from '../nodes'; /** * type Integration v. type Plugin: @@ -568,81 +567,6 @@ export type ListEksClustersResponse = { nextToken?: string; }; -export type ListEc2InstancesRequest = { - region: Regions; - nextToken?: string; -}; - -export type ListEc2InstancesResponse = { - // instances is the list of EC2 Instances. - instances: Node[]; - nextToken?: string; -}; - -export type ListEc2InstanceConnectEndpointsRequest = { - region: Regions; - // VPCIDs is a list of VPCs to filter EC2 Instance Connect Endpoints. - vpcIds: string[]; - nextToken?: string; -}; - -export type ListEc2InstanceConnectEndpointsResponse = { - // endpoints is the list of EC2 Instance Connect Endpoints. - endpoints: Ec2InstanceConnectEndpoint[]; - nextToken?: string; - // DashboardLink is the URL for AWS Web Console that - // lists all the Endpoints for the queries VPCs. - dashboardLink: string; -}; - -export type Ec2InstanceConnectEndpoint = { - name: string; - // state is the current state of the EC2 Instance Connect Endpoint. - state: Ec2InstanceConnectEndpointState; - // stateMessage is an optional message describing the state of the EICE, such as an error message. - stateMessage?: string; - // dashboardLink is a URL to AWS Console where the user can see the EC2 Instance Connect Endpoint. - dashboardLink: string; - // subnetID is the subnet used by the Endpoint. Please note that the Endpoint should be able to reach any subnet within the VPC. - subnetId: string; - // VPCID is the VPC ID where the Endpoint is created. - vpcId: string; -}; - -export type Ec2InstanceConnectEndpointState = - | 'create-in-progress' - | 'create-complete' - | 'create-failed' - | 'delete-in-progress' - | 'delete-complete' - | 'delete-failed'; - -export type AwsOidcDeployEc2InstanceConnectEndpointRequest = { - // SubnetID is the subnet id for the EC2 Instance Connect Endpoint. - subnetId: string; - // SecurityGroupIDs is the list of SecurityGroups to apply to the Endpoint. - // If not specified, the Endpoint will receive the default SG for the Subnet's VPC. - securityGroupIds?: string[]; -}; - -export type DeployEc2InstanceConnectEndpointRequest = { - region: Regions; - // Endpoints is a list of endpoinst to create. - endpoints: AwsOidcDeployEc2InstanceConnectEndpointRequest[]; -}; - -export type AwsEc2InstanceConnectEndpoint = { - // Name is the EC2 Instance Connect Endpoint name. - name: string; - // SubnetID is the subnet where this endpoint was created. - subnetId: string; -}; - -export type DeployEc2InstanceConnectEndpointResponse = { - // Endpoints is a list of created endpoints - endpoints: AwsEc2InstanceConnectEndpoint[]; -}; - export type Subnet = { /** * Subnet name. diff --git a/web/packages/teleport/src/services/userEvent/types.ts b/web/packages/teleport/src/services/userEvent/types.ts index 16e927986df65..09b0b5f7003f5 100644 --- a/web/packages/teleport/src/services/userEvent/types.ts +++ b/web/packages/teleport/src/services/userEvent/types.ts @@ -89,10 +89,7 @@ export enum DiscoverEvent { DatabaseRegister = 'tp.ui.discover.database.register', DatabaseConfigureMTLS = 'tp.ui.discover.database.configure.mtls', DatabaseConfigureIAMPolicy = 'tp.ui.discover.database.configure.iampolicy', - EC2InstanceSelection = 'tp.ui.discover.selectedEC2Instance', - EC2DeployEICE = 'tp.ui.discover.deployEICE', CreateApplicationServer = 'tp.ui.discover.createAppServer', - CreateNode = 'tp.ui.discover.createNode', CreateDiscoveryConfig = 'tp.ui.discover.createDiscoveryConfig', KubeEKSEnrollEvent = 'tp.ui.discover.kube.enroll.eks', PrincipalsConfigure = 'tp.ui.discover.principals.configure', @@ -241,7 +238,6 @@ export enum DiscoverServiceDeployType { export enum DiscoverDiscoveryConfigMethod { Unspecified = 'CONFIG_METHOD_UNSPECIFIED', AwsEc2Ssm = 'CONFIG_METHOD_AWS_EC2_SSM', - AwsEc2Eice = 'CONFIG_METHOD_AWS_EC2_EICE', AwsRdsEcs = 'CONFIG_METHOD_AWS_RDS_ECS', AwsEks = 'CONFIG_METHOD_AWS_EKS', }