diff --git a/api/client/client.go b/api/client/client.go index 2daddc81d9777..4306ab1a619b0 100644 --- a/api/client/client.go +++ b/api/client/client.go @@ -4835,6 +4835,18 @@ func (c *Client) GenerateAWSOIDCToken(ctx context.Context, integration string) ( return resp.GetToken(), nil } +// GenerateAzureOIDCToken generates a token to be used when executing an Azure OIDC Integration action. +func (c *Client) GenerateAzureOIDCToken(ctx context.Context, integration string) (string, error) { + resp, err := c.integrationsClient().GenerateAzureOIDCToken(ctx, &integrationpb.GenerateAzureOIDCTokenRequest{ + Integration: integration, + }) + if err != nil { + return "", trace.Wrap(err) + } + + return resp.GetToken(), nil +} + // PluginsClient returns an unadorned Plugins client, using the underlying // Auth gRPC connection. // Clients connecting to non-Enterprise clusters, or older Teleport versions, diff --git a/api/gen/proto/go/teleport/integration/v1/integration_service.pb.go b/api/gen/proto/go/teleport/integration/v1/integration_service.pb.go index caebbb68f43fd..510b0edf3d84d 100644 --- a/api/gen/proto/go/teleport/integration/v1/integration_service.pb.go +++ b/api/gen/proto/go/teleport/integration/v1/integration_service.pb.go @@ -495,6 +495,102 @@ func (x *GenerateAWSOIDCTokenResponse) GetToken() string { return "" } +// GenerateAzureOIDCTokenRequest are the parameters used to request an Azure OIDC +// Integration token. +type GenerateAzureOIDCTokenRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Integration is the Azure OIDC Integration name. + // Required. + Integration string `protobuf:"bytes,1,opt,name=integration,proto3" json:"integration,omitempty"` +} + +func (x *GenerateAzureOIDCTokenRequest) Reset() { + *x = GenerateAzureOIDCTokenRequest{} + mi := &file_teleport_integration_v1_integration_service_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GenerateAzureOIDCTokenRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GenerateAzureOIDCTokenRequest) ProtoMessage() {} + +func (x *GenerateAzureOIDCTokenRequest) ProtoReflect() protoreflect.Message { + mi := &file_teleport_integration_v1_integration_service_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GenerateAzureOIDCTokenRequest.ProtoReflect.Descriptor instead. +func (*GenerateAzureOIDCTokenRequest) Descriptor() ([]byte, []int) { + return file_teleport_integration_v1_integration_service_proto_rawDescGZIP(), []int{9} +} + +func (x *GenerateAzureOIDCTokenRequest) GetIntegration() string { + if x != nil { + return x.Integration + } + return "" +} + +// GenerateAzureOIDCTokenResponse contains a signed Azure OIDC Integration token. +type GenerateAzureOIDCTokenResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Token is the signed JWT ready to be used + Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` +} + +func (x *GenerateAzureOIDCTokenResponse) Reset() { + *x = GenerateAzureOIDCTokenResponse{} + mi := &file_teleport_integration_v1_integration_service_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GenerateAzureOIDCTokenResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GenerateAzureOIDCTokenResponse) ProtoMessage() {} + +func (x *GenerateAzureOIDCTokenResponse) ProtoReflect() protoreflect.Message { + mi := &file_teleport_integration_v1_integration_service_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GenerateAzureOIDCTokenResponse.ProtoReflect.Descriptor instead. +func (*GenerateAzureOIDCTokenResponse) Descriptor() ([]byte, []int) { + return file_teleport_integration_v1_integration_service_proto_rawDescGZIP(), []int{10} +} + +func (x *GenerateAzureOIDCTokenResponse) GetToken() string { + if x != nil { + return x.Token + } + return "" +} + // GenerateGitHubUserCertRequest is a request to sign a client certificate used by // GitHub integration to authenticate with GitHub enterprise. type GenerateGitHubUserCertRequest struct { @@ -516,7 +612,7 @@ type GenerateGitHubUserCertRequest struct { func (x *GenerateGitHubUserCertRequest) Reset() { *x = GenerateGitHubUserCertRequest{} - mi := &file_teleport_integration_v1_integration_service_proto_msgTypes[9] + mi := &file_teleport_integration_v1_integration_service_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -528,7 +624,7 @@ func (x *GenerateGitHubUserCertRequest) String() string { func (*GenerateGitHubUserCertRequest) ProtoMessage() {} func (x *GenerateGitHubUserCertRequest) ProtoReflect() protoreflect.Message { - mi := &file_teleport_integration_v1_integration_service_proto_msgTypes[9] + mi := &file_teleport_integration_v1_integration_service_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -541,7 +637,7 @@ func (x *GenerateGitHubUserCertRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GenerateGitHubUserCertRequest.ProtoReflect.Descriptor instead. func (*GenerateGitHubUserCertRequest) Descriptor() ([]byte, []int) { - return file_teleport_integration_v1_integration_service_proto_rawDescGZIP(), []int{9} + return file_teleport_integration_v1_integration_service_proto_rawDescGZIP(), []int{11} } func (x *GenerateGitHubUserCertRequest) GetIntegration() string { @@ -591,7 +687,7 @@ type GenerateGitHubUserCertResponse struct { func (x *GenerateGitHubUserCertResponse) Reset() { *x = GenerateGitHubUserCertResponse{} - mi := &file_teleport_integration_v1_integration_service_proto_msgTypes[10] + mi := &file_teleport_integration_v1_integration_service_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -603,7 +699,7 @@ func (x *GenerateGitHubUserCertResponse) String() string { func (*GenerateGitHubUserCertResponse) ProtoMessage() {} func (x *GenerateGitHubUserCertResponse) ProtoReflect() protoreflect.Message { - mi := &file_teleport_integration_v1_integration_service_proto_msgTypes[10] + mi := &file_teleport_integration_v1_integration_service_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -616,7 +712,7 @@ func (x *GenerateGitHubUserCertResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GenerateGitHubUserCertResponse.ProtoReflect.Descriptor instead. func (*GenerateGitHubUserCertResponse) Descriptor() ([]byte, []int) { - return file_teleport_integration_v1_integration_service_proto_rawDescGZIP(), []int{10} + return file_teleport_integration_v1_integration_service_proto_rawDescGZIP(), []int{12} } func (x *GenerateGitHubUserCertResponse) GetAuthorizedKey() []byte { @@ -639,7 +735,7 @@ type ExportIntegrationCertAuthoritiesRequest struct { func (x *ExportIntegrationCertAuthoritiesRequest) Reset() { *x = ExportIntegrationCertAuthoritiesRequest{} - mi := &file_teleport_integration_v1_integration_service_proto_msgTypes[11] + mi := &file_teleport_integration_v1_integration_service_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -651,7 +747,7 @@ func (x *ExportIntegrationCertAuthoritiesRequest) String() string { func (*ExportIntegrationCertAuthoritiesRequest) ProtoMessage() {} func (x *ExportIntegrationCertAuthoritiesRequest) ProtoReflect() protoreflect.Message { - mi := &file_teleport_integration_v1_integration_service_proto_msgTypes[11] + mi := &file_teleport_integration_v1_integration_service_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -664,7 +760,7 @@ func (x *ExportIntegrationCertAuthoritiesRequest) ProtoReflect() protoreflect.Me // Deprecated: Use ExportIntegrationCertAuthoritiesRequest.ProtoReflect.Descriptor instead. func (*ExportIntegrationCertAuthoritiesRequest) Descriptor() ([]byte, []int) { - return file_teleport_integration_v1_integration_service_proto_rawDescGZIP(), []int{11} + return file_teleport_integration_v1_integration_service_proto_rawDescGZIP(), []int{13} } func (x *ExportIntegrationCertAuthoritiesRequest) GetIntegration() string { @@ -687,7 +783,7 @@ type ExportIntegrationCertAuthoritiesResponse struct { func (x *ExportIntegrationCertAuthoritiesResponse) Reset() { *x = ExportIntegrationCertAuthoritiesResponse{} - mi := &file_teleport_integration_v1_integration_service_proto_msgTypes[12] + mi := &file_teleport_integration_v1_integration_service_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -699,7 +795,7 @@ func (x *ExportIntegrationCertAuthoritiesResponse) String() string { func (*ExportIntegrationCertAuthoritiesResponse) ProtoMessage() {} func (x *ExportIntegrationCertAuthoritiesResponse) ProtoReflect() protoreflect.Message { - mi := &file_teleport_integration_v1_integration_service_proto_msgTypes[12] + mi := &file_teleport_integration_v1_integration_service_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -712,7 +808,7 @@ func (x *ExportIntegrationCertAuthoritiesResponse) ProtoReflect() protoreflect.M // Deprecated: Use ExportIntegrationCertAuthoritiesResponse.ProtoReflect.Descriptor instead. func (*ExportIntegrationCertAuthoritiesResponse) Descriptor() ([]byte, []int) { - return file_teleport_integration_v1_integration_service_proto_rawDescGZIP(), []int{12} + return file_teleport_integration_v1_integration_service_proto_rawDescGZIP(), []int{14} } func (x *ExportIntegrationCertAuthoritiesResponse) GetCertAuthorities() *types.CAKeySet { @@ -777,107 +873,124 @@ var file_teleport_integration_v1_integration_service_proto_rawDesc = []byte{ 0x1c, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x41, 0x57, 0x53, 0x4f, 0x49, 0x44, 0x43, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, - 0x6b, 0x65, 0x6e, 0x22, 0xbd, 0x01, 0x0a, 0x1d, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, - 0x47, 0x69, 0x74, 0x48, 0x75, 0x62, 0x55, 0x73, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 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, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, - 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x75, 0x62, - 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 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, 0x12, - 0x15, 0x0a, 0x06, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x6b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x2b, 0x0a, 0x03, 0x74, 0x74, 0x6c, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x03, - 0x74, 0x74, 0x6c, 0x22, 0x47, 0x0a, 0x1e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x47, - 0x69, 0x74, 0x48, 0x75, 0x62, 0x55, 0x73, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, - 0x7a, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x61, - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x22, 0x4b, 0x0a, 0x27, - 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 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, 0x22, 0x66, 0x0a, 0x28, 0x45, 0x78, 0x70, - 0x6f, 0x72, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x65, - 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x10, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x61, 0x75, - 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x0f, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x43, 0x41, 0x4b, 0x65, 0x79, 0x53, 0x65, 0x74, - 0x52, 0x0f, 0x63, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, - 0x73, 0x32, 0xa5, 0x08, 0x0a, 0x12, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x77, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, - 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 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, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x67, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 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, 0x49, 0x6e, 0x74, - 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x56, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 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, 0x47, 0x65, - 0x74, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x49, 0x6e, 0x74, 0x65, - 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x31, 0x12, 0x5c, 0x0a, 0x11, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 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, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, - 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x14, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x31, 0x12, 0x5c, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 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, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x74, - 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x14, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x56, 0x31, 0x12, 0x5e, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, - 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 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, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x67, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x66, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, - 0x6c, 0x6c, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x35, + 0x6b, 0x65, 0x6e, 0x22, 0x41, 0x0a, 0x1d, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x41, + 0x7a, 0x75, 0x72, 0x65, 0x4f, 0x49, 0x44, 0x43, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 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, 0x22, 0x36, 0x0a, 0x1e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, + 0x74, 0x65, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x4f, 0x49, 0x44, 0x43, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, + 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xbd, + 0x01, 0x0a, 0x1d, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x47, 0x69, 0x74, 0x48, 0x75, + 0x62, 0x55, 0x73, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 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, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, + 0x79, 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, 0x12, 0x15, 0x0a, 0x06, 0x6b, 0x65, + 0x79, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6b, 0x65, 0x79, 0x49, + 0x64, 0x12, 0x2b, 0x0a, 0x03, 0x74, 0x74, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x03, 0x74, 0x74, 0x6c, 0x22, 0x47, + 0x0a, 0x1e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x47, 0x69, 0x74, 0x48, 0x75, 0x62, + 0x55, 0x73, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x7a, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x22, 0x4b, 0x0a, 0x27, 0x45, 0x78, 0x70, 0x6f, 0x72, + 0x74, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x65, 0x72, 0x74, + 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 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, 0x22, 0x66, 0x0a, 0x28, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x49, 0x6e, + 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x3a, 0x0a, 0x10, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x74, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x74, 0x79, 0x70, + 0x65, 0x73, 0x2e, 0x43, 0x41, 0x4b, 0x65, 0x79, 0x53, 0x65, 0x74, 0x52, 0x0f, 0x63, 0x65, 0x72, + 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x32, 0xb1, 0x09, 0x0a, + 0x12, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x12, 0x77, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x67, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 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, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 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, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x0e, + 0x47, 0x65, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 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, 0x6c, 0x65, 0x74, 0x65, 0x41, - 0x6c, 0x6c, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x83, 0x01, - 0x0a, 0x14, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x41, 0x57, 0x53, 0x4f, 0x49, 0x44, - 0x43, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x34, 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, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x41, 0x57, 0x53, 0x4f, 0x49, 0x44, 0x43, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 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, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x41, - 0x57, 0x53, 0x4f, 0x49, 0x44, 0x43, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x89, 0x01, 0x0a, 0x16, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, - 0x47, 0x69, 0x74, 0x48, 0x75, 0x62, 0x55, 0x73, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x12, 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, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, - 0x65, 0x47, 0x69, 0x74, 0x48, 0x75, 0x62, 0x55, 0x73, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x37, 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, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x47, 0x69, 0x74, 0x48, 0x75, 0x62, 0x55, - 0x73, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0xa7, 0x01, 0x0a, 0x20, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, - 0x74, 0x69, 0x65, 0x73, 0x12, 0x40, 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, - 0x78, 0x70, 0x6f, 0x72, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x41, 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, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x5a, 0x5a, 0x58, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x61, - 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, - 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x3b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x74, 0x65, + 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, + 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x56, 0x31, 0x12, 0x5c, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x6e, + 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 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, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x74, + 0x79, 0x70, 0x65, 0x73, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x56, 0x31, 0x12, 0x5c, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x74, 0x65, + 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 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, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x74, 0x79, 0x70, + 0x65, 0x73, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x31, + 0x12, 0x5e, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 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, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x12, 0x66, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, 0x6c, 0x49, 0x6e, 0x74, + 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 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, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, 0x6c, 0x49, 0x6e, 0x74, + 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x83, 0x01, 0x0a, 0x14, 0x47, 0x65, 0x6e, + 0x65, 0x72, 0x61, 0x74, 0x65, 0x41, 0x57, 0x53, 0x4f, 0x49, 0x44, 0x43, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x12, 0x34, 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, 0x47, 0x65, 0x6e, 0x65, + 0x72, 0x61, 0x74, 0x65, 0x41, 0x57, 0x53, 0x4f, 0x49, 0x44, 0x43, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 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, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x41, 0x57, 0x53, 0x4f, 0x49, 0x44, + 0x43, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x89, + 0x01, 0x0a, 0x16, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x41, 0x7a, 0x75, 0x72, 0x65, + 0x4f, 0x49, 0x44, 0x43, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 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, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x41, 0x7a, 0x75, 0x72, + 0x65, 0x4f, 0x49, 0x44, 0x43, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x37, 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, 0x47, 0x65, 0x6e, 0x65, + 0x72, 0x61, 0x74, 0x65, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x4f, 0x49, 0x44, 0x43, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x89, 0x01, 0x0a, 0x16, 0x47, + 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x47, 0x69, 0x74, 0x48, 0x75, 0x62, 0x55, 0x73, 0x65, + 0x72, 0x43, 0x65, 0x72, 0x74, 0x12, 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, + 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x47, 0x69, 0x74, 0x48, 0x75, 0x62, 0x55, 0x73, + 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x37, 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, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, + 0x47, 0x69, 0x74, 0x48, 0x75, 0x62, 0x55, 0x73, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xa7, 0x01, 0x0a, 0x20, 0x45, 0x78, 0x70, 0x6f, 0x72, + 0x74, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x65, 0x72, 0x74, + 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x12, 0x40, 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, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x49, 0x6e, 0x74, 0x65, + 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x41, 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, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x49, 0x6e, + 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x42, 0x5a, 0x5a, 0x58, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, + 0x72, 0x61, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, + 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x3b, 0x69, + 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -892,7 +1005,7 @@ func file_teleport_integration_v1_integration_service_proto_rawDescGZIP() []byte return file_teleport_integration_v1_integration_service_proto_rawDescData } -var file_teleport_integration_v1_integration_service_proto_msgTypes = make([]protoimpl.MessageInfo, 13) +var file_teleport_integration_v1_integration_service_proto_msgTypes = make([]protoimpl.MessageInfo, 15) var file_teleport_integration_v1_integration_service_proto_goTypes = []any{ (*ListIntegrationsRequest)(nil), // 0: teleport.integration.v1.ListIntegrationsRequest (*ListIntegrationsResponse)(nil), // 1: teleport.integration.v1.ListIntegrationsResponse @@ -903,21 +1016,23 @@ var file_teleport_integration_v1_integration_service_proto_goTypes = []any{ (*DeleteAllIntegrationsRequest)(nil), // 6: teleport.integration.v1.DeleteAllIntegrationsRequest (*GenerateAWSOIDCTokenRequest)(nil), // 7: teleport.integration.v1.GenerateAWSOIDCTokenRequest (*GenerateAWSOIDCTokenResponse)(nil), // 8: teleport.integration.v1.GenerateAWSOIDCTokenResponse - (*GenerateGitHubUserCertRequest)(nil), // 9: teleport.integration.v1.GenerateGitHubUserCertRequest - (*GenerateGitHubUserCertResponse)(nil), // 10: teleport.integration.v1.GenerateGitHubUserCertResponse - (*ExportIntegrationCertAuthoritiesRequest)(nil), // 11: teleport.integration.v1.ExportIntegrationCertAuthoritiesRequest - (*ExportIntegrationCertAuthoritiesResponse)(nil), // 12: teleport.integration.v1.ExportIntegrationCertAuthoritiesResponse - (*types.IntegrationV1)(nil), // 13: types.IntegrationV1 - (*durationpb.Duration)(nil), // 14: google.protobuf.Duration - (*types.CAKeySet)(nil), // 15: types.CAKeySet - (*emptypb.Empty)(nil), // 16: google.protobuf.Empty + (*GenerateAzureOIDCTokenRequest)(nil), // 9: teleport.integration.v1.GenerateAzureOIDCTokenRequest + (*GenerateAzureOIDCTokenResponse)(nil), // 10: teleport.integration.v1.GenerateAzureOIDCTokenResponse + (*GenerateGitHubUserCertRequest)(nil), // 11: teleport.integration.v1.GenerateGitHubUserCertRequest + (*GenerateGitHubUserCertResponse)(nil), // 12: teleport.integration.v1.GenerateGitHubUserCertResponse + (*ExportIntegrationCertAuthoritiesRequest)(nil), // 13: teleport.integration.v1.ExportIntegrationCertAuthoritiesRequest + (*ExportIntegrationCertAuthoritiesResponse)(nil), // 14: teleport.integration.v1.ExportIntegrationCertAuthoritiesResponse + (*types.IntegrationV1)(nil), // 15: types.IntegrationV1 + (*durationpb.Duration)(nil), // 16: google.protobuf.Duration + (*types.CAKeySet)(nil), // 17: types.CAKeySet + (*emptypb.Empty)(nil), // 18: google.protobuf.Empty } var file_teleport_integration_v1_integration_service_proto_depIdxs = []int32{ - 13, // 0: teleport.integration.v1.ListIntegrationsResponse.integrations:type_name -> types.IntegrationV1 - 13, // 1: teleport.integration.v1.CreateIntegrationRequest.integration:type_name -> types.IntegrationV1 - 13, // 2: teleport.integration.v1.UpdateIntegrationRequest.integration:type_name -> types.IntegrationV1 - 14, // 3: teleport.integration.v1.GenerateGitHubUserCertRequest.ttl:type_name -> google.protobuf.Duration - 15, // 4: teleport.integration.v1.ExportIntegrationCertAuthoritiesResponse.cert_authorities:type_name -> types.CAKeySet + 15, // 0: teleport.integration.v1.ListIntegrationsResponse.integrations:type_name -> types.IntegrationV1 + 15, // 1: teleport.integration.v1.CreateIntegrationRequest.integration:type_name -> types.IntegrationV1 + 15, // 2: teleport.integration.v1.UpdateIntegrationRequest.integration:type_name -> types.IntegrationV1 + 16, // 3: teleport.integration.v1.GenerateGitHubUserCertRequest.ttl:type_name -> google.protobuf.Duration + 17, // 4: teleport.integration.v1.ExportIntegrationCertAuthoritiesResponse.cert_authorities:type_name -> types.CAKeySet 0, // 5: teleport.integration.v1.IntegrationService.ListIntegrations:input_type -> teleport.integration.v1.ListIntegrationsRequest 2, // 6: teleport.integration.v1.IntegrationService.GetIntegration:input_type -> teleport.integration.v1.GetIntegrationRequest 3, // 7: teleport.integration.v1.IntegrationService.CreateIntegration:input_type -> teleport.integration.v1.CreateIntegrationRequest @@ -925,19 +1040,21 @@ var file_teleport_integration_v1_integration_service_proto_depIdxs = []int32{ 5, // 9: teleport.integration.v1.IntegrationService.DeleteIntegration:input_type -> teleport.integration.v1.DeleteIntegrationRequest 6, // 10: teleport.integration.v1.IntegrationService.DeleteAllIntegrations:input_type -> teleport.integration.v1.DeleteAllIntegrationsRequest 7, // 11: teleport.integration.v1.IntegrationService.GenerateAWSOIDCToken:input_type -> teleport.integration.v1.GenerateAWSOIDCTokenRequest - 9, // 12: teleport.integration.v1.IntegrationService.GenerateGitHubUserCert:input_type -> teleport.integration.v1.GenerateGitHubUserCertRequest - 11, // 13: teleport.integration.v1.IntegrationService.ExportIntegrationCertAuthorities:input_type -> teleport.integration.v1.ExportIntegrationCertAuthoritiesRequest - 1, // 14: teleport.integration.v1.IntegrationService.ListIntegrations:output_type -> teleport.integration.v1.ListIntegrationsResponse - 13, // 15: teleport.integration.v1.IntegrationService.GetIntegration:output_type -> types.IntegrationV1 - 13, // 16: teleport.integration.v1.IntegrationService.CreateIntegration:output_type -> types.IntegrationV1 - 13, // 17: teleport.integration.v1.IntegrationService.UpdateIntegration:output_type -> types.IntegrationV1 - 16, // 18: teleport.integration.v1.IntegrationService.DeleteIntegration:output_type -> google.protobuf.Empty - 16, // 19: teleport.integration.v1.IntegrationService.DeleteAllIntegrations:output_type -> google.protobuf.Empty - 8, // 20: teleport.integration.v1.IntegrationService.GenerateAWSOIDCToken:output_type -> teleport.integration.v1.GenerateAWSOIDCTokenResponse - 10, // 21: teleport.integration.v1.IntegrationService.GenerateGitHubUserCert:output_type -> teleport.integration.v1.GenerateGitHubUserCertResponse - 12, // 22: teleport.integration.v1.IntegrationService.ExportIntegrationCertAuthorities:output_type -> teleport.integration.v1.ExportIntegrationCertAuthoritiesResponse - 14, // [14:23] is the sub-list for method output_type - 5, // [5:14] is the sub-list for method input_type + 9, // 12: teleport.integration.v1.IntegrationService.GenerateAzureOIDCToken:input_type -> teleport.integration.v1.GenerateAzureOIDCTokenRequest + 11, // 13: teleport.integration.v1.IntegrationService.GenerateGitHubUserCert:input_type -> teleport.integration.v1.GenerateGitHubUserCertRequest + 13, // 14: teleport.integration.v1.IntegrationService.ExportIntegrationCertAuthorities:input_type -> teleport.integration.v1.ExportIntegrationCertAuthoritiesRequest + 1, // 15: teleport.integration.v1.IntegrationService.ListIntegrations:output_type -> teleport.integration.v1.ListIntegrationsResponse + 15, // 16: teleport.integration.v1.IntegrationService.GetIntegration:output_type -> types.IntegrationV1 + 15, // 17: teleport.integration.v1.IntegrationService.CreateIntegration:output_type -> types.IntegrationV1 + 15, // 18: teleport.integration.v1.IntegrationService.UpdateIntegration:output_type -> types.IntegrationV1 + 18, // 19: teleport.integration.v1.IntegrationService.DeleteIntegration:output_type -> google.protobuf.Empty + 18, // 20: teleport.integration.v1.IntegrationService.DeleteAllIntegrations:output_type -> google.protobuf.Empty + 8, // 21: teleport.integration.v1.IntegrationService.GenerateAWSOIDCToken:output_type -> teleport.integration.v1.GenerateAWSOIDCTokenResponse + 10, // 22: teleport.integration.v1.IntegrationService.GenerateAzureOIDCToken:output_type -> teleport.integration.v1.GenerateAzureOIDCTokenResponse + 12, // 23: teleport.integration.v1.IntegrationService.GenerateGitHubUserCert:output_type -> teleport.integration.v1.GenerateGitHubUserCertResponse + 14, // 24: teleport.integration.v1.IntegrationService.ExportIntegrationCertAuthorities:output_type -> teleport.integration.v1.ExportIntegrationCertAuthoritiesResponse + 15, // [15:25] is the sub-list for method output_type + 5, // [5:15] is the sub-list for method input_type 5, // [5:5] is the sub-list for extension type_name 5, // [5:5] is the sub-list for extension extendee 0, // [0:5] is the sub-list for field type_name @@ -954,7 +1071,7 @@ func file_teleport_integration_v1_integration_service_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_teleport_integration_v1_integration_service_proto_rawDesc, NumEnums: 0, - NumMessages: 13, + NumMessages: 15, NumExtensions: 0, NumServices: 1, }, diff --git a/api/gen/proto/go/teleport/integration/v1/integration_service_grpc.pb.go b/api/gen/proto/go/teleport/integration/v1/integration_service_grpc.pb.go index e003922829236..7dfadc9f20be6 100644 --- a/api/gen/proto/go/teleport/integration/v1/integration_service_grpc.pb.go +++ b/api/gen/proto/go/teleport/integration/v1/integration_service_grpc.pb.go @@ -42,6 +42,7 @@ const ( IntegrationService_DeleteIntegration_FullMethodName = "/teleport.integration.v1.IntegrationService/DeleteIntegration" IntegrationService_DeleteAllIntegrations_FullMethodName = "/teleport.integration.v1.IntegrationService/DeleteAllIntegrations" IntegrationService_GenerateAWSOIDCToken_FullMethodName = "/teleport.integration.v1.IntegrationService/GenerateAWSOIDCToken" + IntegrationService_GenerateAzureOIDCToken_FullMethodName = "/teleport.integration.v1.IntegrationService/GenerateAzureOIDCToken" IntegrationService_GenerateGitHubUserCert_FullMethodName = "/teleport.integration.v1.IntegrationService/GenerateGitHubUserCert" IntegrationService_ExportIntegrationCertAuthorities_FullMethodName = "/teleport.integration.v1.IntegrationService/ExportIntegrationCertAuthorities" ) @@ -67,6 +68,8 @@ type IntegrationServiceClient interface { DeleteAllIntegrations(ctx context.Context, in *DeleteAllIntegrationsRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) // GenerateAWSOIDCToken generates a token to be used when executing an AWS OIDC Integration action. GenerateAWSOIDCToken(ctx context.Context, in *GenerateAWSOIDCTokenRequest, opts ...grpc.CallOption) (*GenerateAWSOIDCTokenResponse, error) + // GenerateAzureOIDCToken generates a token to be used when executing an Azure OIDC Integration action. + GenerateAzureOIDCToken(ctx context.Context, in *GenerateAzureOIDCTokenRequest, opts ...grpc.CallOption) (*GenerateAzureOIDCTokenResponse, error) // GenerateGitHubUserCert signs a SSH certificate for GitHub integration. GenerateGitHubUserCert(ctx context.Context, in *GenerateGitHubUserCertRequest, opts ...grpc.CallOption) (*GenerateGitHubUserCertResponse, error) // ExportIntegrationCertAuthorities exports cert authorities for an integration. @@ -151,6 +154,16 @@ func (c *integrationServiceClient) GenerateAWSOIDCToken(ctx context.Context, in return out, nil } +func (c *integrationServiceClient) GenerateAzureOIDCToken(ctx context.Context, in *GenerateAzureOIDCTokenRequest, opts ...grpc.CallOption) (*GenerateAzureOIDCTokenResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GenerateAzureOIDCTokenResponse) + err := c.cc.Invoke(ctx, IntegrationService_GenerateAzureOIDCToken_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *integrationServiceClient) GenerateGitHubUserCert(ctx context.Context, in *GenerateGitHubUserCertRequest, opts ...grpc.CallOption) (*GenerateGitHubUserCertResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GenerateGitHubUserCertResponse) @@ -192,6 +205,8 @@ type IntegrationServiceServer interface { DeleteAllIntegrations(context.Context, *DeleteAllIntegrationsRequest) (*emptypb.Empty, error) // GenerateAWSOIDCToken generates a token to be used when executing an AWS OIDC Integration action. GenerateAWSOIDCToken(context.Context, *GenerateAWSOIDCTokenRequest) (*GenerateAWSOIDCTokenResponse, error) + // GenerateAzureOIDCToken generates a token to be used when executing an Azure OIDC Integration action. + GenerateAzureOIDCToken(context.Context, *GenerateAzureOIDCTokenRequest) (*GenerateAzureOIDCTokenResponse, error) // GenerateGitHubUserCert signs a SSH certificate for GitHub integration. GenerateGitHubUserCert(context.Context, *GenerateGitHubUserCertRequest) (*GenerateGitHubUserCertResponse, error) // ExportIntegrationCertAuthorities exports cert authorities for an integration. @@ -227,6 +242,9 @@ func (UnimplementedIntegrationServiceServer) DeleteAllIntegrations(context.Conte func (UnimplementedIntegrationServiceServer) GenerateAWSOIDCToken(context.Context, *GenerateAWSOIDCTokenRequest) (*GenerateAWSOIDCTokenResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GenerateAWSOIDCToken not implemented") } +func (UnimplementedIntegrationServiceServer) GenerateAzureOIDCToken(context.Context, *GenerateAzureOIDCTokenRequest) (*GenerateAzureOIDCTokenResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GenerateAzureOIDCToken not implemented") +} func (UnimplementedIntegrationServiceServer) GenerateGitHubUserCert(context.Context, *GenerateGitHubUserCertRequest) (*GenerateGitHubUserCertResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GenerateGitHubUserCert not implemented") } @@ -380,6 +398,24 @@ func _IntegrationService_GenerateAWSOIDCToken_Handler(srv interface{}, ctx conte return interceptor(ctx, in, info, handler) } +func _IntegrationService_GenerateAzureOIDCToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GenerateAzureOIDCTokenRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IntegrationServiceServer).GenerateAzureOIDCToken(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: IntegrationService_GenerateAzureOIDCToken_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IntegrationServiceServer).GenerateAzureOIDCToken(ctx, req.(*GenerateAzureOIDCTokenRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _IntegrationService_GenerateGitHubUserCert_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(GenerateGitHubUserCertRequest) if err := dec(in); err != nil { @@ -451,6 +487,10 @@ var IntegrationService_ServiceDesc = grpc.ServiceDesc{ MethodName: "GenerateAWSOIDCToken", Handler: _IntegrationService_GenerateAWSOIDCToken_Handler, }, + { + MethodName: "GenerateAzureOIDCToken", + Handler: _IntegrationService_GenerateAzureOIDCToken_Handler, + }, { MethodName: "GenerateGitHubUserCert", Handler: _IntegrationService_GenerateGitHubUserCert_Handler, diff --git a/api/proto/teleport/integration/v1/integration_service.proto b/api/proto/teleport/integration/v1/integration_service.proto index 0528f521f684e..8eb0875f6443b 100644 --- a/api/proto/teleport/integration/v1/integration_service.proto +++ b/api/proto/teleport/integration/v1/integration_service.proto @@ -46,6 +46,9 @@ service IntegrationService { // GenerateAWSOIDCToken generates a token to be used when executing an AWS OIDC Integration action. rpc GenerateAWSOIDCToken(GenerateAWSOIDCTokenRequest) returns (GenerateAWSOIDCTokenResponse); + // GenerateAzureOIDCToken generates a token to be used when executing an Azure OIDC Integration action. + rpc GenerateAzureOIDCToken(GenerateAzureOIDCTokenRequest) returns (GenerateAzureOIDCTokenResponse); + // GenerateGitHubUserCert signs a SSH certificate for GitHub integration. rpc GenerateGitHubUserCert(GenerateGitHubUserCertRequest) returns (GenerateGitHubUserCertResponse); @@ -119,6 +122,20 @@ message GenerateAWSOIDCTokenResponse { string token = 1; } +// GenerateAzureOIDCTokenRequest are the parameters used to request an Azure OIDC +// Integration token. +message GenerateAzureOIDCTokenRequest { + // Integration is the Azure OIDC Integration name. + // Required. + string integration = 1; +} + +// GenerateAzureOIDCTokenResponse contains a signed Azure OIDC Integration token. +message GenerateAzureOIDCTokenResponse { + // Token is the signed JWT ready to be used + string token = 1; +} + // GenerateGitHubUserCertRequest is a request to sign a client certificate used by // GitHub integration to authenticate with GitHub enterprise. message GenerateGitHubUserCertRequest { diff --git a/api/proto/teleport/legacy/types/types.proto b/api/proto/teleport/legacy/types/types.proto index 746845cd0894d..3d5beb6c55ba5 100644 --- a/api/proto/teleport/legacy/types/types.proto +++ b/api/proto/teleport/legacy/types/types.proto @@ -8109,12 +8109,14 @@ message OktaOptions { message AccessGraphSync { // AWS is a configuration for AWS Access Graph service poll service. repeated AccessGraphAWSSync AWS = 1 [(gogoproto.jsontag) = "aws,omitempty"]; - // PollInterval is the frequency at which to poll for AWS resources + // PollInterval is the frequency at which to poll for resources google.protobuf.Duration PollInterval = 2 [ (gogoproto.jsontag) = "poll_interval,omitempty", (gogoproto.nullable) = false, (gogoproto.stdduration) = true ]; + // Azure is a configuration for Azure Access Graph service poll service. + repeated AccessGraphAzureSync Azure = 3 [(gogoproto.jsontag) = "azure,omitempty"]; } // AccessGraphAWSSync is a configuration for AWS Access Graph service poll service. @@ -8126,3 +8128,11 @@ message AccessGraphAWSSync { // Integration is the integration name used to generate credentials to interact with AWS APIs. string Integration = 4 [(gogoproto.jsontag) = "integration,omitempty"]; } + +// AccessGraphAzureSync is a configuration for Azure Access Graph service poll service. +message AccessGraphAzureSync { + // SubscriptionID Is the ID of the Azure subscription to sync resources from + string SubscriptionID = 1 [(gogoproto.jsontag) = "subscription_id,omitempty"]; + // Integration is the integration name used to generate credentials to interact with AWS APIs. + string Integration = 2 [(gogoproto.jsontag) = "integration,omitempty"]; +} diff --git a/api/types/discoveryconfig/derived.gen.go b/api/types/discoveryconfig/derived.gen.go index 9053fdd312473..c1f713517c7ca 100644 --- a/api/types/discoveryconfig/derived.gen.go +++ b/api/types/discoveryconfig/derived.gen.go @@ -117,7 +117,8 @@ func deriveTeleportEqual_6(this, that *types.AccessGraphSync) bool { return (this == nil && that == nil) || this != nil && that != nil && deriveTeleportEqual_12(this.AWS, that.AWS) && - this.PollInterval == that.PollInterval + this.PollInterval == that.PollInterval && + deriveTeleportEqual_13(this.Azure, that.Azure) } // deriveTeleportEqual_7 returns whether this and that are equal. @@ -144,12 +145,12 @@ func deriveTeleportEqual_7(this, that map[string]string) bool { func deriveTeleportEqual_8(this, that *types.AWSMatcher) bool { return (this == nil && that == nil) || this != nil && that != nil && - deriveTeleportEqual_13(this.Types, that.Types) && - deriveTeleportEqual_13(this.Regions, that.Regions) && - deriveTeleportEqual_14(this.AssumeRole, that.AssumeRole) && - deriveTeleportEqual_15(this.Tags, that.Tags) && - deriveTeleportEqual_16(this.Params, that.Params) && - deriveTeleportEqual_17(this.SSM, that.SSM) && + deriveTeleportEqual_14(this.Types, that.Types) && + deriveTeleportEqual_14(this.Regions, that.Regions) && + deriveTeleportEqual_15(this.AssumeRole, that.AssumeRole) && + deriveTeleportEqual_16(this.Tags, that.Tags) && + deriveTeleportEqual_17(this.Params, that.Params) && + deriveTeleportEqual_18(this.SSM, that.SSM) && this.Integration == that.Integration && this.KubeAppDiscovery == that.KubeAppDiscovery && this.SetupAccessForARN == that.SetupAccessForARN @@ -159,34 +160,34 @@ func deriveTeleportEqual_8(this, that *types.AWSMatcher) bool { func deriveTeleportEqual_9(this, that *types.AzureMatcher) bool { return (this == nil && that == nil) || this != nil && that != nil && - deriveTeleportEqual_13(this.Subscriptions, that.Subscriptions) && - deriveTeleportEqual_13(this.ResourceGroups, that.ResourceGroups) && - deriveTeleportEqual_13(this.Types, that.Types) && - deriveTeleportEqual_13(this.Regions, that.Regions) && - deriveTeleportEqual_15(this.ResourceTags, that.ResourceTags) && - deriveTeleportEqual_16(this.Params, that.Params) + deriveTeleportEqual_14(this.Subscriptions, that.Subscriptions) && + deriveTeleportEqual_14(this.ResourceGroups, that.ResourceGroups) && + deriveTeleportEqual_14(this.Types, that.Types) && + deriveTeleportEqual_14(this.Regions, that.Regions) && + deriveTeleportEqual_16(this.ResourceTags, that.ResourceTags) && + deriveTeleportEqual_17(this.Params, that.Params) } // deriveTeleportEqual_10 returns whether this and that are equal. func deriveTeleportEqual_10(this, that *types.GCPMatcher) bool { return (this == nil && that == nil) || this != nil && that != nil && - deriveTeleportEqual_13(this.Types, that.Types) && - deriveTeleportEqual_13(this.Locations, that.Locations) && - deriveTeleportEqual_15(this.Tags, that.Tags) && - deriveTeleportEqual_13(this.ProjectIDs, that.ProjectIDs) && - deriveTeleportEqual_13(this.ServiceAccounts, that.ServiceAccounts) && - deriveTeleportEqual_16(this.Params, that.Params) && - deriveTeleportEqual_15(this.Labels, that.Labels) + deriveTeleportEqual_14(this.Types, that.Types) && + deriveTeleportEqual_14(this.Locations, that.Locations) && + deriveTeleportEqual_16(this.Tags, that.Tags) && + deriveTeleportEqual_14(this.ProjectIDs, that.ProjectIDs) && + deriveTeleportEqual_14(this.ServiceAccounts, that.ServiceAccounts) && + deriveTeleportEqual_17(this.Params, that.Params) && + deriveTeleportEqual_16(this.Labels, that.Labels) } // deriveTeleportEqual_11 returns whether this and that are equal. func deriveTeleportEqual_11(this, that *types.KubernetesMatcher) bool { return (this == nil && that == nil) || this != nil && that != nil && - deriveTeleportEqual_13(this.Types, that.Types) && - deriveTeleportEqual_13(this.Namespaces, that.Namespaces) && - deriveTeleportEqual_15(this.Labels, that.Labels) + deriveTeleportEqual_14(this.Types, that.Types) && + deriveTeleportEqual_14(this.Namespaces, that.Namespaces) && + deriveTeleportEqual_16(this.Labels, that.Labels) } // deriveTeleportEqual_12 returns whether this and that are equal. @@ -198,7 +199,7 @@ func deriveTeleportEqual_12(this, that []*types.AccessGraphAWSSync) bool { return false } for i := 0; i < len(this); i++ { - if !(deriveTeleportEqual_18(this[i], that[i])) { + if !(deriveTeleportEqual_19(this[i], that[i])) { return false } } @@ -206,7 +207,7 @@ func deriveTeleportEqual_12(this, that []*types.AccessGraphAWSSync) bool { } // deriveTeleportEqual_13 returns whether this and that are equal. -func deriveTeleportEqual_13(this, that []string) bool { +func deriveTeleportEqual_13(this, that []*types.AccessGraphAzureSync) bool { if this == nil || that == nil { return this == nil && that == nil } @@ -214,7 +215,7 @@ func deriveTeleportEqual_13(this, that []string) bool { return false } for i := 0; i < len(this); i++ { - if !(this[i] == that[i]) { + if !(deriveTeleportEqual_20(this[i], that[i])) { return false } } @@ -222,15 +223,31 @@ func deriveTeleportEqual_13(this, that []string) bool { } // deriveTeleportEqual_14 returns whether this and that are equal. -func deriveTeleportEqual_14(this, that *types.AssumeRole) bool { +func deriveTeleportEqual_14(this, that []string) bool { + if this == nil || that == nil { + return this == nil && that == nil + } + if len(this) != len(that) { + return false + } + for i := 0; i < len(this); i++ { + if !(this[i] == that[i]) { + return false + } + } + return true +} + +// deriveTeleportEqual_15 returns whether this and that are equal. +func deriveTeleportEqual_15(this, that *types.AssumeRole) bool { return (this == nil && that == nil) || this != nil && that != nil && this.RoleARN == that.RoleARN && this.ExternalID == that.ExternalID } -// deriveTeleportEqual_15 returns whether this and that are equal. -func deriveTeleportEqual_15(this, that map[string]utils.Strings) bool { +// deriveTeleportEqual_16 returns whether this and that are equal. +func deriveTeleportEqual_16(this, that map[string]utils.Strings) bool { if this == nil || that == nil { return this == nil && that == nil } @@ -242,15 +259,15 @@ func deriveTeleportEqual_15(this, that map[string]utils.Strings) bool { if !ok { return false } - if !(deriveTeleportEqual_13(v, thatv)) { + if !(deriveTeleportEqual_14(v, thatv)) { return false } } return true } -// deriveTeleportEqual_16 returns whether this and that are equal. -func deriveTeleportEqual_16(this, that *types.InstallerParams) bool { +// deriveTeleportEqual_17 returns whether this and that are equal. +func deriveTeleportEqual_17(this, that *types.InstallerParams) bool { return (this == nil && that == nil) || this != nil && that != nil && this.JoinMethod == that.JoinMethod && @@ -259,28 +276,36 @@ func deriveTeleportEqual_16(this, that *types.InstallerParams) bool { this.InstallTeleport == that.InstallTeleport && this.SSHDConfig == that.SSHDConfig && this.PublicProxyAddr == that.PublicProxyAddr && - deriveTeleportEqual_19(this.Azure, that.Azure) && + deriveTeleportEqual_21(this.Azure, that.Azure) && this.EnrollMode == that.EnrollMode } -// deriveTeleportEqual_17 returns whether this and that are equal. -func deriveTeleportEqual_17(this, that *types.AWSSSM) bool { +// deriveTeleportEqual_18 returns whether this and that are equal. +func deriveTeleportEqual_18(this, that *types.AWSSSM) bool { return (this == nil && that == nil) || this != nil && that != nil && this.DocumentName == that.DocumentName } -// deriveTeleportEqual_18 returns whether this and that are equal. -func deriveTeleportEqual_18(this, that *types.AccessGraphAWSSync) bool { +// deriveTeleportEqual_19 returns whether this and that are equal. +func deriveTeleportEqual_19(this, that *types.AccessGraphAWSSync) bool { return (this == nil && that == nil) || this != nil && that != nil && - deriveTeleportEqual_13(this.Regions, that.Regions) && - deriveTeleportEqual_14(this.AssumeRole, that.AssumeRole) && + deriveTeleportEqual_14(this.Regions, that.Regions) && + deriveTeleportEqual_15(this.AssumeRole, that.AssumeRole) && this.Integration == that.Integration } -// deriveTeleportEqual_19 returns whether this and that are equal. -func deriveTeleportEqual_19(this, that *types.AzureInstallerParams) bool { +// deriveTeleportEqual_20 returns whether this and that are equal. +func deriveTeleportEqual_20(this, that *types.AccessGraphAzureSync) bool { + return (this == nil && that == nil) || + this != nil && that != nil && + this.SubscriptionID == that.SubscriptionID && + this.Integration == that.Integration +} + +// deriveTeleportEqual_21 returns whether this and that are equal. +func deriveTeleportEqual_21(this, that *types.AzureInstallerParams) bool { return (this == nil && that == nil) || this != nil && that != nil && this.ClientID == that.ClientID diff --git a/api/types/types.pb.go b/api/types/types.pb.go index 7b03abac7468c..f6e9899167df9 100644 --- a/api/types/types.pb.go +++ b/api/types/types.pb.go @@ -21657,11 +21657,13 @@ var xxx_messageInfo_OktaOptions proto.InternalMessageInfo type AccessGraphSync struct { // AWS is a configuration for AWS Access Graph service poll service. AWS []*AccessGraphAWSSync `protobuf:"bytes,1,rep,name=AWS,proto3" json:"aws,omitempty"` - // PollInterval is the frequency at which to poll for AWS resources - PollInterval time.Duration `protobuf:"bytes,2,opt,name=PollInterval,proto3,stdduration" json:"poll_interval,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + // PollInterval is the frequency at which to poll for resources + PollInterval time.Duration `protobuf:"bytes,2,opt,name=PollInterval,proto3,stdduration" json:"poll_interval,omitempty"` + // Azure is a configuration for Azure Access Graph service poll service. + Azure []*AccessGraphAzureSync `protobuf:"bytes,3,rep,name=Azure,proto3" json:"azure,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *AccessGraphSync) Reset() { *m = AccessGraphSync{} } @@ -21743,6 +21745,50 @@ func (m *AccessGraphAWSSync) XXX_DiscardUnknown() { var xxx_messageInfo_AccessGraphAWSSync proto.InternalMessageInfo +// AccessGraphAzureSync is a configuration for Azure Access Graph service poll service. +type AccessGraphAzureSync struct { + // SubscriptionID Is the ID of the Azure subscription to sync resources from + SubscriptionID string `protobuf:"bytes,1,opt,name=SubscriptionID,proto3" json:"subscription_id,omitempty"` + // Integration is the integration name used to generate credentials to interact with AWS APIs. + Integration string `protobuf:"bytes,2,opt,name=Integration,proto3" json:"integration,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AccessGraphAzureSync) Reset() { *m = AccessGraphAzureSync{} } +func (m *AccessGraphAzureSync) String() string { return proto.CompactTextString(m) } +func (*AccessGraphAzureSync) ProtoMessage() {} +func (*AccessGraphAzureSync) Descriptor() ([]byte, []int) { + return fileDescriptor_9198ee693835762e, []int{375} +} +func (m *AccessGraphAzureSync) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AccessGraphAzureSync) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AccessGraphAzureSync.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *AccessGraphAzureSync) XXX_Merge(src proto.Message) { + xxx_messageInfo_AccessGraphAzureSync.Merge(m, src) +} +func (m *AccessGraphAzureSync) XXX_Size() int { + return m.Size() +} +func (m *AccessGraphAzureSync) XXX_DiscardUnknown() { + xxx_messageInfo_AccessGraphAzureSync.DiscardUnknown(m) +} + +var xxx_messageInfo_AccessGraphAzureSync proto.InternalMessageInfo + func init() { proto.RegisterEnum("types.IAMPolicyStatus", IAMPolicyStatus_name, IAMPolicyStatus_value) proto.RegisterEnum("types.DatabaseTLSMode", DatabaseTLSMode_name, DatabaseTLSMode_value) @@ -22185,12 +22231,13 @@ func init() { proto.RegisterType((*OktaOptions)(nil), "types.OktaOptions") proto.RegisterType((*AccessGraphSync)(nil), "types.AccessGraphSync") proto.RegisterType((*AccessGraphAWSSync)(nil), "types.AccessGraphAWSSync") + proto.RegisterType((*AccessGraphAzureSync)(nil), "types.AccessGraphAzureSync") } func init() { proto.RegisterFile("teleport/legacy/types/types.proto", fileDescriptor_9198ee693835762e) } var fileDescriptor_9198ee693835762e = []byte{ - // 30601 bytes of a gzipped FileDescriptorProto + // 30646 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0xfd, 0x7d, 0x70, 0x1c, 0x49, 0x76, 0x20, 0x86, 0x4f, 0x77, 0xe3, 0xa3, 0xf1, 0xf0, 0xd5, 0x48, 0x80, 0x24, 0x88, 0x99, 0x61, 0x73, 0x6a, 0x66, 0x38, 0xe4, 0xec, 0x0c, 0xb9, 0x04, 0x77, 0xb8, 0x3b, 0x3b, 0x5f, 0xdb, 0xe8, @@ -23674,436 +23721,439 @@ var fileDescriptor_9198ee693835762e = []byte{ 0x72, 0x0d, 0x0a, 0xbb, 0xb6, 0x50, 0x15, 0xd6, 0xf7, 0xed, 0x76, 0x9b, 0x36, 0xc5, 0x36, 0x3d, 0x2d, 0xe1, 0x65, 0x0e, 0xe6, 0x9c, 0x8d, 0xf7, 0x60, 0x2e, 0x6d, 0x96, 0x90, 0x17, 0x60, 0x42, 0x8d, 0x20, 0x24, 0x98, 0x8c, 0xdb, 0x1d, 0x47, 0xc6, 0x10, 0x12, 0x0c, 0x7e, 0x33, 0x03, 0xcf, - 0xf5, 0xdb, 0x73, 0xc8, 0xc2, 0xff, 0xc7, 0xde, 0xb7, 0xc4, 0xb8, 0x91, 0x9c, 0x07, 0xab, 0x49, - 0xce, 0x0c, 0xf9, 0xcd, 0xab, 0xa7, 0x34, 0xd2, 0xcc, 0xea, 0xb9, 0x6a, 0x3d, 0x2c, 0x71, 0xbd, - 0xeb, 0x95, 0xf6, 0x5f, 0xef, 0xca, 0xf6, 0xda, 0xee, 0xe1, 0xf4, 0x0c, 0x29, 0xf1, 0xe5, 0x6e, - 0x72, 0x64, 0x59, 0xb6, 0xdb, 0x2d, 0xb2, 0x67, 0xa6, 0xbd, 0x1c, 0x92, 0x66, 0x93, 0x2b, 0x8f, - 0xf1, 0x03, 0xbf, 0x8d, 0x1f, 0xb1, 0x81, 0xbc, 0x9c, 0x38, 0x09, 0xb2, 0xc8, 0xc5, 0x87, 0x2c, - 0x82, 0x1c, 0x9c, 0x63, 0x80, 0x20, 0x3e, 0xf9, 0x66, 0xc0, 0x30, 0x60, 0x20, 0x37, 0x27, 0x58, - 0x24, 0x0b, 0x24, 0x40, 0x1e, 0xb7, 0x20, 0x39, 0xf8, 0x14, 0xd4, 0x57, 0x55, 0xdd, 0xd5, 0x0f, - 0x52, 0x23, 0xef, 0x6e, 0x12, 0x03, 0x3e, 0xcd, 0xf0, 0xab, 0xaf, 0xbe, 0xae, 0x77, 0x7d, 0xf5, - 0x3d, 0x21, 0x3f, 0x1c, 0x79, 0x03, 0xe4, 0x6d, 0x79, 0x8a, 0x06, 0xf1, 0x1b, 0xb3, 0x2f, 0x20, - 0x13, 0x36, 0x76, 0x0e, 0xb8, 0x57, 0x88, 0x59, 0x40, 0x48, 0xcb, 0x39, 0xf0, 0xc9, 0x0b, 0xb0, - 0xd6, 0x75, 0xf7, 0x9d, 0x49, 0x6f, 0x6c, 0xfb, 0x9d, 0x43, 0xb7, 0x8b, 0x7e, 0x5b, 0x68, 0xed, - 0x67, 0xaa, 0xbc, 0xc0, 0x12, 0xf0, 0x44, 0x8b, 0xe7, 0xa6, 0xb4, 0xf8, 0x5e, 0x2e, 0xaf, 0xa8, - 0x19, 0x13, 0xcd, 0xab, 0xb4, 0x6f, 0x66, 0x60, 0x73, 0xda, 0x26, 0x23, 0x6f, 0xa4, 0x8d, 0x01, - 0xd3, 0x76, 0xc8, 0x70, 0x59, 0xdb, 0x21, 0x7d, 0x8d, 0xdc, 0x81, 0xc0, 0xeb, 0xea, 0x69, 0x11, - 0x14, 0x04, 0x8c, 0xd6, 0x19, 0x3a, 0xbe, 0xff, 0x84, 0x9e, 0x23, 0x59, 0x29, 0x0a, 0x2f, 0x87, - 0xc9, 0x75, 0x04, 0x8c, 0xbc, 0x06, 0xd0, 0xe9, 0x0d, 0x7c, 0x17, 0x8d, 0x0a, 0x38, 0x83, 0xc2, - 0x6c, 0xc9, 0x03, 0xa8, 0xac, 0x45, 0x46, 0x68, 0x69, 0xd0, 0x75, 0xf9, 0x04, 0x3a, 0xb0, 0x31, - 0xe5, 0x54, 0xa5, 0xd3, 0x13, 0xa6, 0xb4, 0x17, 0x09, 0xb2, 0x26, 0x41, 0x62, 0xfb, 0xf8, 0x88, - 0x67, 0xa6, 0xad, 0x91, 0x63, 0x20, 0xc9, 0xa3, 0x93, 0x52, 0xe7, 0x16, 0xd1, 0x93, 0x51, 0x40, - 0x9d, 0x41, 0xda, 0xa3, 0x1e, 0xb9, 0x0c, 0x8b, 0x22, 0x01, 0x26, 0x7d, 0x00, 0x30, 0xe2, 0xc0, - 0x41, 0xf7, 0x5d, 0x5c, 0x3c, 0x18, 0x66, 0x15, 0x7d, 0xeb, 0x38, 0x6b, 0x51, 0x40, 0x48, 0xeb, - 0x78, 0x28, 0x7a, 0x77, 0x41, 0xac, 0xef, 0xe8, 0x85, 0xc6, 0x4b, 0xff, 0x48, 0x11, 0xd3, 0x9f, - 0xbc, 0x11, 0x9e, 0xd6, 0x3e, 0x02, 0xe8, 0xda, 0xc4, 0x1b, 0x86, 0xff, 0x53, 0x56, 0x47, 0xec, - 0x3a, 0xce, 0xea, 0xf0, 0x9f, 0xe4, 0x06, 0xac, 0x8e, 0x98, 0xf1, 0xeb, 0x78, 0xc0, 0xc7, 0x93, - 0x25, 0x1b, 0x59, 0x66, 0xe0, 0xd6, 0x00, 0xc7, 0x94, 0xb7, 0xeb, 0x5e, 0x30, 0x60, 0xd2, 0x05, - 0x49, 0x5e, 0x82, 0x02, 0xbd, 0x20, 0x31, 0x3c, 0x4f, 0xcc, 0xa7, 0x02, 0xf1, 0x90, 0xdd, 0x30, - 0xf3, 0x5f, 0xe5, 0xff, 0x73, 0x5a, 0x6f, 0x67, 0x04, 0x31, 0xf9, 0x7a, 0x26, 0x1b, 0xb0, 0x30, - 0x18, 0x1d, 0x48, 0x5d, 0x9b, 0x1f, 0x8c, 0x0e, 0x68, 0xbf, 0x6e, 0x82, 0xca, 0x5c, 0x7c, 0x58, - 0xa8, 0x05, 0xff, 0xb8, 0xcf, 0xde, 0xef, 0x79, 0x73, 0x85, 0xc1, 0x31, 0xcb, 0xff, 0x71, 0xbf, - 0x43, 0x31, 0x7d, 0x7f, 0x60, 0xcb, 0x51, 0xb9, 0x78, 0xb7, 0x57, 0x7c, 0x7f, 0x10, 0x86, 0xe7, - 0xea, 0x92, 0x2d, 0x58, 0xa6, 0x74, 0x82, 0xd8, 0x60, 0x9c, 0x7b, 0xb8, 0x98, 0xe4, 0x1e, 0x8e, - 0xfb, 0x1d, 0xd1, 0x44, 0x73, 0xc9, 0x97, 0x7e, 0x91, 0xfb, 0xa0, 0x4a, 0x6c, 0x16, 0xfa, 0x7c, - 0xc6, 0x0c, 0xb1, 0x43, 0x32, 0x12, 0x7b, 0x56, 0xe9, 0xef, 0x0f, 0xcc, 0xd5, 0x4e, 0x14, 0xc0, - 0x87, 0xe6, 0xfb, 0x8a, 0x38, 0x4b, 0x53, 0x2a, 0x11, 0x0d, 0x96, 0x0f, 0x1d, 0xdf, 0xf6, 0xfd, - 0x23, 0x66, 0x58, 0xc6, 0xa3, 0x11, 0x2f, 0x1e, 0x3a, 0xbe, 0xe5, 0x1f, 0x89, 0x6c, 0x27, 0x67, - 0x28, 0xce, 0xc0, 0x99, 0x8c, 0x0f, 0x6d, 0x99, 0x69, 0x64, 0x23, 0x76, 0xfa, 0xd0, 0xf1, 0x1b, - 0xb4, 0x4c, 0xa2, 0x4d, 0xae, 0xc1, 0x0a, 0xd2, 0xed, 0x78, 0x82, 0x30, 0x86, 0xcb, 0x30, 0x97, - 0x28, 0xe1, 0x8e, 0xc7, 0x28, 0xf3, 0x16, 0xfe, 0x73, 0x06, 0xce, 0xa6, 0x8f, 0x0e, 0x2e, 0x4f, - 0x3a, 0xa6, 0xe8, 0xd8, 0xc7, 0xdb, 0x56, 0xa0, 0x10, 0x16, 0xea, 0x24, 0x6d, 0x72, 0x32, 0xa9, - 0x93, 0x53, 0x84, 0x35, 0x24, 0xc4, 0xd9, 0xd3, 0x9e, 0xe7, 0x8f, 0x79, 0x04, 0x0f, 0x73, 0x95, - 0x16, 0xb0, 0xf3, 0xbc, 0x4a, 0xc1, 0xe4, 0x3a, 0xac, 0x88, 0x13, 0x79, 0xf0, 0xa4, 0x4f, 0x3f, - 0xcc, 0x8e, 0xe3, 0x65, 0x0e, 0x6d, 0x20, 0x90, 0x9c, 0x81, 0x79, 0x67, 0x38, 0xa4, 0x9f, 0x64, - 0xa7, 0xf0, 0x9c, 0x33, 0x1c, 0xb2, 0x8c, 0x3c, 0xe8, 0xc6, 0x68, 0xef, 0xa3, 0x69, 0x11, 0xb7, - 0x63, 0x34, 0x97, 0x10, 0xc8, 0xcc, 0x8d, 0x7c, 0xba, 0xef, 0x69, 0x5d, 0x81, 0xb2, 0x80, 0x28, - 0xe0, 0x0c, 0x03, 0x84, 0xe7, 0x20, 0x2f, 0x94, 0xdc, 0xcc, 0x1b, 0xc3, 0x5c, 0x70, 0xb8, 0x82, - 0xfb, 0x55, 0xd8, 0xe8, 0x7a, 0x3e, 0x2e, 0x5e, 0xd6, 0xa5, 0xe1, 0x90, 0x3b, 0x4e, 0xb2, 0xc8, - 0xbe, 0xe6, 0x3a, 0x2f, 0xa6, 0x23, 0xa9, 0x0f, 0x87, 0xcc, 0x7d, 0x92, 0x8f, 0xf5, 0xeb, 0xb0, - 0xca, 0xd9, 0x34, 0x7e, 0x45, 0x62, 0x5b, 0xf8, 0x06, 0xa6, 0xef, 0x27, 0x9e, 0x03, 0x09, 0x38, - 0xa8, 0xd2, 0x15, 0x35, 0xff, 0x4e, 0x81, 0x33, 0xa9, 0x7c, 0x1e, 0xf9, 0x0a, 0x30, 0x3f, 0xb1, - 0xf1, 0xc0, 0x1e, 0xb9, 0x1d, 0x6f, 0xe8, 0x61, 0xe0, 0x0d, 0x26, 0x07, 0xbd, 0x33, 0x8b, 0x43, - 0x44, 0x9f, 0xb3, 0xd6, 0xc0, 0x0c, 0x2a, 0x31, 0x01, 0x8d, 0x3a, 0x8a, 0x81, 0xcf, 0x3d, 0x82, - 0x33, 0xa9, 0xa8, 0x29, 0x82, 0x93, 0x8f, 0x46, 0x33, 0x50, 0x0b, 0xcd, 0x56, 0xac, 0xd3, 0x92, - 0x40, 0x85, 0x77, 0xef, 0x47, 0x41, 0xf7, 0x62, 0x1c, 0x21, 0x31, 0xe2, 0xfb, 0x3a, 0xed, 0x51, - 0x23, 0x2a, 0x4d, 0xdf, 0xda, 0x8f, 0xe0, 0x0c, 0x5f, 0x7c, 0x07, 0x23, 0x67, 0x78, 0x18, 0x92, - 0x63, 0x0d, 0xfd, 0x48, 0x1a, 0x39, 0xb6, 0x2a, 0x77, 0x29, 0x7e, 0x40, 0xf5, 0xb4, 0x93, 0x04, - 0xf2, 0x3e, 0x7c, 0x2b, 0x23, 0xb6, 0x7a, 0x4a, 0x73, 0x52, 0x96, 0xb5, 0x92, 0xb6, 0xac, 0x4f, - 0xbe, 0xa7, 0xea, 0x40, 0xe4, 0xc3, 0x8a, 0x89, 0x4a, 0xb9, 0x15, 0x96, 0x60, 0xee, 0x79, 0x43, - 0xa4, 0xa3, 0xc1, 0x62, 0x19, 0x40, 0xd7, 0x3a, 0x71, 0x10, 0x39, 0x0f, 0x85, 0x20, 0xc9, 0x36, - 0xbf, 0x38, 0xf2, 0x0c, 0x50, 0xe9, 0x92, 0xe7, 0x61, 0x89, 0xf1, 0xf1, 0x91, 0x3d, 0x07, 0x08, - 0xd3, 0xe9, 0xc6, 0x13, 0x63, 0xa0, 0xc0, 0xf3, 0x4f, 0x1b, 0x43, 0xf2, 0x00, 0xce, 0xa2, 0x2d, - 0x88, 0x3f, 0x08, 0xa6, 0xc1, 0xee, 0x38, 0x9d, 0x43, 0x97, 0xaf, 0x5a, 0x2d, 0x75, 0x32, 0x86, - 0x43, 0xcb, 0x6a, 0x48, 0xf3, 0x30, 0x1c, 0x5a, 0xfe, 0x40, 0xfc, 0x2e, 0xd1, 0xea, 0xbc, 0x0d, - 0x5d, 0x38, 0x3f, 0xa3, 0xa6, 0x74, 0x70, 0x28, 0xf2, 0xc1, 0x71, 0x13, 0xd4, 0x7d, 0xb7, 0x4b, - 0x79, 0x62, 0xb7, 0x8b, 0x4d, 0x7b, 0xeb, 0x0e, 0x4b, 0x2b, 0x6f, 0xae, 0x04, 0x70, 0xcb, 0x1f, - 0xec, 0xdd, 0xe1, 0x5f, 0x39, 0x12, 0x57, 0x9e, 0xfc, 0x16, 0x21, 0x2f, 0xc1, 0xe9, 0x58, 0x50, - 0x93, 0xd0, 0x4b, 0xde, 0x5c, 0xa3, 0x45, 0xd1, 0x10, 0x58, 0x57, 0x60, 0x49, 0xac, 0x8a, 0x51, - 0xe0, 0x3c, 0x67, 0x2e, 0x72, 0x18, 0xdd, 0x75, 0xfc, 0x73, 0x13, 0xd1, 0xa9, 0xd4, 0x67, 0xcc, - 0x09, 0x78, 0x69, 0xf2, 0x22, 0x90, 0x80, 0x6f, 0x0f, 0x0e, 0x0a, 0xfe, 0xc1, 0x35, 0x51, 0x12, - 0xec, 0x70, 0xfe, 0xd9, 0xbf, 0x98, 0x83, 0xd3, 0x29, 0xef, 0x1f, 0xfa, 0x08, 0xf0, 0xfa, 0x63, - 0xf7, 0x80, 0x3d, 0x21, 0xe4, 0x4e, 0xae, 0x4a, 0x70, 0x2e, 0xd4, 0x9a, 0x67, 0x69, 0xd3, 0xf9, - 0xb7, 0xf8, 0x2f, 0x7a, 0x78, 0x38, 0x23, 0x21, 0xaf, 0xa1, 0xff, 0x92, 0x0a, 0xac, 0x61, 0x2e, - 0x08, 0xdf, 0x1b, 0x60, 0x4a, 0x09, 0x64, 0x42, 0x72, 0x91, 0x17, 0x12, 0xb6, 0xa2, 0x29, 0x21, - 0x51, 0x2e, 0xc4, 0x54, 0x87, 0x31, 0x08, 0xf9, 0x24, 0x9c, 0x93, 0xee, 0x1a, 0x3b, 0xb6, 0xf3, - 0xd0, 0x3c, 0xde, 0xdc, 0x70, 0x82, 0x5b, 0x67, 0x3b, 0xb2, 0x07, 0xb7, 0xe0, 0x12, 0x4e, 0xa2, - 0xd7, 0x1d, 0xda, 0x89, 0xe4, 0x21, 0xd8, 0x55, 0x16, 0x6d, 0xff, 0x1c, 0xc5, 0xaa, 0x74, 0x87, - 0xb1, 0x3c, 0x22, 0xd8, 0xeb, 0x6a, 0xea, 0xee, 0x5c, 0xc0, 0xdd, 0x79, 0x51, 0xee, 0xcc, 0x89, - 0xf6, 0xe6, 0x01, 0xac, 0x05, 0x9c, 0x52, 0x70, 0x6d, 0xe5, 0x23, 0x29, 0xd4, 0x91, 0x98, 0xe0, - 0x9b, 0xd8, 0x3d, 0xc6, 0x1c, 0xfc, 0x13, 0x15, 0xe5, 0x30, 0x16, 0x93, 0x48, 0x05, 0x9f, 0x54, - 0x61, 0x9d, 0xbe, 0x81, 0x79, 0xca, 0x4a, 0x3f, 0xf8, 0x56, 0x21, 0xf9, 0x2d, 0xa1, 0x9d, 0x61, - 0x55, 0x4d, 0xe2, 0x3c, 0xf1, 0x79, 0x26, 0x4b, 0x5f, 0x50, 0xfb, 0x2a, 0x10, 0x76, 0x19, 0x47, - 0xda, 0x0d, 0x4f, 0xa3, 0xc5, 0xf3, 0x5d, 0x26, 0x6a, 0xca, 0xc1, 0xb8, 0xb0, 0x54, 0x6a, 0x39, - 0x5f, 0xaf, 0xbf, 0xa1, 0xc0, 0xe9, 0x14, 0x8a, 0x44, 0x83, 0x8c, 0xd8, 0xf0, 0x49, 0x2b, 0xa3, - 0xf2, 0x29, 0x33, 0xe3, 0x75, 0xc9, 0x5d, 0x00, 0xcc, 0x13, 0x39, 0x72, 0x0f, 0xdc, 0xaf, 0xcb, - 0x49, 0xf2, 0x43, 0x68, 0xa4, 0x4e, 0x01, 0x25, 0xb7, 0x14, 0xcc, 0x9f, 0xd0, 0x05, 0x58, 0xf0, - 0xfa, 0x9d, 0xde, 0xa4, 0xeb, 0x6a, 0x3f, 0x10, 0xed, 0x88, 0xce, 0x08, 0x69, 0x01, 0x57, 0xef, - 0xf1, 0xd9, 0xbb, 0x31, 0x7d, 0xf6, 0x64, 0xad, 0x09, 0x0f, 0xee, 0x80, 0x00, 0x59, 0x37, 0xc0, - 0x20, 0xef, 0x43, 0x9f, 0xc1, 0x87, 0xed, 0x11, 0x9c, 0x49, 0xdd, 0x59, 0x94, 0x11, 0x42, 0x2b, - 0xc1, 0x90, 0x87, 0x5f, 0xa0, 0xbf, 0x29, 0x13, 0x7f, 0x05, 0x96, 0x1e, 0xbb, 0xce, 0xc8, 0x1d, - 0x71, 0x0e, 0x93, 0x1f, 0x5d, 0x0c, 0x26, 0x33, 0x98, 0xdd, 0xe8, 0x11, 0xc2, 0x05, 0xa2, 0xa4, - 0x06, 0xa7, 0xd9, 0x14, 0x7b, 0x47, 0xf8, 0x68, 0xe1, 0x42, 0x54, 0x25, 0xc2, 0xb6, 0x63, 0x15, - 0x64, 0xa1, 0x2a, 0x88, 0xc5, 0x6a, 0x9b, 0x6b, 0x07, 0x71, 0x10, 0xbd, 0x79, 0xce, 0xa6, 0x63, - 0x93, 0x2d, 0x58, 0x64, 0xc4, 0xd9, 0xf3, 0x95, 0x69, 0xbf, 0xae, 0xcc, 0xfc, 0x42, 0x09, 0x8d, - 0xe7, 0xfd, 0xe0, 0x7f, 0xca, 0x57, 0xa2, 0xa1, 0x81, 0x7d, 0x24, 0x2b, 0xf7, 0xcc, 0x25, 0x04, - 0x72, 0xa5, 0x9e, 0xf6, 0x37, 0x8a, 0xe8, 0x6a, 0x44, 0xf2, 0x43, 0x8f, 0x40, 0xdf, 0xed, 0x0b, - 0x05, 0x67, 0xc1, 0xe4, 0xbf, 0x9e, 0xf1, 0x48, 0x26, 0xaf, 0xc1, 0x12, 0x25, 0x7b, 0x30, 0xe9, - 0xb3, 0xa3, 0x31, 0x1b, 0x09, 0x3a, 0x55, 0x63, 0x45, 0x74, 0xda, 0xca, 0xa7, 0xcc, 0xc5, 0xa3, - 0xf0, 0x27, 0x7d, 0xd5, 0xf9, 0x47, 0xe3, 0xa1, 0x7c, 0xa0, 0x0a, 0x29, 0xb8, 0x55, 0x6b, 0x35, - 0x79, 0x95, 0x3c, 0xc5, 0x09, 0x5f, 0x75, 0x5b, 0xf3, 0x4c, 0x0e, 0xae, 0xbd, 0x00, 0x8b, 0x12, - 0x6d, 0xda, 0x19, 0xe6, 0x16, 0x26, 0x3a, 0xc3, 0x7e, 0xf1, 0xc9, 0x7e, 0x0c, 0x79, 0x41, 0x92, - 0x3e, 0x5f, 0x0f, 0x07, 0xbe, 0xb8, 0x8c, 0xf0, 0x7f, 0x0a, 0xa3, 0xa3, 0x8c, 0x9d, 0x9c, 0x33, - 0xf1, 0x7f, 0xe4, 0x79, 0xc6, 0x0e, 0x7d, 0xb7, 0xf6, 0x7c, 0x7b, 0x88, 0xe6, 0x85, 0xc1, 0x23, - 0x8f, 0xc2, 0x5b, 0x3d, 0x9f, 0x19, 0x1d, 0xf2, 0x6f, 0xfc, 0x55, 0xc0, 0x2c, 0xc6, 0x44, 0x65, - 0xd3, 0xee, 0xf6, 0x08, 0x6b, 0x93, 0x49, 0xb2, 0x36, 0x2c, 0x98, 0x10, 0xaf, 0xc9, 0xbe, 0x0c, - 0x08, 0x43, 0xd6, 0x46, 0xba, 0xc1, 0x72, 0x91, 0x1b, 0x4c, 0x92, 0x1d, 0x85, 0xb3, 0xc7, 0x38, - 0x23, 0x21, 0x3b, 0x8a, 0xdf, 0xa7, 0xef, 0x04, 0x2b, 0x24, 0x22, 0xac, 0xa3, 0x8f, 0x3c, 0xf6, - 0xc0, 0xe3, 0x29, 0xa8, 0x63, 0x17, 0xf9, 0x69, 0x2c, 0x64, 0x09, 0xaa, 0x82, 0x0b, 0xfd, 0xe9, - 0xb2, 0x11, 0xf2, 0x32, 0xac, 0x07, 0x49, 0x53, 0xfd, 0x37, 0xbd, 0xa1, 0x8d, 0x69, 0x73, 0x8f, - 0xf9, 0xd3, 0x8b, 0x88, 0x32, 0xeb, 0x4d, 0x6f, 0xb8, 0x87, 0x25, 0xbc, 0x99, 0x7f, 0x96, 0x11, - 0x12, 0xb7, 0xad, 0xc1, 0x60, 0xec, 0x8f, 0x47, 0xce, 0x30, 0xa2, 0x8e, 0x20, 0x47, 0xf0, 0x1c, - 0x36, 0xe9, 0x0e, 0xa6, 0xb1, 0x19, 0x8c, 0x44, 0x98, 0x9d, 0x60, 0x83, 0x2d, 0xde, 0xf9, 0x58, - 0xf4, 0xc9, 0xac, 0x53, 0x6c, 0x5d, 0x46, 0xa6, 0xfb, 0x4a, 0xa2, 0x5a, 0x3e, 0x65, 0x6e, 0x30, - 0x9a, 0x09, 0x2c, 0x52, 0x4e, 0x39, 0x6b, 0xe2, 0xfa, 0x88, 0xad, 0xf0, 0xe0, 0x89, 0x52, 0x95, - 0x8f, 0x24, 0xf2, 0x69, 0x28, 0x78, 0x5d, 0x39, 0x5b, 0x6b, 0x5c, 0x12, 0x5e, 0xe9, 0xb2, 0x88, - 0xf1, 0x21, 0x0d, 0xba, 0x35, 0x3c, 0x0e, 0xdd, 0x5a, 0x8e, 0x28, 0x6e, 0xb4, 0x2d, 0x21, 0xdc, - 0x49, 0x56, 0x23, 0x2b, 0xe1, 0x9d, 0x83, 0xf7, 0x0b, 0x9e, 0x02, 0x61, 0xcc, 0x7a, 0x93, 0xff, - 0xd2, 0xfe, 0x2f, 0xdc, 0x3c, 0xe9, 0x18, 0xd1, 0x13, 0x63, 0xca, 0x80, 0x17, 0x58, 0xb8, 0xd8, - 0xe8, 0xb8, 0x5d, 0x01, 0x39, 0xe4, 0xb6, 0x27, 0x96, 0x88, 0x80, 0xb5, 0x47, 0x9e, 0xf6, 0x6f, - 0x59, 0x58, 0x89, 0xaa, 0xaa, 0xc8, 0x0b, 0x90, 0x93, 0x0e, 0xca, 0x8d, 0x14, 0x7d, 0x16, 0x1e, - 0x8f, 0x88, 0x74, 0xa2, 0x83, 0x91, 0xdc, 0x83, 0x15, 0x34, 0x9e, 0xc5, 0xdb, 0x7c, 0xec, 0x71, - 0x05, 0xe8, 0x6c, 0x1d, 0x76, 0xfe, 0xc7, 0xef, 0x5e, 0x3e, 0x85, 0xea, 0xea, 0x25, 0x5a, 0x97, - 0x5e, 0x8c, 0xb4, 0x50, 0xd2, 0x44, 0xe4, 0xa6, 0x6b, 0x22, 0x78, 0x57, 0xa6, 0x68, 0x22, 0xe6, - 0x66, 0x68, 0x22, 0xc2, 0x9a, 0xb2, 0x26, 0x02, 0xf5, 0x51, 0x0b, 0xd3, 0xf4, 0x51, 0x61, 0x1d, - 0xa6, 0x8f, 0x0a, 0x35, 0x09, 0xf9, 0xa9, 0x9a, 0x84, 0xb0, 0x0e, 0xd7, 0x24, 0x84, 0xb2, 0xfd, - 0xc2, 0x54, 0xd9, 0xbe, 0x54, 0x89, 0xc9, 0xf6, 0xaf, 0xf1, 0x81, 0x1d, 0x39, 0x4f, 0x6c, 0x1c, - 0x71, 0xce, 0x9a, 0xe2, 0x90, 0x99, 0xce, 0x13, 0xb4, 0x8a, 0xa3, 0x8c, 0x09, 0x37, 0xa5, 0xd3, - 0x7e, 0x18, 0x3b, 0x80, 0xc4, 0x9c, 0x5f, 0x87, 0x15, 0x76, 0x0f, 0xf3, 0x30, 0xc4, 0xec, 0x22, - 0x5e, 0x36, 0x97, 0x05, 0x94, 0x89, 0x7c, 0x3e, 0x02, 0xab, 0x01, 0x1a, 0x97, 0x7a, 0xa0, 0x87, - 0xad, 0x19, 0xd4, 0xe6, 0xe1, 0xa2, 0x64, 0x7a, 0x23, 0x1e, 0x90, 0x29, 0x42, 0x8f, 0x45, 0xeb, - 0x79, 0x11, 0x48, 0x88, 0x16, 0x18, 0x16, 0xe7, 0x10, 0x75, 0x2d, 0x40, 0x0d, 0xac, 0x7f, 0xff, - 0x40, 0x89, 0xe9, 0x12, 0x3e, 0xac, 0xe6, 0xbf, 0x00, 0xc1, 0xd7, 0x6d, 0x2e, 0x0f, 0x16, 0x3d, - 0x50, 0x45, 0x41, 0x93, 0xc3, 0xb5, 0x83, 0xb8, 0xec, 0xe2, 0x43, 0x6a, 0x95, 0xf6, 0xa3, 0x6c, - 0x44, 0xce, 0x2a, 0x3e, 0x43, 0xf9, 0x1b, 0x7f, 0x60, 0xf3, 0x29, 0xe6, 0xc7, 0xef, 0x95, 0x29, - 0xcb, 0x94, 0x9b, 0x52, 0x5a, 0x56, 0xc3, 0x04, 0xdf, 0x1f, 0x08, 0xcb, 0x4a, 0x9b, 0xbd, 0xc9, - 0x25, 0xa6, 0x5b, 0x90, 0x63, 0x67, 0x6d, 0x71, 0x36, 0x39, 0x21, 0xe8, 0xa2, 0xbb, 0x14, 0xdf, - 0xe6, 0xc1, 0x2f, 0xf1, 0x81, 0x36, 0xa0, 0x5a, 0xc2, 0x8f, 0x12, 0xcf, 0xa6, 0x48, 0x5f, 0x12, - 0xc4, 0x71, 0x94, 0x90, 0xb2, 0x3a, 0x11, 0xff, 0x0a, 0xb2, 0x06, 0x2c, 0xa1, 0x94, 0x53, 0x10, - 0xcc, 0xa5, 0x68, 0xfe, 0x92, 0x9d, 0x2f, 0x55, 0x6a, 0xe6, 0x22, 0xad, 0x27, 0xc8, 0x1c, 0xc2, - 0x73, 0xb2, 0x6c, 0x32, 0xda, 0xc8, 0x39, 0x11, 0x3c, 0x7c, 0xe6, 0x08, 0x84, 0x22, 0x4c, 0x6c, - 0xea, 0x59, 0x27, 0x0a, 0xe0, 0x68, 0xda, 0x21, 0x9c, 0x9b, 0x3e, 0x25, 0x33, 0x12, 0xd3, 0x85, - 0xac, 0x4d, 0x46, 0x66, 0x6d, 0x64, 0x49, 0x65, 0x36, 0x22, 0xa9, 0xd4, 0xfe, 0x34, 0x0b, 0x57, - 0x4f, 0x30, 0x5d, 0x33, 0xbe, 0xf9, 0xd9, 0x28, 0xe3, 0x9c, 0x89, 0xc8, 0x96, 0x28, 0x51, 0x7e, - 0x27, 0x1c, 0xf7, 0x3b, 0x53, 0xd8, 0xe6, 0xaf, 0xc0, 0x2a, 0x3b, 0xf8, 0x99, 0x35, 0xf4, 0xfe, - 0xa4, 0x77, 0x82, 0x93, 0xff, 0xbc, 0x70, 0xdd, 0x8c, 0x55, 0xc5, 0xcb, 0x00, 0xcf, 0x3b, 0x2b, - 0x80, 0x91, 0x16, 0x2c, 0x22, 0xda, 0xbe, 0xe3, 0xf5, 0x4e, 0xe4, 0x43, 0x28, 0x1c, 0x43, 0xe5, - 0x6a, 0xcc, 0x89, 0x83, 0x02, 0x76, 0xf0, 0x37, 0xb9, 0x01, 0xab, 0xfd, 0xc9, 0x11, 0x65, 0x09, - 0xd9, 0x5a, 0xe0, 0x46, 0x67, 0x73, 0xe6, 0x72, 0x7f, 0x72, 0xa4, 0x0f, 0x87, 0x38, 0xa5, 0x68, - 0x9d, 0xb6, 0x46, 0xf1, 0xd8, 0xae, 0x15, 0x98, 0xf3, 0x88, 0x49, 0x09, 0xb0, 0x7d, 0xcb, 0x71, - 0xd7, 0x81, 0xd9, 0x2a, 0xf3, 0xc4, 0x7c, 0xec, 0x87, 0xf6, 0x9f, 0x19, 0x21, 0x31, 0x9b, 0xbe, - 0xee, 0x7f, 0x3d, 0x45, 0x29, 0x53, 0x74, 0x13, 0x54, 0x3a, 0xf4, 0xe1, 0xa1, 0x12, 0xcc, 0xd1, - 0x4a, 0x7f, 0x72, 0x14, 0x8c, 0x9d, 0x3c, 0xf0, 0xf3, 0xf2, 0xc0, 0xbf, 0x26, 0x24, 0x6a, 0xa9, - 0xc7, 0xc3, 0xf4, 0x21, 0xa7, 0x1c, 0xd3, 0x8d, 0x93, 0x1d, 0x02, 0xbf, 0x9e, 0xb7, 0x94, 0x79, - 0x8b, 0x29, 0x5f, 0xe6, 0x12, 0xca, 0x97, 0x94, 0xbd, 0x37, 0x9f, 0xb6, 0xf7, 0x12, 0xaa, 0x9e, - 0x85, 0x14, 0x55, 0x4f, 0xea, 0x06, 0xcd, 0x3f, 0x65, 0x83, 0x16, 0xe4, 0x75, 0xf2, 0x4f, 0x19, - 0xc1, 0x31, 0x45, 0x9f, 0x40, 0x8f, 0xe0, 0xb4, 0x78, 0x02, 0xb1, 0x9b, 0x23, 0xd4, 0xe0, 0x2d, - 0xde, 0xb9, 0x95, 0xf6, 0xf8, 0x41, 0xb4, 0x94, 0x07, 0xca, 0x1a, 0x7f, 0xf6, 0x84, 0xe5, 0xff, - 0x7b, 0x1e, 0x3c, 0xe4, 0x21, 0x9c, 0xc5, 0xb4, 0x16, 0x1d, 0x59, 0xf7, 0x68, 0x8f, 0xdc, 0x7d, - 0xbe, 0x1e, 0xae, 0x24, 0x9e, 0x07, 0x5e, 0x47, 0x6a, 0x8e, 0xe9, 0xee, 0x97, 0x4f, 0x99, 0xeb, - 0x7e, 0x0a, 0x3c, 0xfe, 0x96, 0xfa, 0x81, 0x02, 0xda, 0xd3, 0xc7, 0x0b, 0x9f, 0xbd, 0xf1, 0x01, - 0xa7, 0xcf, 0x5e, 0x69, 0xf4, 0xae, 0xc2, 0xf2, 0xc8, 0xdd, 0x1f, 0xb9, 0xfe, 0x61, 0x44, 0x36, - 0xb5, 0xc4, 0x81, 0x62, 0x60, 0x44, 0x2c, 0xdc, 0x67, 0x7a, 0x8c, 0x88, 0x4a, 0xda, 0x4e, 0xf0, - 0x44, 0x4e, 0x9d, 0x07, 0xba, 0x9a, 0xe4, 0x06, 0xb2, 0x1f, 0xf7, 0x72, 0xf9, 0x8c, 0x9a, 0x35, - 0x79, 0xc4, 0xde, 0x7d, 0xaf, 0xe7, 0x6a, 0x7f, 0xad, 0x08, 0x8e, 0x20, 0x6d, 0xf0, 0xc8, 0x23, - 0xc9, 0x87, 0x20, 0x9b, 0x60, 0x43, 0xd2, 0xaa, 0x9c, 0x44, 0x70, 0x58, 0xfd, 0x80, 0x04, 0x87, - 0x77, 0x85, 0x21, 0x22, 0x3d, 0xf3, 0xf6, 0x6e, 0x93, 0x5b, 0xb0, 0xc0, 0x6c, 0x0f, 0x45, 0x73, - 0x57, 0x23, 0xcd, 0xdd, 0xbb, 0x6d, 0x8a, 0x72, 0xed, 0xed, 0x40, 0x33, 0x9e, 0xe8, 0xc4, 0xde, - 0x6d, 0xf2, 0xda, 0xc9, 0x7c, 0x02, 0xf2, 0xc2, 0x27, 0x20, 0xf0, 0x07, 0x78, 0x3d, 0xe2, 0x0f, - 0x70, 0x6d, 0xf6, 0x68, 0x71, 0x7b, 0x06, 0x16, 0x05, 0x35, 0x8c, 0x8e, 0xf7, 0xf3, 0x0c, 0x5c, - 0x9c, 0x59, 0x83, 0x5c, 0x80, 0xbc, 0xde, 0xac, 0xb4, 0xc2, 0xf9, 0xa5, 0x7b, 0x46, 0x40, 0xc8, - 0x2e, 0x14, 0xb6, 0x1c, 0xdf, 0xeb, 0xd0, 0x65, 0x9c, 0xaa, 0x60, 0x4c, 0x90, 0x0d, 0xd0, 0xcb, - 0xa7, 0xcc, 0xb0, 0x2e, 0xb1, 0x61, 0x0d, 0xf7, 0x42, 0x24, 0xe3, 0x5d, 0x36, 0x45, 0xbc, 0x92, - 0x20, 0x98, 0xa8, 0x46, 0xcf, 0x99, 0x04, 0x90, 0x3c, 0x06, 0x62, 0x59, 0xe5, 0x92, 0x3b, 0x1a, - 0x73, 0xb1, 0xc3, 0xd8, 0x0b, 0x0c, 0xcc, 0x5f, 0x7e, 0xca, 0xd8, 0x25, 0xea, 0x95, 0x4f, 0x99, - 0x29, 0xd4, 0xe2, 0xdb, 0xfc, 0x2d, 0xc1, 0xef, 0x4c, 0x1f, 0x84, 0x67, 0x88, 0x30, 0x7d, 0x13, - 0xf2, 0x4d, 0x61, 0xcd, 0x24, 0x39, 0xea, 0x08, 0xcb, 0x25, 0x33, 0x28, 0xd5, 0x7e, 0x5b, 0x11, - 0x72, 0x96, 0xa7, 0x0f, 0x96, 0x94, 0x90, 0xb0, 0x3b, 0x3b, 0x21, 0x61, 0xf7, 0x97, 0x4c, 0x48, - 0xa8, 0x79, 0x70, 0xeb, 0xc4, 0x03, 0x4b, 0x3e, 0x05, 0x2a, 0xe6, 0x6e, 0x73, 0xa4, 0x49, 0x62, - 0xfb, 0x6b, 0x2d, 0x48, 0x39, 0x50, 0xe6, 0x09, 0x32, 0xcd, 0xd5, 0x4e, 0xb4, 0xb6, 0xf6, 0xe7, - 0x3c, 0xd5, 0x44, 0xa5, 0xdb, 0x8c, 0xa9, 0xaa, 0xde, 0xaf, 0x6f, 0x97, 0x11, 0xd9, 0x6c, 0x57, - 0xa5, 0xdc, 0xb9, 0xc9, 0x6f, 0x4d, 0x77, 0xf1, 0x92, 0x76, 0xde, 0x1f, 0x67, 0xe1, 0xc2, 0xac, - 0xea, 0xa9, 0xd9, 0xf9, 0x95, 0x67, 0xcb, 0xce, 0x7f, 0x0b, 0xf2, 0x0c, 0x16, 0x38, 0x2e, 0xe1, - 0xdc, 0xf2, 0xaa, 0x74, 0x6e, 0x45, 0x31, 0xb9, 0x0a, 0xf3, 0x7a, 0xc9, 0x0a, 0x13, 0x46, 0xa2, - 0x87, 0x81, 0xd3, 0xf1, 0xd1, 0x76, 0x9d, 0x17, 0x91, 0x2f, 0x27, 0x73, 0xa4, 0xf2, 0x4c, 0x91, - 0xe7, 0xa5, 0x01, 0x49, 0x64, 0x81, 0xc1, 0xf6, 0x86, 0x59, 0x4b, 0x78, 0x22, 0x00, 0x33, 0x99, - 0x6f, 0x55, 0x83, 0xf9, 0xe6, 0xc8, 0xf5, 0xdd, 0xb1, 0x6c, 0xfd, 0x3f, 0x44, 0x88, 0xc9, 0x4b, - 0xb8, 0x6d, 0xbe, 0x73, 0xcc, 0x42, 0xb1, 0xcc, 0xcb, 0xe1, 0xb1, 0xd0, 0x98, 0x9f, 0x82, 0x4d, - 0x09, 0x85, 0x56, 0xa8, 0x3a, 0x93, 0x7e, 0xe7, 0xb0, 0x6d, 0x56, 0x39, 0xe7, 0xc4, 0x2a, 0xf4, - 0x10, 0x4a, 0x3b, 0xe8, 0x9b, 0x12, 0x8a, 0xf6, 0x1d, 0x05, 0xd6, 0xd3, 0xfa, 0x41, 0x2e, 0x40, - 0xae, 0x9f, 0x9a, 0x0e, 0xb6, 0xcf, 0x22, 0x48, 0x2c, 0xa2, 0xfa, 0x6c, 0x7f, 0x30, 0x3a, 0x72, - 0xc6, 0xb2, 0x8f, 0x84, 0x04, 0x36, 0x51, 0xf1, 0xb6, 0x83, 0xff, 0x93, 0xcb, 0xe2, 0xca, 0xc9, - 0x26, 0x12, 0xc8, 0xe2, 0x1f, 0x4d, 0x07, 0xa8, 0x74, 0x9b, 0x8d, 0x21, 0xcb, 0x42, 0xf2, 0x0a, - 0xe4, 0x68, 0xb3, 0x62, 0xab, 0x97, 0xae, 0x1f, 0xbd, 0x56, 0xe5, 0x48, 0xac, 0x55, 0xbe, 0x73, - 0xd4, 0x33, 0x11, 0x59, 0x7b, 0x00, 0x2b, 0x51, 0x0c, 0x62, 0x44, 0x03, 0x51, 0x2f, 0xde, 0x51, - 0x39, 0xa5, 0xad, 0xc1, 0x80, 0xf9, 0xe9, 0x6d, 0x3d, 0xf7, 0xf3, 0x77, 0x2f, 0x03, 0xfd, 0xc9, - 0xea, 0xa4, 0x05, 0xaa, 0xd6, 0xbe, 0x9b, 0x81, 0xf5, 0x30, 0x34, 0x88, 0xd8, 0x43, 0xbf, 0xb2, - 0x7e, 0xea, 0x7a, 0xc4, 0x8f, 0x5a, 0xf0, 0x8d, 0xc9, 0x0e, 0xce, 0x70, 0xdf, 0xdc, 0x85, 0xcd, - 0x69, 0xf8, 0xe4, 0x05, 0x28, 0x60, 0x34, 0xb9, 0xa1, 0xd3, 0x71, 0xe5, 0x63, 0xb6, 0x2f, 0x80, - 0x66, 0x58, 0xae, 0xfd, 0x54, 0x81, 0x73, 0xdc, 0xbb, 0xac, 0xe6, 0x78, 0x7d, 0xd4, 0xdf, 0x74, - 0xdc, 0x0f, 0x26, 0xce, 0xc2, 0x6e, 0xe4, 0x1c, 0xbb, 0x1e, 0x75, 0x22, 0x4c, 0x7c, 0x6d, 0x7a, - 0x6f, 0xc9, 0x2d, 0x8c, 0x90, 0xc8, 0xed, 0x70, 0x72, 0x2c, 0xae, 0x4d, 0x9f, 0x02, 0xe4, 0xb8, - 0x36, 0x88, 0xa1, 0xfd, 0x3f, 0xb8, 0x34, 0xfb, 0x03, 0xe4, 0x4b, 0xb0, 0x8c, 0x29, 0xff, 0xda, - 0xc3, 0x83, 0x91, 0xd3, 0x75, 0x85, 0x64, 0x4f, 0x08, 0xa0, 0xe5, 0x32, 0x16, 0xf0, 0x91, 0xc7, - 0x59, 0x39, 0xc0, 0x64, 0x82, 0xbc, 0x52, 0xc4, 0x85, 0x53, 0xa6, 0xa6, 0x7d, 0x53, 0x01, 0x92, - 0xa4, 0x41, 0x3e, 0x0e, 0x4b, 0xed, 0x56, 0xc9, 0x1a, 0x3b, 0xa3, 0x71, 0x79, 0x30, 0x19, 0xf1, - 0x68, 0x8b, 0x2c, 0xec, 0xc6, 0xb8, 0x63, 0x33, 0x4d, 0xdd, 0xe1, 0x60, 0x32, 0x32, 0x23, 0x78, - 0x98, 0x5a, 0xce, 0x75, 0xdf, 0xec, 0x3a, 0xc7, 0xd1, 0xd4, 0x72, 0x1c, 0x16, 0x49, 0x2d, 0xc7, - 0x61, 0xda, 0x3b, 0x0a, 0x9c, 0x17, 0xe6, 0xd5, 0xdd, 0x94, 0xb6, 0x94, 0x30, 0xb8, 0xd4, 0x48, - 0x84, 0xf7, 0x9e, 0xc5, 0xa1, 0xaf, 0x89, 0xf8, 0x6b, 0xd8, 0x40, 0x64, 0xd5, 0x59, 0x5d, 0xf2, - 0x59, 0xc8, 0x59, 0xe3, 0xc1, 0xf0, 0x04, 0x01, 0xd8, 0xd4, 0x60, 0x46, 0xc7, 0x83, 0x21, 0x92, - 0xc0, 0x9a, 0x9a, 0x0b, 0xeb, 0x72, 0xe3, 0x44, 0x8b, 0x49, 0x0d, 0x16, 0x78, 0xa4, 0xcd, 0x98, - 0xe5, 0xd2, 0x8c, 0x3e, 0x6d, 0xad, 0x8a, 0x28, 0x6f, 0x3c, 0xbc, 0xb4, 0x29, 0x68, 0x68, 0xbf, - 0xab, 0xc0, 0x22, 0x65, 0x6c, 0xf0, 0x51, 0xfa, 0x7e, 0x97, 0x74, 0x94, 0x0f, 0x16, 0x86, 0x78, - 0x01, 0xf9, 0x13, 0xdd, 0xc6, 0xaf, 0xc2, 0x6a, 0xac, 0x02, 0xd1, 0x30, 0xbe, 0x4f, 0xcf, 0xeb, - 0x38, 0x2c, 0x53, 0x15, 0x33, 0x62, 0x8b, 0xc0, 0xb4, 0xdf, 0x54, 0x60, 0xbd, 0xf1, 0xe6, 0xd8, - 0x61, 0x0a, 0x75, 0x73, 0xd2, 0x13, 0xfb, 0x9d, 0x32, 0x6b, 0xc2, 0x4e, 0x9f, 0xc5, 0x1e, 0x61, - 0xcc, 0x1a, 0x87, 0x99, 0x41, 0x29, 0x29, 0x43, 0x9e, 0xdf, 0x2f, 0x3e, 0x8f, 0x0a, 0x7d, 0x49, - 0x92, 0x8d, 0x84, 0x84, 0x39, 0x12, 0xed, 0x09, 0x1e, 0x61, 0xbc, 0x8e, 0x19, 0xd4, 0xd6, 0xfe, - 0x5d, 0x81, 0x8d, 0x29, 0x75, 0xc8, 0x1b, 0x30, 0x87, 0x7e, 0xd1, 0x7c, 0xf6, 0x2e, 0x4c, 0xf9, - 0xc4, 0xb8, 0x73, 0xb8, 0x77, 0x9b, 0x5d, 0x44, 0x47, 0xf4, 0x87, 0xc9, 0x6a, 0x91, 0x47, 0x50, - 0xd0, 0xbb, 0x5d, 0xfe, 0x3a, 0xcb, 0x44, 0x5e, 0x67, 0x53, 0xbe, 0xf8, 0x52, 0x80, 0xcf, 0x5e, - 0x67, 0xcc, 0x43, 0xaf, 0xdb, 0xb5, 0xb9, 0xcf, 0x77, 0x48, 0xef, 0xdc, 0xa7, 0x60, 0x25, 0x8a, - 0xfc, 0x4c, 0x6e, 0xaa, 0x6f, 0x2b, 0xa0, 0x46, 0xdb, 0xf0, 0xe1, 0xc4, 0xa7, 0x4b, 0x9b, 0xe6, - 0xa7, 0x2c, 0xaa, 0xdf, 0xcf, 0xc0, 0x99, 0xd4, 0x11, 0x26, 0x2f, 0xc2, 0xbc, 0x3e, 0x1c, 0x56, - 0xb6, 0xf9, 0xaa, 0xe2, 0x1c, 0x12, 0x0a, 0xbd, 0x23, 0x8f, 0x57, 0x86, 0x44, 0x5e, 0x81, 0x3c, - 0xb3, 0xdb, 0xd8, 0x16, 0x07, 0x0e, 0x06, 0xdc, 0xe2, 0x46, 0x25, 0xd1, 0xf8, 0xcc, 0x02, 0x91, - 0xec, 0xc0, 0x0a, 0x0f, 0x55, 0x85, 0x96, 0x3b, 0x41, 0xa2, 0x10, 0xcc, 0x65, 0x22, 0x24, 0xe9, - 0xcc, 0xd8, 0x27, 0x72, 0x76, 0xc6, 0x6a, 0x91, 0x2a, 0xa8, 0x48, 0x53, 0xa6, 0xc4, 0x82, 0x44, - 0x4b, 0xc6, 0x4b, 0x53, 0x68, 0x25, 0x6a, 0x06, 0xd3, 0xa5, 0xfb, 0xbe, 0x77, 0xd0, 0x3f, 0x72, - 0xfb, 0xe3, 0x0f, 0x6f, 0xba, 0xc2, 0x6f, 0x9c, 0x68, 0xba, 0xfe, 0x30, 0xc7, 0x36, 0x73, 0xbc, - 0x1a, 0xe5, 0x68, 0xa4, 0xbc, 0x00, 0xc8, 0xd1, 0xd0, 0xf7, 0x19, 0x0f, 0xc6, 0xb4, 0x0d, 0x0b, - 0x2c, 0x48, 0x96, 0xd8, 0x19, 0x17, 0x53, 0x9b, 0xc0, 0x70, 0xf6, 0x6e, 0x33, 0xf6, 0x85, 0x39, - 0x68, 0xfb, 0xa6, 0xa8, 0x4a, 0xf6, 0x60, 0xb1, 0xd4, 0x73, 0x9d, 0xfe, 0x64, 0xd8, 0x3a, 0x99, - 0xd2, 0x78, 0x93, 0xf7, 0x65, 0xa9, 0xc3, 0xaa, 0xa1, 0xb2, 0x19, 0x4f, 0x72, 0x99, 0x10, 0x69, - 0x05, 0x3e, 0x9b, 0x39, 0x14, 0xbc, 0xbe, 0x3c, 0x63, 0x7c, 0xe2, 0x40, 0xac, 0x17, 0x75, 0x48, - 0xe6, 0x4e, 0x9d, 0x36, 0xac, 0x54, 0x1d, 0x7f, 0xdc, 0x1a, 0x39, 0x7d, 0x1f, 0x83, 0xeb, 0x9e, - 0x20, 0xf8, 0xe0, 0x79, 0x91, 0x38, 0x1e, 0x45, 0xa6, 0xe3, 0xa0, 0x2a, 0x13, 0xc8, 0x46, 0xc9, - 0x51, 0x7e, 0x69, 0xc7, 0xeb, 0x3b, 0x3d, 0xef, 0x1b, 0xc2, 0xb5, 0x9d, 0xf1, 0x4b, 0xfb, 0x02, - 0x68, 0x86, 0xe5, 0xda, 0x17, 0x13, 0xf3, 0xc6, 0x5a, 0xb9, 0x08, 0x0b, 0x3c, 0xf0, 0x09, 0x0b, - 0x04, 0xd2, 0x34, 0xea, 0xdb, 0x95, 0xfa, 0xae, 0xaa, 0x90, 0x15, 0x80, 0xa6, 0xd9, 0x28, 0x19, - 0x96, 0x45, 0x7f, 0x67, 0xe8, 0x6f, 0x1e, 0x25, 0x64, 0xa7, 0x5d, 0x55, 0xb3, 0x52, 0xa0, 0x90, - 0x9c, 0xf6, 0x13, 0x05, 0xce, 0xa6, 0x4f, 0x25, 0x69, 0x01, 0x86, 0x8a, 0xe1, 0xe6, 0x03, 0x1f, - 0x9f, 0x39, 0xef, 0xa9, 0xe0, 0x78, 0xc8, 0x99, 0x31, 0x0b, 0x65, 0x92, 0x11, 0xba, 0x2f, 0xe6, - 0x1b, 0xed, 0x75, 0xcd, 0x8c, 0xd7, 0xd5, 0x4a, 0xb0, 0x39, 0x8d, 0x46, 0xb4, 0xab, 0xab, 0xb0, - 0xa8, 0x37, 0x9b, 0xd5, 0x4a, 0x49, 0x6f, 0x55, 0x1a, 0x75, 0x55, 0x21, 0x05, 0x98, 0xdb, 0x35, - 0x1b, 0xed, 0xa6, 0x9a, 0xd1, 0xbe, 0xa7, 0xc0, 0x72, 0x25, 0xb4, 0x5b, 0x7d, 0xbf, 0x9b, 0xef, - 0x13, 0x91, 0xcd, 0xb7, 0x19, 0x04, 0x55, 0x0a, 0x3e, 0x70, 0xa2, 0x9d, 0xf7, 0x5e, 0x06, 0xd6, - 0x12, 0x75, 0x88, 0x05, 0x0b, 0xfa, 0x03, 0xab, 0x51, 0xd9, 0x2e, 0xf1, 0x96, 0x5d, 0x0e, 0x0d, - 0xd9, 0x30, 0xcd, 0x5e, 0xe2, 0x2b, 0x2c, 0x10, 0xc1, 0x13, 0xdf, 0x1e, 0x78, 0xdd, 0x4e, 0xc4, - 0x82, 0x51, 0x50, 0xc2, 0x9b, 0xec, 0x1b, 0x93, 0x91, 0x8b, 0x64, 0x33, 0x11, 0xb9, 0x6e, 0x00, - 0x4f, 0x12, 0x46, 0xe3, 0x48, 0x87, 0x96, 0x27, 0x49, 0x87, 0xf4, 0x48, 0x1d, 0xe6, 0x77, 0xbd, - 0x71, 0x79, 0xf2, 0x98, 0xef, 0xdf, 0x4b, 0x61, 0xd2, 0xb5, 0xf2, 0xe4, 0x71, 0x92, 0x2c, 0x8a, - 0x2c, 0x59, 0xd0, 0xb0, 0x08, 0x49, 0x4e, 0x25, 0xee, 0x3b, 0x9d, 0x7b, 0x26, 0xdf, 0xe9, 0xad, - 0x65, 0x58, 0xe4, 0x6f, 0x28, 0x7c, 0x9e, 0xfc, 0x48, 0x81, 0xcd, 0x69, 0x23, 0x47, 0x9f, 0x65, - 0xd1, 0x18, 0x29, 0x67, 0x83, 0xac, 0x3c, 0xd1, 0xe0, 0x28, 0x02, 0x8d, 0x7c, 0x06, 0x16, 0x99, - 0x95, 0x96, 0xf5, 0x4a, 0xdb, 0xac, 0xf0, 0xe5, 0x7a, 0xf1, 0x5f, 0xde, 0xbd, 0xbc, 0xc1, 0x0d, - 0xbb, 0xfc, 0x57, 0xec, 0xc9, 0xc8, 0x8b, 0x64, 0x30, 0x91, 0x6b, 0x50, 0x2e, 0xda, 0x99, 0x74, - 0x3d, 0x57, 0xbc, 0x21, 0x44, 0x1c, 0x09, 0x0e, 0x93, 0xef, 0x34, 0x01, 0xd3, 0xbe, 0xad, 0xc0, - 0xb9, 0xe9, 0xd3, 0x44, 0xef, 0xc9, 0x16, 0x33, 0x76, 0x13, 0x91, 0x1c, 0xf0, 0x9e, 0x0c, 0x2c, - 0xe2, 0x64, 0x9a, 0x02, 0x91, 0x56, 0xe2, 0x12, 0x2e, 0x21, 0x24, 0x91, 0xd3, 0xf0, 0x47, 0x2b, - 0x09, 0x44, 0xed, 0x21, 0x6c, 0x4c, 0x99, 0x54, 0xf2, 0xe9, 0xd4, 0x5c, 0x5f, 0xe8, 0xe8, 0x28, - 0xe7, 0xfa, 0x8a, 0x24, 0x8d, 0x94, 0xe0, 0xda, 0xbf, 0x66, 0xe0, 0x2c, 0xdd, 0x5d, 0x3d, 0xd7, - 0xf7, 0xf5, 0x30, 0x2d, 0x36, 0x3d, 0x15, 0x5f, 0x83, 0xf9, 0xc3, 0x67, 0x13, 0x15, 0x33, 0x74, - 0x42, 0x00, 0x6f, 0x2c, 0xe1, 0x5e, 0x47, 0xff, 0x27, 0x57, 0x00, 0xa4, 0xc4, 0xe8, 0x59, 0x8c, - 0xaa, 0x9c, 0xd9, 0x54, 0xcc, 0xc2, 0x30, 0x48, 0x7f, 0xfe, 0x3a, 0xcc, 0xa1, 0x3c, 0x85, 0xdf, - 0x1d, 0x82, 0xe7, 0x4f, 0x6f, 0x1d, 0x4a, 0x5b, 0x4c, 0x56, 0x81, 0x7c, 0x0c, 0x20, 0x4c, 0x48, - 0xc3, 0x2f, 0x07, 0x21, 0x67, 0x08, 0x72, 0xd2, 0x98, 0x85, 0xa3, 0x7d, 0x87, 0x67, 0x79, 0x29, - 0xc2, 0x9a, 0x18, 0xf1, 0xa1, 0x08, 0xc6, 0xca, 0xb5, 0x98, 0xab, 0xac, 0xa0, 0x32, 0x14, 0x01, - 0x59, 0xaf, 0x25, 0xf2, 0xc2, 0x63, 0x4c, 0xf6, 0x58, 0xf2, 0xf7, 0x6b, 0x89, 0xe4, 0xef, 0x79, - 0x86, 0x25, 0x67, 0x78, 0xd7, 0xfe, 0x31, 0x03, 0x85, 0x07, 0x94, 0x2b, 0x43, 0x59, 0xc3, 0x6c, - 0xd9, 0xc5, 0x1d, 0x58, 0xac, 0x0e, 0x1c, 0xae, 0x2e, 0xe2, 0x5e, 0x69, 0xcc, 0xc6, 0xba, 0x37, - 0x70, 0x84, 0xe6, 0xc9, 0x37, 0x65, 0xa4, 0xa7, 0x84, 0xc1, 0xb8, 0x07, 0xf3, 0x4c, 0x7d, 0xc7, - 0xc5, 0x68, 0x82, 0x2f, 0x0f, 0x5a, 0xf4, 0x12, 0x2b, 0x96, 0x34, 0x1c, 0x4c, 0x05, 0x28, 0x33, - 0x89, 0xdc, 0xe0, 0x5a, 0x92, 0xac, 0xcc, 0x9d, 0x4c, 0xb2, 0x22, 0x85, 0xd0, 0x9c, 0x3f, 0x49, - 0x08, 0xcd, 0x73, 0x77, 0x61, 0x51, 0x6a, 0xcf, 0x33, 0xb1, 0xe9, 0xdf, 0xca, 0xc0, 0x32, 0xf6, - 0x2a, 0xb0, 0xe5, 0xf9, 0xd5, 0x94, 0x13, 0x7d, 0x22, 0x22, 0x27, 0xda, 0x94, 0xe7, 0x8b, 0xf5, - 0x6c, 0x86, 0x80, 0xe8, 0x1e, 0xac, 0x25, 0x10, 0xc9, 0xab, 0x30, 0x47, 0x9b, 0x2f, 0xde, 0xd5, - 0x6a, 0x7c, 0x05, 0x84, 0xe1, 0xd6, 0x69, 0xc7, 0x7d, 0x93, 0x61, 0x6b, 0xff, 0xa1, 0xc0, 0x12, - 0xcf, 0x76, 0xd4, 0xdf, 0x1f, 0x3c, 0x75, 0x38, 0x6f, 0xc4, 0x87, 0x93, 0x05, 0x75, 0xe2, 0xc3, - 0xf9, 0xdf, 0x3d, 0x88, 0x77, 0x23, 0x83, 0xb8, 0x11, 0x04, 0x5f, 0x15, 0xdd, 0x99, 0x31, 0x86, - 0x3f, 0xc4, 0x70, 0xe4, 0x51, 0x44, 0xf2, 0x65, 0x28, 0xd4, 0xdd, 0x27, 0x91, 0xe7, 0xe9, 0x8d, - 0x29, 0x44, 0x5f, 0x0a, 0x10, 0xd9, 0x9e, 0x62, 0x6e, 0x0f, 0xee, 0x13, 0x3b, 0xa1, 0x39, 0x0c, - 0x49, 0xd2, 0x17, 0x6a, 0xb4, 0xda, 0xb3, 0x2c, 0x7d, 0xee, 0x22, 0x8f, 0x71, 0xca, 0xbe, 0x93, - 0x05, 0x08, 0xbd, 0x8b, 0xe9, 0x06, 0x8c, 0x18, 0x4d, 0x08, 0xc9, 0x3e, 0x82, 0xe4, 0x35, 0x2e, - 0x6c, 0x29, 0x6e, 0x70, 0x09, 0x74, 0x66, 0x7a, 0x70, 0x5c, 0x94, 0x45, 0x97, 0xb8, 0x3b, 0x6b, - 0xd7, 0xed, 0x39, 0xec, 0x6c, 0xcf, 0x6e, 0x5d, 0xc3, 0x58, 0xe8, 0x01, 0x74, 0x4a, 0x96, 0x7b, - 0x74, 0x7a, 0xdd, 0xa6, 0x08, 0x09, 0x8f, 0xfd, 0xdc, 0xb3, 0x79, 0xec, 0x37, 0xa1, 0xe0, 0xf5, - 0xdf, 0x72, 0xfb, 0xe3, 0xc1, 0xe8, 0x18, 0xc5, 0xee, 0xa1, 0x3c, 0x8f, 0x0e, 0x41, 0x45, 0x94, - 0xb1, 0x79, 0xc0, 0x3b, 0x37, 0xc0, 0x97, 0xa7, 0x21, 0x00, 0x06, 0x11, 0x07, 0xe6, 0xd4, 0xf9, - 0x7b, 0xb9, 0xfc, 0xbc, 0xba, 0x70, 0x2f, 0x97, 0xcf, 0xab, 0x85, 0x7b, 0xb9, 0x7c, 0x41, 0x05, - 0x53, 0xd2, 0x99, 0x05, 0x3a, 0x31, 0x49, 0x8d, 0x15, 0x55, 0x51, 0x69, 0xbf, 0xc8, 0x00, 0x49, - 0x36, 0x83, 0x7c, 0x02, 0x16, 0xd9, 0x01, 0x6b, 0x8f, 0xfc, 0xaf, 0x71, 0x47, 0x10, 0x16, 0xed, - 0x4d, 0x02, 0xcb, 0xd1, 0xde, 0x18, 0xd8, 0xf4, 0xbf, 0xd6, 0x23, 0x5f, 0x82, 0xd3, 0x38, 0xbc, - 0x43, 0x77, 0xe4, 0x0d, 0xba, 0x36, 0x86, 0xe6, 0x76, 0x7a, 0x3c, 0x23, 0xed, 0x8b, 0x98, 0x3a, - 0x3d, 0x59, 0x3c, 0x65, 0x1a, 0xd0, 0x89, 0xb8, 0x89, 0x98, 0x4d, 0x86, 0x48, 0x5a, 0xa0, 0xca, - 0xf5, 0xf7, 0x27, 0xbd, 0x1e, 0x9f, 0xd9, 0x22, 0x7d, 0xd1, 0xc7, 0xcb, 0xa6, 0x10, 0x5e, 0x09, - 0x09, 0xef, 0x4c, 0x7a, 0x3d, 0xf2, 0x1a, 0xc0, 0xa0, 0x6f, 0x1f, 0x79, 0xbe, 0xcf, 0x94, 0x39, - 0x81, 0x2b, 0x50, 0x08, 0x95, 0x27, 0x63, 0xd0, 0xaf, 0x31, 0x20, 0xf9, 0x3f, 0x80, 0x41, 0x62, - 0x30, 0x7a, 0x12, 0xb3, 0x46, 0xe2, 0x49, 0xa3, 0x04, 0x30, 0x1a, 0x5e, 0xe1, 0xc0, 0xb5, 0xbc, - 0x6f, 0x08, 0x17, 0xbf, 0x2f, 0xc0, 0x1a, 0xb7, 0x97, 0x7e, 0xe0, 0x8d, 0x0f, 0xf9, 0x53, 0xe2, - 0xfd, 0xbc, 0x43, 0xa4, 0xb7, 0xc4, 0xdf, 0xe6, 0x00, 0xf4, 0x07, 0x96, 0x08, 0x4c, 0x78, 0x0b, - 0xe6, 0xe8, 0x03, 0x49, 0x08, 0x5a, 0x50, 0x4c, 0x8d, 0x74, 0x65, 0x31, 0x35, 0x62, 0xd0, 0xdd, - 0x68, 0xa2, 0xbb, 0x83, 0x10, 0xb2, 0xe0, 0x6e, 0x64, 0x1e, 0x10, 0x91, 0xc0, 0xf0, 0x1c, 0x8b, - 0x54, 0x01, 0xc2, 0x50, 0x81, 0x9c, 0xe5, 0x5f, 0x0b, 0x63, 0x6e, 0xf1, 0x02, 0x9e, 0x9c, 0x26, - 0x0c, 0x37, 0x28, 0x2f, 0x9f, 0x10, 0x8d, 0xdc, 0x87, 0x5c, 0xcb, 0x09, 0xbc, 0xf9, 0xa7, 0x04, - 0x50, 0x7c, 0x9e, 0x67, 0x0c, 0x0e, 0x83, 0x28, 0xae, 0x8c, 0x9d, 0x48, 0x62, 0x75, 0x24, 0x42, - 0x0c, 0x98, 0x6f, 0x3a, 0x23, 0xe7, 0xc8, 0x9f, 0x16, 0x78, 0x97, 0x95, 0x8a, 0x70, 0xfb, 0x08, - 0x94, 0x79, 0x0a, 0x56, 0x4c, 0xee, 0x40, 0xd6, 0xb2, 0x6a, 0x3c, 0x6c, 0xd0, 0x72, 0xf8, 0xfc, - 0xb2, 0xac, 0x1a, 0xd3, 0xfb, 0xfa, 0xfe, 0x91, 0x54, 0x8d, 0x22, 0x93, 0x4f, 0xc2, 0xa2, 0xc4, - 0x14, 0xf3, 0x80, 0x5b, 0x38, 0x06, 0x92, 0xbf, 0xa4, 0x7c, 0x68, 0x48, 0xd8, 0xa4, 0x0a, 0xea, - 0xfd, 0xc9, 0x63, 0x57, 0x1f, 0x0e, 0xd1, 0x91, 0xfa, 0x2d, 0x77, 0xc4, 0xd8, 0xb6, 0x7c, 0x18, - 0xa9, 0x1e, 0xbd, 0x57, 0xba, 0xa2, 0x54, 0x16, 0x36, 0xc5, 0x6b, 0x92, 0x26, 0xac, 0x59, 0xee, - 0x78, 0x32, 0x64, 0xf6, 0x35, 0x3b, 0x83, 0x11, 0x7d, 0xdf, 0xb0, 0xf0, 0x5c, 0x18, 0xd4, 0xdb, - 0xa7, 0x85, 0xc2, 0xa8, 0x69, 0x7f, 0x30, 0x8a, 0xbd, 0x75, 0x92, 0x95, 0x35, 0x57, 0x9e, 0x72, - 0x7a, 0xab, 0x46, 0x5f, 0x4d, 0x78, 0xab, 0x8a, 0x57, 0x53, 0xf8, 0x56, 0xfa, 0x58, 0x4a, 0x08, - 0x49, 0xd4, 0x0c, 0x4a, 0x21, 0x24, 0x23, 0x81, 0x23, 0xdf, 0xc9, 0x49, 0x51, 0x8c, 0xf9, 0x5c, - 0xbc, 0x01, 0x70, 0x6f, 0xe0, 0xf5, 0x6b, 0xee, 0xf8, 0x70, 0xd0, 0x95, 0x22, 0x59, 0x2e, 0x7e, - 0x75, 0xe0, 0xf5, 0xed, 0x23, 0x04, 0xff, 0xe2, 0xdd, 0xcb, 0x12, 0x92, 0x29, 0xfd, 0x4f, 0x3e, - 0x0a, 0x05, 0xfa, 0xab, 0x15, 0x5a, 0x09, 0x31, 0x99, 0x2c, 0xd6, 0x66, 0xb9, 0x7e, 0x42, 0x04, - 0x72, 0x17, 0xb3, 0x5b, 0x79, 0xc3, 0xb1, 0xc4, 0xbc, 0x8a, 0x54, 0x56, 0xde, 0x70, 0x1c, 0x0f, - 0x4c, 0x2f, 0x21, 0x93, 0x72, 0xd0, 0x74, 0x91, 0x90, 0x8e, 0x27, 0xd1, 0x42, 0xc1, 0x23, 0x5f, - 0x6b, 0xb6, 0x88, 0x88, 0x2d, 0xbb, 0x68, 0xc6, 0xaa, 0x61, 0x23, 0xac, 0xf2, 0x36, 0xd3, 0x14, - 0x71, 0xa6, 0x96, 0x35, 0xc2, 0x3f, 0xec, 0xda, 0x1d, 0x04, 0x47, 0x1a, 0x11, 0x20, 0x93, 0x2d, - 0x58, 0x65, 0x3c, 0x7e, 0x90, 0xd8, 0x96, 0xb3, 0xb8, 0x78, 0xb6, 0x85, 0x99, 0x6f, 0xe5, 0xcf, - 0xc7, 0x2a, 0x90, 0x1d, 0x98, 0xc3, 0xb7, 0x26, 0xf7, 0x86, 0x38, 0x2f, 0x8b, 0x09, 0xe2, 0xfb, - 0x08, 0xcf, 0x15, 0x14, 0x10, 0xc8, 0xe7, 0x0a, 0xa2, 0x92, 0xcf, 0x03, 0x18, 0xfd, 0xd1, 0xa0, - 0xd7, 0xc3, 0x98, 0xed, 0xf9, 0x88, 0x63, 0x2c, 0xa7, 0x83, 0x54, 0x42, 0x24, 0x1e, 0x5f, 0x14, - 0x7f, 0xdb, 0xb1, 0xc8, 0xee, 0x12, 0x2d, 0xad, 0x02, 0xf3, 0x6c, 0x33, 0x62, 0xfe, 0x03, 0x9e, - 0xd1, 0x49, 0x8a, 0x9e, 0xcf, 0xf2, 0x1f, 0x70, 0x78, 0x32, 0xff, 0x81, 0x54, 0x41, 0xbb, 0x0f, - 0xeb, 0x69, 0x1d, 0x8b, 0xbc, 0x8e, 0x95, 0x93, 0xbe, 0x8e, 0xbf, 0x9f, 0x85, 0x25, 0xa4, 0x26, - 0x4e, 0x61, 0x1d, 0x96, 0xad, 0xc9, 0xe3, 0x20, 0x38, 0xa0, 0x38, 0x8d, 0xb1, 0x7d, 0xbe, 0x5c, - 0x20, 0xeb, 0xf0, 0x22, 0x35, 0x88, 0x01, 0x2b, 0xe2, 0x26, 0xd8, 0x15, 0x9e, 0x03, 0x41, 0xea, - 0x01, 0xe1, 0x50, 0x91, 0x4c, 0xec, 0x1d, 0xab, 0x14, 0xde, 0x07, 0xd9, 0x67, 0xb9, 0x0f, 0x72, - 0x27, 0xba, 0x0f, 0x1e, 0xc1, 0x92, 0xf8, 0x1a, 0x9e, 0xe4, 0x73, 0xef, 0xef, 0x24, 0x8f, 0x10, - 0x23, 0xd5, 0xe0, 0x44, 0x9f, 0x9f, 0x79, 0xa2, 0xa3, 0x62, 0x54, 0xec, 0xb2, 0x21, 0xc2, 0x92, - 0x07, 0x3b, 0x66, 0xbe, 0xdd, 0x2d, 0x35, 0x7f, 0x89, 0x5b, 0xf2, 0x55, 0x28, 0x54, 0x07, 0x42, - 0x27, 0x26, 0x29, 0x23, 0x7a, 0x02, 0x28, 0xb3, 0x0b, 0x01, 0x66, 0x70, 0xbb, 0x65, 0x3f, 0x88, - 0xdb, 0xed, 0x2e, 0x00, 0x77, 0x49, 0x09, 0x33, 0x56, 0xe2, 0x96, 0x11, 0x31, 0x8e, 0xa2, 0x3a, - 0x11, 0x09, 0x99, 0x9e, 0x4e, 0xdc, 0xdc, 0x46, 0xb8, 0x70, 0xcb, 0x29, 0xde, 0x85, 0x0f, 0xbc, - 0xf0, 0x0a, 0x97, 0x8f, 0x87, 0x58, 0xb5, 0x0f, 0x76, 0x42, 0xc8, 0xe7, 0x02, 0xe3, 0xc7, 0x85, - 0x59, 0x23, 0xa4, 0x25, 0x46, 0x68, 0xaa, 0xc9, 0xa3, 0xf6, 0x13, 0x45, 0xce, 0xfb, 0xf2, 0x4b, - 0x4c, 0xf5, 0xeb, 0x00, 0x81, 0x51, 0x82, 0x98, 0xeb, 0xc0, 0x4d, 0x9c, 0x41, 0xe5, 0x51, 0x0e, - 0x71, 0xa5, 0xde, 0x64, 0x3f, 0xa8, 0xde, 0xb4, 0x60, 0xb1, 0xf1, 0xe6, 0xd8, 0x09, 0xad, 0x58, - 0xc0, 0x0a, 0x38, 0x59, 0x3c, 0x99, 0xb2, 0x5b, 0xd7, 0xf1, 0x6e, 0x08, 0xf9, 0xe0, 0x29, 0x2c, - 0xb0, 0x54, 0x51, 0xfb, 0x4b, 0x05, 0x56, 0xe5, 0xc0, 0x1d, 0xc7, 0xfd, 0x0e, 0xf9, 0x34, 0x0b, - 0x43, 0xad, 0x44, 0x9e, 0x2c, 0x12, 0x12, 0x3d, 0x72, 0x8f, 0xfb, 0x1d, 0xc6, 0x00, 0x39, 0x4f, - 0xe4, 0xc6, 0xd2, 0x8a, 0xe4, 0x31, 0x2c, 0x35, 0x07, 0xbd, 0x1e, 0x65, 0x6b, 0x46, 0x6f, 0xf1, - 0x07, 0x00, 0x25, 0x14, 0x57, 0x8d, 0x88, 0x06, 0x6d, 0x5d, 0xe5, 0xef, 0xdc, 0x8d, 0x21, 0x3d, - 0xef, 0x3d, 0x5e, 0x2f, 0x24, 0xfb, 0x36, 0xba, 0x06, 0xca, 0x34, 0xb5, 0x9f, 0x29, 0x40, 0x92, - 0x4d, 0x92, 0x8f, 0x2c, 0xe5, 0x7f, 0x80, 0x85, 0x8d, 0xb1, 0x7e, 0xb9, 0x67, 0x61, 0xfd, 0x8a, - 0xbf, 0xa7, 0xc0, 0x6a, 0x45, 0xaf, 0xf1, 0x4c, 0x30, 0x4c, 0x83, 0x73, 0x05, 0x2e, 0x56, 0xf4, - 0x9a, 0xdd, 0x6c, 0x54, 0x2b, 0xa5, 0x87, 0x76, 0x6a, 0x80, 0xf7, 0x8b, 0xf0, 0x5c, 0x12, 0x25, - 0xd4, 0xf4, 0x5c, 0x80, 0xcd, 0x64, 0xb1, 0x08, 0x02, 0x9f, 0x5e, 0x59, 0xc4, 0x8b, 0xcf, 0x16, - 0x3f, 0x03, 0xab, 0x22, 0xe0, 0x79, 0xab, 0x6a, 0x61, 0x4a, 0x95, 0x55, 0x58, 0xdc, 0x33, 0xcc, - 0xca, 0xce, 0x43, 0x7b, 0xa7, 0x5d, 0xad, 0xaa, 0xa7, 0xc8, 0x32, 0x14, 0x38, 0xa0, 0xa4, 0xab, - 0x0a, 0x59, 0x82, 0x7c, 0xa5, 0x6e, 0x19, 0xa5, 0xb6, 0x69, 0xa8, 0x99, 0xe2, 0x67, 0x60, 0xa5, - 0x39, 0xf2, 0xde, 0x72, 0xc6, 0xee, 0x7d, 0xf7, 0x18, 0x15, 0x35, 0x0b, 0x90, 0x35, 0xf5, 0x07, - 0xea, 0x29, 0x02, 0x30, 0xdf, 0xbc, 0x5f, 0xb2, 0x6e, 0xdf, 0x56, 0x15, 0xb2, 0x08, 0x0b, 0xbb, - 0xa5, 0xa6, 0x7d, 0xbf, 0x66, 0xa9, 0x19, 0xfa, 0x43, 0x7f, 0x60, 0xe1, 0x8f, 0x6c, 0xf1, 0x65, - 0x58, 0x43, 0x86, 0xa4, 0xea, 0xf9, 0x63, 0xb7, 0xef, 0x8e, 0xb0, 0x0d, 0x4b, 0x90, 0xb7, 0x5c, - 0x7a, 0x92, 0x8c, 0x5d, 0xd6, 0x80, 0xda, 0xa4, 0x37, 0xf6, 0x86, 0x3d, 0xf7, 0xeb, 0xaa, 0x52, - 0xbc, 0x0b, 0xab, 0xe6, 0x60, 0x32, 0xf6, 0xfa, 0x07, 0xd6, 0x98, 0x62, 0x1c, 0x1c, 0x93, 0x33, - 0xb0, 0xd6, 0xae, 0xeb, 0xb5, 0xad, 0xca, 0x6e, 0xbb, 0xd1, 0xb6, 0xec, 0x9a, 0xde, 0x2a, 0x95, - 0x99, 0x9a, 0xa8, 0xd6, 0xb0, 0x5a, 0xb6, 0x69, 0x94, 0x8c, 0x7a, 0x4b, 0x55, 0x8a, 0xdf, 0x45, - 0xd9, 0x4a, 0x67, 0xd0, 0xef, 0xee, 0x38, 0x9d, 0xf1, 0x60, 0x84, 0x0d, 0xd6, 0xe0, 0x92, 0x65, - 0x94, 0x1a, 0xf5, 0x6d, 0x7b, 0x47, 0x2f, 0xb5, 0x1a, 0x66, 0x5a, 0x86, 0x81, 0x73, 0x70, 0x36, - 0x05, 0xa7, 0xd1, 0x6a, 0xaa, 0x0a, 0xb9, 0x0c, 0xe7, 0x53, 0xca, 0x1e, 0x18, 0x5b, 0x7a, 0xbb, - 0x55, 0xae, 0xab, 0x99, 0x29, 0x95, 0x2d, 0xab, 0xa1, 0x66, 0x8b, 0xbf, 0xa5, 0xc0, 0x4a, 0xdb, - 0xe7, 0x26, 0xe7, 0x6d, 0x74, 0xb0, 0x7d, 0x1e, 0x2e, 0xb4, 0x2d, 0xc3, 0xb4, 0x5b, 0x8d, 0xfb, - 0x46, 0xdd, 0x6e, 0x5b, 0xfa, 0x6e, 0xbc, 0x35, 0x97, 0xe1, 0xbc, 0x84, 0x61, 0x1a, 0xa5, 0xc6, - 0x9e, 0x61, 0xda, 0x4d, 0xdd, 0xb2, 0x1e, 0x34, 0xcc, 0x6d, 0x55, 0xa1, 0x5f, 0x4c, 0x41, 0xa8, - 0xed, 0xe8, 0xac, 0x35, 0x91, 0xb2, 0xba, 0xf1, 0x40, 0xaf, 0xda, 0x5b, 0x8d, 0x96, 0x9a, 0x2d, - 0xd6, 0xe8, 0xfd, 0x8e, 0x71, 0xbe, 0x99, 0x65, 0x61, 0x1e, 0x72, 0xf5, 0x46, 0xdd, 0x88, 0x2b, - 0x17, 0x97, 0x20, 0xaf, 0x37, 0x9b, 0x66, 0x63, 0x0f, 0x97, 0x18, 0xc0, 0xfc, 0xb6, 0x51, 0xa7, - 0x2d, 0xcb, 0xd2, 0x92, 0xa6, 0xd9, 0xa8, 0x35, 0x5a, 0xc6, 0xb6, 0x9a, 0x2b, 0x9a, 0x62, 0x0b, - 0x0b, 0xa2, 0x9d, 0x01, 0xd3, 0xe4, 0x6d, 0x1b, 0x3b, 0x7a, 0xbb, 0xda, 0xe2, 0x53, 0xf4, 0xd0, - 0x36, 0x8d, 0xcf, 0xb5, 0x0d, 0xab, 0x65, 0xa9, 0x0a, 0x51, 0x61, 0xa9, 0x6e, 0x18, 0xdb, 0x96, - 0x6d, 0x1a, 0x7b, 0x15, 0xe3, 0x81, 0x9a, 0xa1, 0x34, 0xd9, 0xff, 0xf4, 0x0b, 0xc5, 0x77, 0x14, - 0x20, 0x2c, 0x46, 0xba, 0x48, 0xbc, 0x85, 0x2b, 0xe6, 0x12, 0x9c, 0x2b, 0xd3, 0xa9, 0xc6, 0xae, - 0xd5, 0x1a, 0xdb, 0xf1, 0x21, 0x3b, 0x0b, 0x24, 0x56, 0xde, 0xd8, 0xd9, 0x51, 0x15, 0x72, 0x1e, - 0x4e, 0xc7, 0xe0, 0xdb, 0x66, 0xa3, 0xa9, 0x66, 0xce, 0x65, 0xf2, 0x0a, 0xd9, 0x48, 0x14, 0xde, - 0x37, 0x8c, 0xa6, 0x9a, 0xa5, 0x53, 0x14, 0x2b, 0x10, 0x5b, 0x82, 0x55, 0xcf, 0x15, 0xbf, 0xad, - 0xc0, 0x59, 0xd6, 0x4c, 0xb1, 0xbf, 0x82, 0xa6, 0x5e, 0x80, 0x4d, 0x9e, 0xf9, 0x21, 0xad, 0xa1, - 0xeb, 0xa0, 0x46, 0x4a, 0x59, 0x33, 0xcf, 0xc0, 0x5a, 0x04, 0x8a, 0xed, 0xc8, 0xd0, 0xd3, 0x23, - 0x02, 0xde, 0x32, 0xac, 0x96, 0x6d, 0xec, 0xec, 0x34, 0xcc, 0x16, 0x6b, 0x48, 0xb6, 0xa8, 0xc1, - 0x5a, 0xc9, 0x1d, 0x8d, 0xe9, 0xd3, 0xab, 0xef, 0x7b, 0x83, 0x3e, 0x36, 0x61, 0x19, 0x0a, 0xc6, - 0xe7, 0x5b, 0x46, 0xdd, 0xaa, 0x34, 0xea, 0xea, 0xa9, 0xe2, 0x85, 0x18, 0x8e, 0xd8, 0xc7, 0x96, - 0x55, 0x56, 0x4f, 0x15, 0x1d, 0x58, 0x16, 0x86, 0xd7, 0x6c, 0x55, 0x5c, 0x82, 0x73, 0x62, 0xad, - 0xe1, 0x89, 0x12, 0xef, 0xc2, 0x26, 0xac, 0x27, 0xcb, 0x8d, 0x96, 0xaa, 0xd0, 0x59, 0x88, 0x95, - 0x50, 0x78, 0xa6, 0xf8, 0xff, 0x15, 0x58, 0x0e, 0x94, 0x26, 0x28, 0xa6, 0xbd, 0x0c, 0xe7, 0x6b, - 0x3b, 0xba, 0xbd, 0x6d, 0xec, 0x55, 0x4a, 0x86, 0x7d, 0xbf, 0x52, 0xdf, 0x8e, 0x7d, 0xe4, 0x39, - 0x38, 0x93, 0x82, 0x80, 0x5f, 0xd9, 0x84, 0xf5, 0x78, 0x51, 0x8b, 0x6e, 0xd5, 0x0c, 0x1d, 0xfa, - 0x78, 0x49, 0xb0, 0x4f, 0xb3, 0xc5, 0x3d, 0x58, 0xb1, 0xf4, 0x5a, 0x75, 0x67, 0x30, 0xea, 0xb8, - 0xfa, 0x64, 0x7c, 0xd8, 0x27, 0xe7, 0x61, 0x63, 0xa7, 0x61, 0x96, 0x0c, 0x1b, 0x51, 0x62, 0x2d, - 0x38, 0x0d, 0xab, 0x72, 0xe1, 0x43, 0x83, 0x2e, 0x5f, 0x02, 0x2b, 0x32, 0xb0, 0xde, 0x50, 0x33, - 0xc5, 0x2f, 0xc2, 0x52, 0x24, 0xff, 0xe6, 0x06, 0x9c, 0x96, 0x7f, 0x37, 0xdd, 0x7e, 0xd7, 0xeb, - 0x1f, 0xa8, 0xa7, 0xe2, 0x05, 0xe6, 0xa4, 0xdf, 0xa7, 0x05, 0xb8, 0x9f, 0xe5, 0x82, 0x96, 0x3b, - 0x3a, 0xf2, 0xfa, 0xce, 0xd8, 0xed, 0xaa, 0x99, 0xe2, 0x4b, 0xb0, 0x1c, 0x89, 0xfa, 0x4f, 0x27, - 0xae, 0xda, 0xe0, 0x07, 0x70, 0xcd, 0xd8, 0xae, 0xb4, 0x6b, 0xea, 0x1c, 0xdd, 0xc9, 0xe5, 0xca, - 0x6e, 0x59, 0x85, 0xe2, 0xf7, 0x14, 0xfa, 0xce, 0xc0, 0x5c, 0x5e, 0xb5, 0x1d, 0x5d, 0x4c, 0x35, - 0x5d, 0x66, 0x2c, 0x97, 0x88, 0x61, 0x59, 0x4c, 0xa7, 0x7e, 0x01, 0x36, 0xf9, 0x0f, 0x5b, 0xaf, - 0x6f, 0xdb, 0x65, 0xdd, 0xdc, 0x7e, 0xa0, 0x9b, 0x74, 0xed, 0x3d, 0x54, 0x33, 0xb8, 0xa1, 0x24, - 0x88, 0xdd, 0x6a, 0xb4, 0x4b, 0x65, 0x35, 0x4b, 0xd7, 0x6f, 0x04, 0xde, 0xac, 0xd4, 0xd5, 0x1c, - 0x6e, 0xcf, 0x04, 0x36, 0x92, 0xa5, 0xe5, 0x73, 0xc5, 0xf7, 0x14, 0xd8, 0xb0, 0xbc, 0x83, 0xbe, - 0x33, 0x9e, 0x8c, 0x5c, 0xbd, 0x77, 0x30, 0x18, 0x79, 0xe3, 0xc3, 0x23, 0x6b, 0xe2, 0x8d, 0x5d, - 0x72, 0x0b, 0xae, 0x5b, 0x95, 0xdd, 0xba, 0xde, 0xa2, 0xdb, 0x4b, 0xaf, 0xee, 0x36, 0xcc, 0x4a, - 0xab, 0x5c, 0xb3, 0xad, 0x76, 0x25, 0xb1, 0xf2, 0xae, 0xc1, 0xf3, 0xd3, 0x51, 0xab, 0xc6, 0xae, - 0x5e, 0x7a, 0xa8, 0x2a, 0xb3, 0x09, 0x6e, 0xe9, 0x55, 0xbd, 0x5e, 0x32, 0xb6, 0xed, 0xbd, 0xdb, - 0x6a, 0x86, 0x5c, 0x87, 0x2b, 0xd3, 0x51, 0x77, 0x2a, 0x4d, 0x8b, 0xa2, 0x65, 0x67, 0x7f, 0xb7, - 0x6c, 0xd5, 0x28, 0x56, 0xae, 0xf8, 0x27, 0x0a, 0x6c, 0x4e, 0x8b, 0xe2, 0x46, 0x6e, 0x80, 0x66, - 0xd4, 0x5b, 0xa6, 0x5e, 0xd9, 0xb6, 0x4b, 0xa6, 0xb1, 0x6d, 0xd4, 0x5b, 0x15, 0xbd, 0x6a, 0xd9, - 0x56, 0xa3, 0x4d, 0x57, 0x53, 0x68, 0xfa, 0x70, 0x15, 0x2e, 0xcf, 0xc0, 0x6b, 0x54, 0xb6, 0x4b, - 0xaa, 0x42, 0x6e, 0xc3, 0x8b, 0x33, 0x90, 0xac, 0x87, 0x56, 0xcb, 0xa8, 0xc9, 0x25, 0x6a, 0x06, - 0x0f, 0xac, 0xf4, 0x20, 0x56, 0xb4, 0x77, 0x58, 0x32, 0xbb, 0x61, 0x57, 0xe0, 0xe2, 0x54, 0x2c, - 0xde, 0xac, 0xab, 0x70, 0x79, 0x2a, 0x0a, 0x6b, 0x94, 0x9a, 0x29, 0x96, 0xe0, 0xdc, 0xf4, 0x38, - 0x3e, 0xf4, 0xbe, 0x88, 0x4e, 0x79, 0x1e, 0x72, 0xdb, 0xf4, 0x8a, 0x8a, 0xe4, 0xbe, 0x29, 0x7a, - 0xa0, 0xc6, 0x63, 0x5c, 0x24, 0x8c, 0x65, 0xcc, 0x76, 0xbd, 0xce, 0xee, 0xb3, 0x55, 0x58, 0x6c, - 0xb4, 0xca, 0x86, 0xc9, 0xb3, 0x07, 0x61, 0xba, 0xa0, 0x76, 0x9d, 0xee, 0xe0, 0x86, 0x59, 0xf9, - 0x02, 0x5e, 0x6c, 0x9b, 0xb0, 0x6e, 0x55, 0xf5, 0xd2, 0x7d, 0xbb, 0xde, 0x68, 0xd9, 0x95, 0xba, - 0x5d, 0x2a, 0xeb, 0xf5, 0xba, 0x51, 0x55, 0x01, 0x67, 0x75, 0x9a, 0x93, 0x27, 0xf9, 0x28, 0xdc, - 0x6c, 0xdc, 0x6f, 0xe9, 0x76, 0xb3, 0xda, 0xde, 0xad, 0xd4, 0x6d, 0xeb, 0x61, 0xbd, 0x24, 0x98, - 0xb0, 0x52, 0xf2, 0xec, 0xbf, 0x09, 0xd7, 0x66, 0x62, 0x87, 0x79, 0x7e, 0x6e, 0x80, 0x36, 0x13, - 0x93, 0x77, 0xa4, 0xf8, 0x53, 0x05, 0xce, 0xcf, 0x50, 0x66, 0x93, 0x17, 0xe1, 0x56, 0xd9, 0xd0, - 0xb7, 0xab, 0x86, 0x65, 0xe1, 0x89, 0x45, 0x27, 0x85, 0x19, 0xd5, 0xa4, 0x9e, 0xec, 0xb7, 0xe0, - 0xfa, 0x6c, 0xf4, 0x90, 0x47, 0xb8, 0x09, 0xd7, 0x66, 0xa3, 0x72, 0x9e, 0x21, 0x43, 0x8a, 0x70, - 0x63, 0x36, 0x66, 0xc0, 0x6b, 0x64, 0x8b, 0xbf, 0xa3, 0xc0, 0xd9, 0x74, 0x89, 0x12, 0x6d, 0x5b, - 0xa5, 0x6e, 0xb5, 0xf4, 0x6a, 0xd5, 0x6e, 0xea, 0xa6, 0x5e, 0xb3, 0x8d, 0xba, 0xd9, 0xa8, 0x56, - 0xd3, 0xee, 0xd8, 0x6b, 0xf0, 0xfc, 0x74, 0x54, 0xab, 0x64, 0x56, 0x9a, 0xf4, 0x1a, 0xd1, 0xe0, - 0xd2, 0x74, 0x2c, 0xa3, 0x52, 0x32, 0xd4, 0xcc, 0xd6, 0x1b, 0x3f, 0xfe, 0x87, 0x4b, 0xa7, 0x7e, - 0xfc, 0xde, 0x25, 0xe5, 0x67, 0xef, 0x5d, 0x52, 0xfe, 0xfe, 0xbd, 0x4b, 0xca, 0x17, 0x5e, 0x38, - 0x59, 0x8a, 0x3c, 0x7c, 0x80, 0x3c, 0x9e, 0xc7, 0xa7, 0xd2, 0x2b, 0xff, 0x15, 0x00, 0x00, 0xff, - 0xff, 0x56, 0x72, 0x84, 0x31, 0xe8, 0xc2, 0x01, 0x00, + 0xf5, 0xdb, 0x73, 0xc8, 0xc2, 0xff, 0xc7, 0xde, 0xb7, 0xc5, 0xb8, 0x91, 0x5c, 0x87, 0xaa, 0x49, + 0xce, 0x0c, 0x79, 0xe6, 0xd5, 0x53, 0x1a, 0x69, 0x66, 0xf5, 0x5c, 0xb5, 0x1e, 0x96, 0xb8, 0xde, + 0xf5, 0x4a, 0x7b, 0xd7, 0xbb, 0xb2, 0xbd, 0xb6, 0x7b, 0x38, 0x3d, 0x43, 0x4a, 0x7c, 0xb9, 0x9b, + 0x1c, 0x59, 0x96, 0xed, 0x76, 0x8b, 0xec, 0x99, 0x69, 0x2f, 0x87, 0xa4, 0xd9, 0xe4, 0xca, 0x63, + 0x5c, 0xe0, 0xda, 0xb8, 0xb8, 0x36, 0x70, 0xf3, 0x70, 0xe2, 0x24, 0xc8, 0xc2, 0x3f, 0xfe, 0xc8, + 0x22, 0xc8, 0x87, 0xf3, 0x1f, 0xc4, 0x5f, 0xfe, 0x33, 0x60, 0x18, 0x30, 0x90, 0x3f, 0x27, 0x58, + 0x24, 0x0b, 0x24, 0x40, 0x1e, 0x7f, 0x41, 0xf2, 0x61, 0x20, 0x40, 0x50, 0xa7, 0xaa, 0xba, 0xab, + 0x1f, 0xa4, 0x46, 0xde, 0xdd, 0x24, 0x06, 0xfc, 0x35, 0xc3, 0x53, 0xa7, 0x4e, 0xd7, 0xbb, 0x4e, + 0x9d, 0x27, 0xe4, 0x87, 0x23, 0x6f, 0x80, 0xbc, 0x2d, 0x4f, 0xd1, 0x20, 0x7e, 0x63, 0xf6, 0x05, + 0x64, 0xc2, 0xc6, 0xce, 0x01, 0xf7, 0x0a, 0x31, 0x0b, 0x08, 0x69, 0x39, 0x07, 0x3e, 0x79, 0x01, + 0xd6, 0xba, 0xee, 0xbe, 0x33, 0xe9, 0x8d, 0x6d, 0xbf, 0x73, 0xe8, 0x76, 0xd1, 0x6f, 0x0b, 0xad, + 0xfd, 0x4c, 0x95, 0x17, 0x58, 0x02, 0x9e, 0x68, 0xf1, 0xdc, 0x94, 0x16, 0xdf, 0xcb, 0xe5, 0x15, + 0x35, 0x63, 0xa2, 0x79, 0x95, 0xf6, 0xcd, 0x0c, 0x6c, 0x4e, 0xdb, 0x64, 0xe4, 0x8d, 0xb4, 0x31, + 0x60, 0xda, 0x0e, 0x19, 0x2e, 0x6b, 0x3b, 0xa4, 0xaf, 0x91, 0x3b, 0x10, 0x78, 0x5d, 0x3d, 0x2d, + 0x82, 0x82, 0x80, 0xd1, 0x3a, 0x43, 0xc7, 0xf7, 0x9f, 0xd0, 0x73, 0x24, 0x2b, 0x45, 0xe1, 0xe5, + 0x30, 0xb9, 0x8e, 0x80, 0x91, 0xd7, 0x00, 0x3a, 0xbd, 0x81, 0xef, 0xa2, 0x51, 0x01, 0x67, 0x50, + 0x98, 0x2d, 0x79, 0x00, 0x95, 0xb5, 0xc8, 0x08, 0x2d, 0x0d, 0xba, 0x2e, 0x9f, 0x40, 0x07, 0x36, + 0xa6, 0x9c, 0xaa, 0x74, 0x7a, 0xc2, 0x94, 0xf6, 0x22, 0x41, 0xd6, 0x24, 0x48, 0x6c, 0x1f, 0x1f, + 0xf1, 0xcc, 0xb4, 0x35, 0x72, 0x0c, 0x24, 0x79, 0x74, 0x52, 0xea, 0xdc, 0x22, 0x7a, 0x32, 0x0a, + 0xa8, 0x33, 0x48, 0x7b, 0xd4, 0x23, 0x97, 0x61, 0x51, 0x24, 0xc0, 0xa4, 0x0f, 0x00, 0x46, 0x1c, + 0x38, 0xe8, 0xbe, 0x8b, 0x8b, 0x07, 0xc3, 0xac, 0xa2, 0x6f, 0x1d, 0x67, 0x2d, 0x0a, 0x08, 0x69, + 0x1d, 0x0f, 0x45, 0xef, 0x2e, 0x88, 0xf5, 0x1d, 0xbd, 0xd0, 0x78, 0xe9, 0x1f, 0x29, 0x62, 0xfa, + 0x93, 0x37, 0xc2, 0xd3, 0xda, 0x47, 0x00, 0x5d, 0x9b, 0x78, 0xc3, 0xf0, 0x7f, 0xca, 0xea, 0x88, + 0x5d, 0xc7, 0x59, 0x1d, 0xfe, 0x93, 0xdc, 0x80, 0xd5, 0x11, 0x33, 0x7e, 0x1d, 0x0f, 0xf8, 0x78, + 0xb2, 0x64, 0x23, 0xcb, 0x0c, 0xdc, 0x1a, 0xe0, 0x98, 0xf2, 0x76, 0xdd, 0x0b, 0x06, 0x4c, 0xba, + 0x20, 0xc9, 0x4b, 0x50, 0xa0, 0x17, 0x24, 0x86, 0xe7, 0x89, 0xf9, 0x54, 0x20, 0x1e, 0xb2, 0x1b, + 0x66, 0xfe, 0xab, 0xfc, 0x7f, 0x4e, 0xeb, 0xed, 0x8c, 0x20, 0x26, 0x5f, 0xcf, 0x64, 0x03, 0x16, + 0x06, 0xa3, 0x03, 0xa9, 0x6b, 0xf3, 0x83, 0xd1, 0x01, 0xed, 0xd7, 0x4d, 0x50, 0x99, 0x8b, 0x0f, + 0x0b, 0xb5, 0xe0, 0x1f, 0xf7, 0xd9, 0xfb, 0x3d, 0x6f, 0xae, 0x30, 0x38, 0x66, 0xf9, 0x3f, 0xee, + 0x77, 0x28, 0xa6, 0xef, 0x0f, 0x6c, 0x39, 0x2a, 0x17, 0xef, 0xf6, 0x8a, 0xef, 0x0f, 0xc2, 0xf0, + 0x5c, 0x5d, 0xb2, 0x05, 0xcb, 0x94, 0x4e, 0x10, 0x1b, 0x8c, 0x73, 0x0f, 0x17, 0x93, 0xdc, 0xc3, + 0x71, 0xbf, 0x23, 0x9a, 0x68, 0x2e, 0xf9, 0xd2, 0x2f, 0x72, 0x1f, 0x54, 0x89, 0xcd, 0x42, 0x9f, + 0xcf, 0x98, 0x21, 0x76, 0x48, 0x46, 0x62, 0xcf, 0x2a, 0xfd, 0xfd, 0x81, 0xb9, 0xda, 0x89, 0x02, + 0xf8, 0xd0, 0xfc, 0x40, 0x11, 0x67, 0x69, 0x4a, 0x25, 0xa2, 0xc1, 0xf2, 0xa1, 0xe3, 0xdb, 0xbe, + 0x7f, 0xc4, 0x0c, 0xcb, 0x78, 0x34, 0xe2, 0xc5, 0x43, 0xc7, 0xb7, 0xfc, 0x23, 0x91, 0xed, 0xe4, + 0x0c, 0xc5, 0x19, 0x38, 0x93, 0xf1, 0xa1, 0x2d, 0x33, 0x8d, 0x6c, 0xc4, 0x4e, 0x1f, 0x3a, 0x7e, + 0x83, 0x96, 0x49, 0xb4, 0xc9, 0x35, 0x58, 0x41, 0xba, 0x1d, 0x4f, 0x10, 0xc6, 0x70, 0x19, 0xe6, + 0x12, 0x25, 0xdc, 0xf1, 0x18, 0x65, 0xde, 0xc2, 0x7f, 0xcc, 0xc0, 0xd9, 0xf4, 0xd1, 0xc1, 0xe5, + 0x49, 0xc7, 0x14, 0x1d, 0xfb, 0x78, 0xdb, 0x0a, 0x14, 0xc2, 0x42, 0x9d, 0xa4, 0x4d, 0x4e, 0x26, + 0x75, 0x72, 0x8a, 0xb0, 0x86, 0x84, 0x38, 0x7b, 0xda, 0xf3, 0xfc, 0x31, 0x8f, 0xe0, 0x61, 0xae, + 0xd2, 0x02, 0x76, 0x9e, 0x57, 0x29, 0x98, 0x5c, 0x87, 0x15, 0x71, 0x22, 0x0f, 0x9e, 0xf4, 0xe9, + 0x87, 0xd9, 0x71, 0xbc, 0xcc, 0xa1, 0x0d, 0x04, 0x92, 0x33, 0x30, 0xef, 0x0c, 0x87, 0xf4, 0x93, + 0xec, 0x14, 0x9e, 0x73, 0x86, 0x43, 0x96, 0x91, 0x07, 0xdd, 0x18, 0xed, 0x7d, 0x34, 0x2d, 0xe2, + 0x76, 0x8c, 0xe6, 0x12, 0x02, 0x99, 0xb9, 0x91, 0x4f, 0xf7, 0x3d, 0xad, 0x2b, 0x50, 0x16, 0x10, + 0x05, 0x9c, 0x61, 0x80, 0xf0, 0x1c, 0xe4, 0x85, 0x92, 0x9b, 0x79, 0x63, 0x98, 0x0b, 0x0e, 0x57, + 0x70, 0xbf, 0x0a, 0x1b, 0x5d, 0xcf, 0xc7, 0xc5, 0xcb, 0xba, 0x34, 0x1c, 0x72, 0xc7, 0x49, 0x16, + 0xd9, 0xd7, 0x5c, 0xe7, 0xc5, 0x74, 0x24, 0xf5, 0xe1, 0x90, 0xb9, 0x4f, 0xf2, 0xb1, 0x7e, 0x1d, + 0x56, 0x39, 0x9b, 0xc6, 0xaf, 0x48, 0x6c, 0x0b, 0xdf, 0xc0, 0xf4, 0xfd, 0xc4, 0x73, 0x20, 0x01, + 0x07, 0x55, 0xba, 0xa2, 0xe6, 0xdf, 0x28, 0x70, 0x26, 0x95, 0xcf, 0x23, 0x5f, 0x01, 0xe6, 0x27, + 0x36, 0x1e, 0xd8, 0x23, 0xb7, 0xe3, 0x0d, 0x3d, 0x0c, 0xbc, 0xc1, 0xe4, 0xa0, 0x77, 0x66, 0x71, + 0x88, 0xe8, 0x73, 0xd6, 0x1a, 0x98, 0x41, 0x25, 0x26, 0xa0, 0x51, 0x47, 0x31, 0xf0, 0xb9, 0x47, + 0x70, 0x26, 0x15, 0x35, 0x45, 0x70, 0xf2, 0xd1, 0x68, 0x06, 0x6a, 0xa1, 0xd9, 0x8a, 0x75, 0x5a, + 0x12, 0xa8, 0xf0, 0xee, 0xfd, 0x38, 0xe8, 0x5e, 0x8c, 0x23, 0x24, 0x46, 0x7c, 0x5f, 0xa7, 0x3d, + 0x6a, 0x44, 0xa5, 0xe9, 0x5b, 0xfb, 0x11, 0x9c, 0xe1, 0x8b, 0xef, 0x60, 0xe4, 0x0c, 0x0f, 0x43, + 0x72, 0xac, 0xa1, 0x1f, 0x49, 0x23, 0xc7, 0x56, 0xe5, 0x2e, 0xc5, 0x0f, 0xa8, 0x9e, 0x76, 0x92, + 0x40, 0xde, 0x87, 0x6f, 0x65, 0xc4, 0x56, 0x4f, 0x69, 0x4e, 0xca, 0xb2, 0x56, 0xd2, 0x96, 0xf5, + 0xc9, 0xf7, 0x54, 0x1d, 0x88, 0x7c, 0x58, 0x31, 0x51, 0x29, 0xb7, 0xc2, 0x12, 0xcc, 0x3d, 0x6f, + 0x88, 0x74, 0x34, 0x58, 0x2c, 0x03, 0xe8, 0x5a, 0x27, 0x0e, 0x22, 0xe7, 0xa1, 0x10, 0x24, 0xd9, + 0xe6, 0x17, 0x47, 0x9e, 0x01, 0x2a, 0x5d, 0xf2, 0x3c, 0x2c, 0x31, 0x3e, 0x3e, 0xb2, 0xe7, 0x00, + 0x61, 0x3a, 0xdd, 0x78, 0x62, 0x0c, 0x14, 0x78, 0xfe, 0x69, 0x63, 0x48, 0x1e, 0xc0, 0x59, 0xb4, + 0x05, 0xf1, 0x07, 0xc1, 0x34, 0xd8, 0x1d, 0xa7, 0x73, 0xe8, 0xf2, 0x55, 0xab, 0xa5, 0x4e, 0xc6, + 0x70, 0x68, 0x59, 0x0d, 0x69, 0x1e, 0x86, 0x43, 0xcb, 0x1f, 0x88, 0xdf, 0x25, 0x5a, 0x9d, 0xb7, + 0xa1, 0x0b, 0xe7, 0x67, 0xd4, 0x94, 0x0e, 0x0e, 0x45, 0x3e, 0x38, 0x6e, 0x82, 0xba, 0xef, 0x76, + 0x29, 0x4f, 0xec, 0x76, 0xb1, 0x69, 0x6f, 0xdd, 0x61, 0x69, 0xe5, 0xcd, 0x95, 0x00, 0x6e, 0xf9, + 0x83, 0xbd, 0x3b, 0xfc, 0x2b, 0x47, 0xe2, 0xca, 0x93, 0xdf, 0x22, 0xe4, 0x25, 0x38, 0x1d, 0x0b, + 0x6a, 0x12, 0x7a, 0xc9, 0x9b, 0x6b, 0xb4, 0x28, 0x1a, 0x02, 0xeb, 0x0a, 0x2c, 0x89, 0x55, 0x31, + 0x0a, 0x9c, 0xe7, 0xcc, 0x45, 0x0e, 0xa3, 0xbb, 0x8e, 0x7f, 0x6e, 0x22, 0x3a, 0x95, 0xfa, 0x8c, + 0x39, 0x01, 0x2f, 0x4d, 0x5e, 0x04, 0x12, 0xf0, 0xed, 0xc1, 0x41, 0xc1, 0x3f, 0xb8, 0x26, 0x4a, + 0x82, 0x1d, 0xce, 0x3f, 0xfb, 0xe7, 0x73, 0x70, 0x3a, 0xe5, 0xfd, 0x43, 0x1f, 0x01, 0x5e, 0x7f, + 0xec, 0x1e, 0xb0, 0x27, 0x84, 0xdc, 0xc9, 0x55, 0x09, 0xce, 0x85, 0x5a, 0xf3, 0x2c, 0x6d, 0x3a, + 0xff, 0x16, 0xff, 0x45, 0x0f, 0x0f, 0x67, 0x24, 0xe4, 0x35, 0xf4, 0x5f, 0x52, 0x81, 0x35, 0xcc, + 0x05, 0xe1, 0x7b, 0x03, 0x4c, 0x29, 0x81, 0x4c, 0x48, 0x2e, 0xf2, 0x42, 0xc2, 0x56, 0x34, 0x25, + 0x24, 0xca, 0x85, 0x98, 0xea, 0x30, 0x06, 0x21, 0x9f, 0x84, 0x73, 0xd2, 0x5d, 0x63, 0xc7, 0x76, + 0x1e, 0x9a, 0xc7, 0x9b, 0x1b, 0x4e, 0x70, 0xeb, 0x6c, 0x47, 0xf6, 0xe0, 0x16, 0x5c, 0xc2, 0x49, + 0xf4, 0xba, 0x43, 0x3b, 0x91, 0x3c, 0x04, 0xbb, 0xca, 0xa2, 0xed, 0x9f, 0xa3, 0x58, 0x95, 0xee, + 0x30, 0x96, 0x47, 0x04, 0x7b, 0x5d, 0x4d, 0xdd, 0x9d, 0x0b, 0xb8, 0x3b, 0x2f, 0xca, 0x9d, 0x39, + 0xd1, 0xde, 0x3c, 0x80, 0xb5, 0x80, 0x53, 0x0a, 0xae, 0xad, 0x7c, 0x24, 0x85, 0x3a, 0x12, 0x13, + 0x7c, 0x13, 0xbb, 0xc7, 0x98, 0x83, 0x7f, 0xa2, 0xa2, 0x1c, 0xc6, 0x62, 0x12, 0xa9, 0xe0, 0x93, + 0x2a, 0xac, 0xd3, 0x37, 0x30, 0x4f, 0x59, 0xe9, 0x07, 0xdf, 0x2a, 0x24, 0xbf, 0x25, 0xb4, 0x33, + 0xac, 0xaa, 0x49, 0x9c, 0x27, 0x3e, 0xcf, 0x64, 0xe9, 0x0b, 0x6a, 0x5f, 0x05, 0xc2, 0x2e, 0xe3, + 0x48, 0xbb, 0xe1, 0x69, 0xb4, 0x78, 0xbe, 0xcb, 0x44, 0x4d, 0x39, 0x18, 0x17, 0x96, 0x4a, 0x2d, + 0xe7, 0xeb, 0xf5, 0xff, 0x29, 0x70, 0x3a, 0x85, 0x22, 0xd1, 0x20, 0x23, 0x36, 0x7c, 0xd2, 0xca, + 0xa8, 0x7c, 0xca, 0xcc, 0x78, 0x5d, 0x72, 0x17, 0x00, 0xf3, 0x44, 0x8e, 0xdc, 0x03, 0xf7, 0xeb, + 0x72, 0x92, 0xfc, 0x10, 0x1a, 0xa9, 0x53, 0x40, 0xc9, 0x2d, 0x05, 0xf3, 0x27, 0x74, 0x01, 0x16, + 0xbc, 0x7e, 0xa7, 0x37, 0xe9, 0xba, 0xda, 0x0f, 0x45, 0x3b, 0xa2, 0x33, 0x42, 0x5a, 0xc0, 0xd5, + 0x7b, 0x7c, 0xf6, 0x6e, 0x4c, 0x9f, 0x3d, 0x59, 0x6b, 0xc2, 0x83, 0x3b, 0x20, 0x40, 0xd6, 0x0d, + 0x30, 0xc8, 0xfb, 0xd0, 0x67, 0xf0, 0x61, 0x7b, 0x04, 0x67, 0x52, 0x77, 0x16, 0x65, 0x84, 0xd0, + 0x4a, 0x30, 0xe4, 0xe1, 0x17, 0xe8, 0x6f, 0xca, 0xc4, 0x5f, 0x81, 0xa5, 0xc7, 0xae, 0x33, 0x72, + 0x47, 0x9c, 0xc3, 0xe4, 0x47, 0x17, 0x83, 0xc9, 0x0c, 0x66, 0x37, 0x7a, 0x84, 0x70, 0x81, 0x28, + 0xa9, 0xc1, 0x69, 0x36, 0xc5, 0xde, 0x11, 0x3e, 0x5a, 0xb8, 0x10, 0x55, 0x89, 0xb0, 0xed, 0x58, + 0x05, 0x59, 0xa8, 0x0a, 0x62, 0xb1, 0xda, 0xe6, 0xda, 0x41, 0x1c, 0x44, 0x6f, 0x9e, 0xb3, 0xe9, + 0xd8, 0x64, 0x0b, 0x16, 0x19, 0x71, 0xf6, 0x7c, 0x65, 0xda, 0xaf, 0x2b, 0x33, 0xbf, 0x50, 0x42, + 0xe3, 0x79, 0x3f, 0xf8, 0x9f, 0xf2, 0x95, 0x68, 0x68, 0x60, 0x1f, 0xc9, 0xca, 0x3d, 0x73, 0x09, + 0x81, 0x5c, 0xa9, 0xa7, 0xfd, 0x95, 0x22, 0xba, 0x1a, 0x91, 0xfc, 0xd0, 0x23, 0xd0, 0x77, 0xfb, + 0x42, 0xc1, 0x59, 0x30, 0xf9, 0xaf, 0x67, 0x3c, 0x92, 0xc9, 0x6b, 0xb0, 0x44, 0xc9, 0x1e, 0x4c, + 0xfa, 0xec, 0x68, 0xcc, 0x46, 0x82, 0x4e, 0xd5, 0x58, 0x11, 0x9d, 0xb6, 0xf2, 0x29, 0x73, 0xf1, + 0x28, 0xfc, 0x49, 0x5f, 0x75, 0xfe, 0xd1, 0x78, 0x28, 0x1f, 0xa8, 0x42, 0x0a, 0x6e, 0xd5, 0x5a, + 0x4d, 0x5e, 0x25, 0x4f, 0x71, 0xc2, 0x57, 0xdd, 0xd6, 0x3c, 0x93, 0x83, 0x6b, 0x2f, 0xc0, 0xa2, + 0x44, 0x9b, 0x76, 0x86, 0xb9, 0x85, 0x89, 0xce, 0xb0, 0x5f, 0x7c, 0xb2, 0x1f, 0x43, 0x5e, 0x90, + 0xa4, 0xcf, 0xd7, 0xc3, 0x81, 0x2f, 0x2e, 0x23, 0xfc, 0x9f, 0xc2, 0xe8, 0x28, 0x63, 0x27, 0xe7, + 0x4c, 0xfc, 0x1f, 0x79, 0x9e, 0xb1, 0x43, 0xdf, 0xad, 0x3d, 0xdf, 0x1e, 0xa2, 0x79, 0x61, 0xf0, + 0xc8, 0xa3, 0xf0, 0x56, 0xcf, 0x67, 0x46, 0x87, 0xfc, 0x1b, 0x7f, 0x11, 0x30, 0x8b, 0x31, 0x51, + 0xd9, 0xb4, 0xbb, 0x3d, 0xc2, 0xda, 0x64, 0x92, 0xac, 0x0d, 0x0b, 0x26, 0xc4, 0x6b, 0xb2, 0x2f, + 0x03, 0xc2, 0x90, 0xb5, 0x91, 0x6e, 0xb0, 0x5c, 0xe4, 0x06, 0x93, 0x64, 0x47, 0xe1, 0xec, 0x31, + 0xce, 0x48, 0xc8, 0x8e, 0xe2, 0xf7, 0xe9, 0x3b, 0xc1, 0x0a, 0x89, 0x08, 0xeb, 0xe8, 0x23, 0x8f, + 0x3d, 0xf0, 0x78, 0x0a, 0xea, 0xd8, 0x45, 0x7e, 0x1a, 0x0b, 0x59, 0x82, 0xaa, 0xe0, 0x42, 0x7f, + 0xba, 0x6c, 0x84, 0xbc, 0x0c, 0xeb, 0x41, 0xd2, 0x54, 0xff, 0x4d, 0x6f, 0x68, 0x63, 0xda, 0xdc, + 0x63, 0xfe, 0xf4, 0x22, 0xa2, 0xcc, 0x7a, 0xd3, 0x1b, 0xee, 0x61, 0x09, 0x6f, 0xe6, 0x9f, 0x66, + 0x84, 0xc4, 0x6d, 0x6b, 0x30, 0x18, 0xfb, 0xe3, 0x91, 0x33, 0x8c, 0xa8, 0x23, 0xc8, 0x11, 0x3c, + 0x87, 0x4d, 0xba, 0x83, 0x69, 0x6c, 0x06, 0x23, 0x11, 0x66, 0x27, 0xd8, 0x60, 0x8b, 0x77, 0x3e, + 0x16, 0x7d, 0x32, 0xeb, 0x14, 0x5b, 0x97, 0x91, 0xe9, 0xbe, 0x92, 0xa8, 0x96, 0x4f, 0x99, 0x1b, + 0x8c, 0x66, 0x02, 0x8b, 0x94, 0x53, 0xce, 0x9a, 0xb8, 0x3e, 0x62, 0x2b, 0x3c, 0x78, 0xa2, 0x54, + 0xe5, 0x23, 0x89, 0x7c, 0x1a, 0x0a, 0x5e, 0x57, 0xce, 0xd6, 0x1a, 0x97, 0x84, 0x57, 0xba, 0x2c, + 0x62, 0x7c, 0x48, 0x83, 0x6e, 0x0d, 0x8f, 0x43, 0xb7, 0x96, 0x23, 0x8a, 0x1b, 0x6d, 0x4b, 0x08, + 0x77, 0x92, 0xd5, 0xc8, 0x4a, 0x78, 0xe7, 0xe0, 0xfd, 0x82, 0xa7, 0x40, 0x18, 0xb3, 0xde, 0xe4, + 0xbf, 0xb4, 0xff, 0x0d, 0x37, 0x4f, 0x3a, 0x46, 0xf4, 0xc4, 0x98, 0x32, 0xe0, 0x05, 0x16, 0x2e, + 0x36, 0x3a, 0x6e, 0x57, 0x40, 0x0e, 0xb9, 0xed, 0x89, 0x25, 0x22, 0x60, 0xed, 0x91, 0xa7, 0xfd, + 0x4b, 0x16, 0x56, 0xa2, 0xaa, 0x2a, 0xf2, 0x02, 0xe4, 0xa4, 0x83, 0x72, 0x23, 0x45, 0x9f, 0x85, + 0xc7, 0x23, 0x22, 0x9d, 0xe8, 0x60, 0x24, 0xf7, 0x60, 0x05, 0x8d, 0x67, 0xf1, 0x36, 0x1f, 0x7b, + 0x5c, 0x01, 0x3a, 0x5b, 0x87, 0x9d, 0xff, 0xc9, 0xbb, 0x97, 0x4f, 0xa1, 0xba, 0x7a, 0x89, 0xd6, + 0xa5, 0x17, 0x23, 0x2d, 0x94, 0x34, 0x11, 0xb9, 0xe9, 0x9a, 0x08, 0xde, 0x95, 0x29, 0x9a, 0x88, + 0xb9, 0x19, 0x9a, 0x88, 0xb0, 0xa6, 0xac, 0x89, 0x40, 0x7d, 0xd4, 0xc2, 0x34, 0x7d, 0x54, 0x58, + 0x87, 0xe9, 0xa3, 0x42, 0x4d, 0x42, 0x7e, 0xaa, 0x26, 0x21, 0xac, 0xc3, 0x35, 0x09, 0xa1, 0x6c, + 0xbf, 0x30, 0x55, 0xb6, 0x2f, 0x55, 0x62, 0xb2, 0xfd, 0x6b, 0x7c, 0x60, 0x47, 0xce, 0x13, 0x1b, + 0x47, 0x9c, 0xb3, 0xa6, 0x38, 0x64, 0xa6, 0xf3, 0x04, 0xad, 0xe2, 0x28, 0x63, 0xc2, 0x4d, 0xe9, + 0xb4, 0x1f, 0xc5, 0x0e, 0x20, 0x31, 0xe7, 0xd7, 0x61, 0x85, 0xdd, 0xc3, 0x3c, 0x0c, 0x31, 0xbb, + 0x88, 0x97, 0xcd, 0x65, 0x01, 0x65, 0x22, 0x9f, 0x8f, 0xc0, 0x6a, 0x80, 0xc6, 0xa5, 0x1e, 0xe8, + 0x61, 0x6b, 0x06, 0xb5, 0x79, 0xb8, 0x28, 0x99, 0xde, 0x88, 0x07, 0x64, 0x8a, 0xd0, 0x63, 0xd1, + 0x7a, 0x5e, 0x04, 0x12, 0xa2, 0x05, 0x86, 0xc5, 0x39, 0x44, 0x5d, 0x0b, 0x50, 0x03, 0xeb, 0xdf, + 0x3f, 0x50, 0x62, 0xba, 0x84, 0x0f, 0xab, 0xf9, 0x2f, 0x40, 0xf0, 0x75, 0x9b, 0xcb, 0x83, 0x45, + 0x0f, 0x54, 0x51, 0xd0, 0xe4, 0x70, 0xed, 0x20, 0x2e, 0xbb, 0xf8, 0x90, 0x5a, 0xa5, 0xfd, 0x38, + 0x1b, 0x91, 0xb3, 0x8a, 0xcf, 0x50, 0xfe, 0xc6, 0x1f, 0xd8, 0x7c, 0x8a, 0xf9, 0xf1, 0x7b, 0x65, + 0xca, 0x32, 0xe5, 0xa6, 0x94, 0x96, 0xd5, 0x30, 0xc1, 0xf7, 0x07, 0xc2, 0xb2, 0xd2, 0x66, 0x6f, + 0x72, 0x89, 0xe9, 0x16, 0xe4, 0xd8, 0x59, 0x5b, 0x9c, 0x4d, 0x4e, 0x08, 0xba, 0xe8, 0x2e, 0xc5, + 0xb7, 0x79, 0xf0, 0x4b, 0x7c, 0xa0, 0x0d, 0xa8, 0x96, 0xf0, 0xa3, 0xc4, 0xb3, 0x29, 0xd2, 0x97, + 0x04, 0x71, 0x1c, 0x25, 0xa4, 0xac, 0x4e, 0xc4, 0xbf, 0x82, 0xac, 0x01, 0x4b, 0x28, 0xe5, 0x14, + 0x04, 0x73, 0x29, 0x9a, 0xbf, 0x64, 0xe7, 0x4b, 0x95, 0x9a, 0xb9, 0x48, 0xeb, 0x09, 0x32, 0x87, + 0xf0, 0x9c, 0x2c, 0x9b, 0x8c, 0x36, 0x72, 0x4e, 0x04, 0x0f, 0x9f, 0x39, 0x02, 0xa1, 0x08, 0x13, + 0x9b, 0x7a, 0xd6, 0x89, 0x02, 0x38, 0x9a, 0x76, 0x08, 0xe7, 0xa6, 0x4f, 0xc9, 0x8c, 0xc4, 0x74, + 0x21, 0x6b, 0x93, 0x91, 0x59, 0x1b, 0x59, 0x52, 0x99, 0x8d, 0x48, 0x2a, 0xb5, 0x3f, 0xc9, 0xc2, + 0xd5, 0x13, 0x4c, 0xd7, 0x8c, 0x6f, 0x7e, 0x36, 0xca, 0x38, 0x67, 0x22, 0xb2, 0x25, 0x4a, 0x94, + 0xdf, 0x09, 0xc7, 0xfd, 0xce, 0x14, 0xb6, 0xf9, 0x2b, 0xb0, 0xca, 0x0e, 0x7e, 0x66, 0x0d, 0xbd, + 0x3f, 0xe9, 0x9d, 0xe0, 0xe4, 0x3f, 0x2f, 0x5c, 0x37, 0x63, 0x55, 0xf1, 0x32, 0xc0, 0xf3, 0xce, + 0x0a, 0x60, 0xa4, 0x05, 0x8b, 0x88, 0xb6, 0xef, 0x78, 0xbd, 0x13, 0xf9, 0x10, 0x0a, 0xc7, 0x50, + 0xb9, 0x1a, 0x73, 0xe2, 0xa0, 0x80, 0x1d, 0xfc, 0x4d, 0x6e, 0xc0, 0x6a, 0x7f, 0x72, 0x44, 0x59, + 0x42, 0xb6, 0x16, 0xb8, 0xd1, 0xd9, 0x9c, 0xb9, 0xdc, 0x9f, 0x1c, 0xe9, 0xc3, 0x21, 0x4e, 0x29, + 0x5a, 0xa7, 0xad, 0x51, 0x3c, 0xb6, 0x6b, 0x05, 0xe6, 0x3c, 0x62, 0x52, 0x02, 0x6c, 0xdf, 0x72, + 0xdc, 0x75, 0x60, 0xb6, 0xca, 0x3c, 0x31, 0x1f, 0xfb, 0xa1, 0xfd, 0x7b, 0x46, 0x48, 0xcc, 0xa6, + 0xaf, 0xfb, 0xdf, 0x4c, 0x51, 0xca, 0x14, 0xdd, 0x04, 0x95, 0x0e, 0x7d, 0x78, 0xa8, 0x04, 0x73, + 0xb4, 0xd2, 0x9f, 0x1c, 0x05, 0x63, 0x27, 0x0f, 0xfc, 0xbc, 0x3c, 0xf0, 0xaf, 0x09, 0x89, 0x5a, + 0xea, 0xf1, 0x30, 0x7d, 0xc8, 0x29, 0xc7, 0x74, 0xe3, 0x64, 0x87, 0xc0, 0x6f, 0xe6, 0x2d, 0x65, + 0xde, 0x62, 0xca, 0x97, 0xb9, 0x84, 0xf2, 0x25, 0x65, 0xef, 0xcd, 0xa7, 0xed, 0xbd, 0x84, 0xaa, + 0x67, 0x21, 0x45, 0xd5, 0x93, 0xba, 0x41, 0xf3, 0x4f, 0xd9, 0xa0, 0x05, 0x79, 0x9d, 0xfc, 0x43, + 0x46, 0x70, 0x4c, 0xd1, 0x27, 0xd0, 0x23, 0x38, 0x2d, 0x9e, 0x40, 0xec, 0xe6, 0x08, 0x35, 0x78, + 0x8b, 0x77, 0x6e, 0xa5, 0x3d, 0x7e, 0x10, 0x2d, 0xe5, 0x81, 0xb2, 0xc6, 0x9f, 0x3d, 0x61, 0xf9, + 0xff, 0x9c, 0x07, 0x0f, 0x79, 0x08, 0x67, 0x31, 0xad, 0x45, 0x47, 0xd6, 0x3d, 0xda, 0x23, 0x77, + 0x9f, 0xaf, 0x87, 0x2b, 0x89, 0xe7, 0x81, 0xd7, 0x91, 0x9a, 0x63, 0xba, 0xfb, 0xe5, 0x53, 0xe6, + 0xba, 0x9f, 0x02, 0x8f, 0xbf, 0xa5, 0x7e, 0xa8, 0x80, 0xf6, 0xf4, 0xf1, 0xc2, 0x67, 0x6f, 0x7c, + 0xc0, 0xe9, 0xb3, 0x57, 0x1a, 0xbd, 0xab, 0xb0, 0x3c, 0x72, 0xf7, 0x47, 0xae, 0x7f, 0x18, 0x91, + 0x4d, 0x2d, 0x71, 0xa0, 0x18, 0x18, 0x11, 0x0b, 0xf7, 0x99, 0x1e, 0x23, 0xa2, 0x92, 0xb6, 0x13, + 0x3c, 0x91, 0x53, 0xe7, 0x81, 0xae, 0x26, 0xb9, 0x81, 0xec, 0xc7, 0xbd, 0x5c, 0x3e, 0xa3, 0x66, + 0x4d, 0x1e, 0xb1, 0x77, 0xdf, 0xeb, 0xb9, 0xda, 0x5f, 0x2a, 0x82, 0x23, 0x48, 0x1b, 0x3c, 0xf2, + 0x48, 0xf2, 0x21, 0xc8, 0x26, 0xd8, 0x90, 0xb4, 0x2a, 0x27, 0x11, 0x1c, 0x56, 0x3f, 0x20, 0xc1, + 0xe1, 0x5d, 0x61, 0x88, 0x48, 0xcf, 0xbc, 0xbd, 0xdb, 0xe4, 0x16, 0x2c, 0x30, 0xdb, 0x43, 0xd1, + 0xdc, 0xd5, 0x48, 0x73, 0xf7, 0x6e, 0x9b, 0xa2, 0x5c, 0x7b, 0x3b, 0xd0, 0x8c, 0x27, 0x3a, 0xb1, + 0x77, 0x9b, 0xbc, 0x76, 0x32, 0x9f, 0x80, 0xbc, 0xf0, 0x09, 0x08, 0xfc, 0x01, 0x5e, 0x8f, 0xf8, + 0x03, 0x5c, 0x9b, 0x3d, 0x5a, 0xdc, 0x9e, 0x81, 0x45, 0x41, 0x0d, 0xa3, 0xe3, 0xfd, 0x22, 0x03, + 0x17, 0x67, 0xd6, 0x20, 0x17, 0x20, 0xaf, 0x37, 0x2b, 0xad, 0x70, 0x7e, 0xe9, 0x9e, 0x11, 0x10, + 0xb2, 0x0b, 0x85, 0x2d, 0xc7, 0xf7, 0x3a, 0x74, 0x19, 0xa7, 0x2a, 0x18, 0x13, 0x64, 0x03, 0xf4, + 0xf2, 0x29, 0x33, 0xac, 0x4b, 0x6c, 0x58, 0xc3, 0xbd, 0x10, 0xc9, 0x78, 0x97, 0x4d, 0x11, 0xaf, + 0x24, 0x08, 0x26, 0xaa, 0xd1, 0x73, 0x26, 0x01, 0x24, 0x8f, 0x81, 0x58, 0x56, 0xb9, 0xe4, 0x8e, + 0xc6, 0x5c, 0xec, 0x30, 0xf6, 0x02, 0x03, 0xf3, 0x97, 0x9f, 0x32, 0x76, 0x89, 0x7a, 0xe5, 0x53, + 0x66, 0x0a, 0xb5, 0xf8, 0x36, 0x7f, 0x4b, 0xf0, 0x3b, 0xd3, 0x07, 0xe1, 0x19, 0x22, 0x4c, 0xdf, + 0x84, 0x7c, 0x53, 0x58, 0x33, 0x49, 0x8e, 0x3a, 0xc2, 0x72, 0xc9, 0x0c, 0x4a, 0xb5, 0xdf, 0x56, + 0x84, 0x9c, 0xe5, 0xe9, 0x83, 0x25, 0x25, 0x24, 0xec, 0xce, 0x4e, 0x48, 0xd8, 0xfd, 0x15, 0x13, + 0x12, 0x6a, 0x1e, 0xdc, 0x3a, 0xf1, 0xc0, 0x92, 0x4f, 0x81, 0x8a, 0xb9, 0xdb, 0x1c, 0x69, 0x92, + 0xd8, 0xfe, 0x5a, 0x0b, 0x52, 0x0e, 0x94, 0x79, 0x82, 0x4c, 0x73, 0xb5, 0x13, 0xad, 0xad, 0xfd, + 0x19, 0x4f, 0x35, 0x51, 0xe9, 0x36, 0x63, 0xaa, 0xaa, 0xf7, 0xeb, 0xdb, 0x65, 0x44, 0x36, 0xdb, + 0x55, 0x29, 0x77, 0x6e, 0xf2, 0x5b, 0xd3, 0x5d, 0xbc, 0xa4, 0x9d, 0xf7, 0xc7, 0x59, 0xb8, 0x30, + 0xab, 0x7a, 0x6a, 0x76, 0x7e, 0xe5, 0xd9, 0xb2, 0xf3, 0xdf, 0x82, 0x3c, 0x83, 0x05, 0x8e, 0x4b, + 0x38, 0xb7, 0xbc, 0x2a, 0x9d, 0x5b, 0x51, 0x4c, 0xae, 0xc2, 0xbc, 0x5e, 0xb2, 0xc2, 0x84, 0x91, + 0xe8, 0x61, 0xe0, 0x74, 0x7c, 0xb4, 0x5d, 0xe7, 0x45, 0xe4, 0xcb, 0xc9, 0x1c, 0xa9, 0x3c, 0x53, + 0xe4, 0x79, 0x69, 0x40, 0x12, 0x59, 0x60, 0xb0, 0xbd, 0x61, 0xd6, 0x12, 0x9e, 0x08, 0xc0, 0x4c, + 0xe6, 0x5b, 0xd5, 0x60, 0xbe, 0x39, 0x72, 0x7d, 0x77, 0x2c, 0x5b, 0xff, 0x0f, 0x11, 0x62, 0xf2, + 0x12, 0x6e, 0x9b, 0xef, 0x1c, 0xb3, 0x50, 0x2c, 0xf3, 0x72, 0x78, 0x2c, 0x34, 0xe6, 0xa7, 0x60, + 0x53, 0x42, 0xa1, 0x15, 0xaa, 0xce, 0xa4, 0xdf, 0x39, 0x6c, 0x9b, 0x55, 0xce, 0x39, 0xb1, 0x0a, + 0x3d, 0x84, 0xd2, 0x0e, 0xfa, 0xa6, 0x84, 0xa2, 0x7d, 0x47, 0x81, 0xf5, 0xb4, 0x7e, 0x90, 0x0b, + 0x90, 0xeb, 0xa7, 0xa6, 0x83, 0xed, 0xb3, 0x08, 0x12, 0x8b, 0xa8, 0x3e, 0xdb, 0x1f, 0x8c, 0x8e, + 0x9c, 0xb1, 0xec, 0x23, 0x21, 0x81, 0x4d, 0x54, 0xbc, 0xed, 0xe0, 0xff, 0xe4, 0xb2, 0xb8, 0x72, + 0xb2, 0x89, 0x04, 0xb2, 0xf8, 0x47, 0xd3, 0x01, 0x2a, 0xdd, 0x66, 0x63, 0xc8, 0xb2, 0x90, 0xbc, + 0x02, 0x39, 0xda, 0xac, 0xd8, 0xea, 0xa5, 0xeb, 0x47, 0xaf, 0x55, 0x39, 0x12, 0x6b, 0x95, 0xef, + 0x1c, 0xf5, 0x4c, 0x44, 0xd6, 0x1e, 0xc0, 0x4a, 0x14, 0x83, 0x18, 0xd1, 0x40, 0xd4, 0x8b, 0x77, + 0x54, 0x4e, 0x69, 0x6b, 0x30, 0x60, 0x7e, 0x7a, 0x5b, 0xcf, 0xfd, 0xe2, 0xdd, 0xcb, 0x40, 0x7f, + 0xb2, 0x3a, 0x69, 0x81, 0xaa, 0xb5, 0xef, 0x66, 0x60, 0x3d, 0x0c, 0x0d, 0x22, 0xf6, 0xd0, 0xaf, + 0xad, 0x9f, 0xba, 0x1e, 0xf1, 0xa3, 0x16, 0x7c, 0x63, 0xb2, 0x83, 0x33, 0xdc, 0x37, 0x77, 0x61, + 0x73, 0x1a, 0x3e, 0x79, 0x01, 0x0a, 0x18, 0x4d, 0x6e, 0xe8, 0x74, 0x5c, 0xf9, 0x98, 0xed, 0x0b, + 0xa0, 0x19, 0x96, 0x6b, 0x3f, 0x53, 0xe0, 0x1c, 0xf7, 0x2e, 0xab, 0x39, 0x5e, 0x1f, 0xf5, 0x37, + 0x1d, 0xf7, 0x83, 0x89, 0xb3, 0xb0, 0x1b, 0x39, 0xc7, 0xae, 0x47, 0x9d, 0x08, 0x13, 0x5f, 0x9b, + 0xde, 0x5b, 0x72, 0x0b, 0x23, 0x24, 0x72, 0x3b, 0x9c, 0x1c, 0x8b, 0x6b, 0xd3, 0xa7, 0x00, 0x39, + 0xae, 0x0d, 0x62, 0x68, 0xff, 0x07, 0x2e, 0xcd, 0xfe, 0x00, 0xf9, 0x12, 0x2c, 0x63, 0xca, 0xbf, + 0xf6, 0xf0, 0x60, 0xe4, 0x74, 0x5d, 0x21, 0xd9, 0x13, 0x02, 0x68, 0xb9, 0x8c, 0x05, 0x7c, 0xe4, + 0x71, 0x56, 0x0e, 0x30, 0x99, 0x20, 0xaf, 0x14, 0x71, 0xe1, 0x94, 0xa9, 0x69, 0xdf, 0x54, 0x80, + 0x24, 0x69, 0x90, 0x8f, 0xc3, 0x52, 0xbb, 0x55, 0xb2, 0xc6, 0xce, 0x68, 0x5c, 0x1e, 0x4c, 0x46, + 0x3c, 0xda, 0x22, 0x0b, 0xbb, 0x31, 0xee, 0xd8, 0x4c, 0x53, 0x77, 0x38, 0x98, 0x8c, 0xcc, 0x08, + 0x1e, 0xa6, 0x96, 0x73, 0xdd, 0x37, 0xbb, 0xce, 0x71, 0x34, 0xb5, 0x1c, 0x87, 0x45, 0x52, 0xcb, + 0x71, 0x98, 0xf6, 0x8e, 0x02, 0xe7, 0x85, 0x79, 0x75, 0x37, 0xa5, 0x2d, 0x25, 0x0c, 0x2e, 0x35, + 0x12, 0xe1, 0xbd, 0x67, 0x71, 0xe8, 0x6b, 0x22, 0xfe, 0x1a, 0x36, 0x10, 0x59, 0x75, 0x56, 0x97, + 0x7c, 0x16, 0x72, 0xd6, 0x78, 0x30, 0x3c, 0x41, 0x00, 0x36, 0x35, 0x98, 0xd1, 0xf1, 0x60, 0x88, + 0x24, 0xb0, 0xa6, 0xe6, 0xc2, 0xba, 0xdc, 0x38, 0xd1, 0x62, 0x52, 0x83, 0x05, 0x1e, 0x69, 0x33, + 0x66, 0xb9, 0x34, 0xa3, 0x4f, 0x5b, 0xab, 0x22, 0xca, 0x1b, 0x0f, 0x2f, 0x6d, 0x0a, 0x1a, 0xda, + 0xef, 0x2a, 0xb0, 0x48, 0x19, 0x1b, 0x7c, 0x94, 0xbe, 0xdf, 0x25, 0x1d, 0xe5, 0x83, 0x85, 0x21, + 0x5e, 0x40, 0xfe, 0x44, 0xb7, 0xf1, 0xab, 0xb0, 0x1a, 0xab, 0x40, 0x34, 0x8c, 0xef, 0xd3, 0xf3, + 0x3a, 0x0e, 0xcb, 0x54, 0xc5, 0x8c, 0xd8, 0x22, 0x30, 0xed, 0xff, 0x2b, 0xb0, 0xde, 0x78, 0x73, + 0xec, 0x30, 0x85, 0xba, 0x39, 0xe9, 0x89, 0xfd, 0x4e, 0x99, 0x35, 0x61, 0xa7, 0xcf, 0x62, 0x8f, + 0x30, 0x66, 0x8d, 0xc3, 0xcc, 0xa0, 0x94, 0x94, 0x21, 0xcf, 0xef, 0x17, 0x9f, 0x47, 0x85, 0xbe, + 0x24, 0xc9, 0x46, 0x42, 0xc2, 0x1c, 0x89, 0xf6, 0x04, 0x8f, 0x30, 0x5e, 0xc7, 0x0c, 0x6a, 0x6b, + 0xff, 0xaa, 0xc0, 0xc6, 0x94, 0x3a, 0xe4, 0x0d, 0x98, 0x43, 0xbf, 0x68, 0x3e, 0x7b, 0x17, 0xa6, + 0x7c, 0x62, 0xdc, 0x39, 0xdc, 0xbb, 0xcd, 0x2e, 0xa2, 0x23, 0xfa, 0xc3, 0x64, 0xb5, 0xc8, 0x23, + 0x28, 0xe8, 0xdd, 0x2e, 0x7f, 0x9d, 0x65, 0x22, 0xaf, 0xb3, 0x29, 0x5f, 0x7c, 0x29, 0xc0, 0x67, + 0xaf, 0x33, 0xe6, 0xa1, 0xd7, 0xed, 0xda, 0xdc, 0xe7, 0x3b, 0xa4, 0x77, 0xee, 0x53, 0xb0, 0x12, + 0x45, 0x7e, 0x26, 0x37, 0xd5, 0xb7, 0x15, 0x50, 0xa3, 0x6d, 0xf8, 0x70, 0xe2, 0xd3, 0xa5, 0x4d, + 0xf3, 0x53, 0x16, 0xd5, 0xef, 0x67, 0xe0, 0x4c, 0xea, 0x08, 0x93, 0x17, 0x61, 0x5e, 0x1f, 0x0e, + 0x2b, 0xdb, 0x7c, 0x55, 0x71, 0x0e, 0x09, 0x85, 0xde, 0x91, 0xc7, 0x2b, 0x43, 0x22, 0xaf, 0x40, + 0x9e, 0xd9, 0x6d, 0x6c, 0x8b, 0x03, 0x07, 0x03, 0x6e, 0x71, 0xa3, 0x92, 0x68, 0x7c, 0x66, 0x81, + 0x48, 0x76, 0x60, 0x85, 0x87, 0xaa, 0x42, 0xcb, 0x9d, 0x20, 0x51, 0x08, 0xe6, 0x32, 0x11, 0x92, + 0x74, 0x66, 0xec, 0x13, 0x39, 0x3b, 0x63, 0xb5, 0x48, 0x15, 0x54, 0xa4, 0x29, 0x53, 0x62, 0x41, + 0xa2, 0x25, 0xe3, 0xa5, 0x29, 0xb4, 0x12, 0x35, 0x83, 0xe9, 0xd2, 0x7d, 0xdf, 0x3b, 0xe8, 0x1f, + 0xb9, 0xfd, 0xf1, 0x87, 0x37, 0x5d, 0xe1, 0x37, 0x4e, 0x34, 0x5d, 0x7f, 0x98, 0x63, 0x9b, 0x39, + 0x5e, 0x8d, 0x72, 0x34, 0x52, 0x5e, 0x00, 0xe4, 0x68, 0xe8, 0xfb, 0x8c, 0x07, 0x63, 0xda, 0x86, + 0x05, 0x16, 0x24, 0x4b, 0xec, 0x8c, 0x8b, 0xa9, 0x4d, 0x60, 0x38, 0x7b, 0xb7, 0x19, 0xfb, 0xc2, + 0x1c, 0xb4, 0x7d, 0x53, 0x54, 0x25, 0x7b, 0xb0, 0x58, 0xea, 0xb9, 0x4e, 0x7f, 0x32, 0x6c, 0x9d, + 0x4c, 0x69, 0xbc, 0xc9, 0xfb, 0xb2, 0xd4, 0x61, 0xd5, 0x50, 0xd9, 0x8c, 0x27, 0xb9, 0x4c, 0x88, + 0xb4, 0x02, 0x9f, 0xcd, 0x1c, 0x0a, 0x5e, 0x5f, 0x9e, 0x31, 0x3e, 0x71, 0x20, 0xd6, 0x8b, 0x3a, + 0x24, 0x73, 0xa7, 0x4e, 0x1b, 0x56, 0xaa, 0x8e, 0x3f, 0x6e, 0x8d, 0x9c, 0xbe, 0x8f, 0xc1, 0x75, + 0x4f, 0x10, 0x7c, 0xf0, 0xbc, 0x48, 0x1c, 0x8f, 0x22, 0xd3, 0x71, 0x50, 0x95, 0x09, 0x64, 0xa3, + 0xe4, 0x28, 0xbf, 0xb4, 0xe3, 0xf5, 0x9d, 0x9e, 0xf7, 0x0d, 0xe1, 0xda, 0xce, 0xf8, 0xa5, 0x7d, + 0x01, 0x34, 0xc3, 0x72, 0xed, 0x8b, 0x89, 0x79, 0x63, 0xad, 0x5c, 0x84, 0x05, 0x1e, 0xf8, 0x84, + 0x05, 0x02, 0x69, 0x1a, 0xf5, 0xed, 0x4a, 0x7d, 0x57, 0x55, 0xc8, 0x0a, 0x40, 0xd3, 0x6c, 0x94, + 0x0c, 0xcb, 0xa2, 0xbf, 0x33, 0xf4, 0x37, 0x8f, 0x12, 0xb2, 0xd3, 0xae, 0xaa, 0x59, 0x29, 0x50, + 0x48, 0x4e, 0xfb, 0xa9, 0x02, 0x67, 0xd3, 0xa7, 0x92, 0xb4, 0x00, 0x43, 0xc5, 0x70, 0xf3, 0x81, + 0x8f, 0xcf, 0x9c, 0xf7, 0x54, 0x70, 0x3c, 0xe4, 0xcc, 0x98, 0x85, 0x32, 0xc9, 0x08, 0xdd, 0x17, + 0xf3, 0x8d, 0xf6, 0xba, 0x66, 0xc6, 0xeb, 0x6a, 0x25, 0xd8, 0x9c, 0x46, 0x23, 0xda, 0xd5, 0x55, + 0x58, 0xd4, 0x9b, 0xcd, 0x6a, 0xa5, 0xa4, 0xb7, 0x2a, 0x8d, 0xba, 0xaa, 0x90, 0x02, 0xcc, 0xed, + 0x9a, 0x8d, 0x76, 0x53, 0xcd, 0x68, 0xdf, 0x53, 0x60, 0xb9, 0x12, 0xda, 0xad, 0xbe, 0xdf, 0xcd, + 0xf7, 0x89, 0xc8, 0xe6, 0xdb, 0x0c, 0x82, 0x2a, 0x05, 0x1f, 0x38, 0xd1, 0xce, 0x7b, 0x2f, 0x03, + 0x6b, 0x89, 0x3a, 0xc4, 0x82, 0x05, 0xfd, 0x81, 0xd5, 0xa8, 0x6c, 0x97, 0x78, 0xcb, 0x2e, 0x87, + 0x86, 0x6c, 0x98, 0x66, 0x2f, 0xf1, 0x15, 0x16, 0x88, 0xe0, 0x89, 0x6f, 0x0f, 0xbc, 0x6e, 0x27, + 0x62, 0xc1, 0x28, 0x28, 0xe1, 0x4d, 0xf6, 0x8d, 0xc9, 0xc8, 0x45, 0xb2, 0x99, 0x88, 0x5c, 0x37, + 0x80, 0x27, 0x09, 0xa3, 0x71, 0xa4, 0x43, 0xcb, 0x93, 0xa4, 0x43, 0x7a, 0xa4, 0x0e, 0xf3, 0xbb, + 0xde, 0xb8, 0x3c, 0x79, 0xcc, 0xf7, 0xef, 0xa5, 0x30, 0xe9, 0x5a, 0x79, 0xf2, 0x38, 0x49, 0x16, + 0x45, 0x96, 0x2c, 0x68, 0x58, 0x84, 0x24, 0xa7, 0x12, 0xf7, 0x9d, 0xce, 0x3d, 0x93, 0xef, 0xf4, + 0xd6, 0x32, 0x2c, 0xf2, 0x37, 0x14, 0x3e, 0x4f, 0x7e, 0xac, 0xc0, 0xe6, 0xb4, 0x91, 0xa3, 0xcf, + 0xb2, 0x68, 0x8c, 0x94, 0xb3, 0x41, 0x56, 0x9e, 0x68, 0x70, 0x14, 0x81, 0x46, 0x3e, 0x03, 0x8b, + 0xcc, 0x4a, 0xcb, 0x7a, 0xa5, 0x6d, 0x56, 0xf8, 0x72, 0xbd, 0xf8, 0x4f, 0xef, 0x5e, 0xde, 0xe0, + 0x86, 0x5d, 0xfe, 0x2b, 0xf6, 0x64, 0xe4, 0x45, 0x32, 0x98, 0xc8, 0x35, 0x28, 0x17, 0xed, 0x4c, + 0xba, 0x9e, 0x2b, 0xde, 0x10, 0x22, 0x8e, 0x04, 0x87, 0xc9, 0x77, 0x9a, 0x80, 0x69, 0xdf, 0x56, + 0xe0, 0xdc, 0xf4, 0x69, 0xa2, 0xf7, 0x64, 0x8b, 0x19, 0xbb, 0x89, 0x48, 0x0e, 0x78, 0x4f, 0x06, + 0x16, 0x71, 0x32, 0x4d, 0x81, 0x48, 0x2b, 0x71, 0x09, 0x97, 0x10, 0x92, 0xc8, 0x69, 0xf8, 0xa3, + 0x95, 0x04, 0xa2, 0xf6, 0x10, 0x36, 0xa6, 0x4c, 0x2a, 0xf9, 0x74, 0x6a, 0xae, 0x2f, 0x74, 0x74, + 0x94, 0x73, 0x7d, 0x45, 0x92, 0x46, 0x4a, 0x70, 0xed, 0x9f, 0x33, 0x70, 0x96, 0xee, 0xae, 0x9e, + 0xeb, 0xfb, 0x7a, 0x98, 0x16, 0x9b, 0x9e, 0x8a, 0xaf, 0xc1, 0xfc, 0xe1, 0xb3, 0x89, 0x8a, 0x19, + 0x3a, 0x21, 0x80, 0x37, 0x96, 0x70, 0xaf, 0xa3, 0xff, 0x93, 0x2b, 0x00, 0x52, 0x62, 0xf4, 0x2c, + 0x46, 0x55, 0xce, 0x6c, 0x2a, 0x66, 0x61, 0x18, 0xa4, 0x3f, 0x7f, 0x1d, 0xe6, 0x50, 0x9e, 0xc2, + 0xef, 0x0e, 0xc1, 0xf3, 0xa7, 0xb7, 0x0e, 0xa5, 0x2d, 0x26, 0xab, 0x40, 0x3e, 0x06, 0x10, 0x26, + 0xa4, 0xe1, 0x97, 0x83, 0x90, 0x33, 0x04, 0x39, 0x69, 0xcc, 0xc2, 0xd1, 0xbe, 0xc3, 0xb3, 0xbc, + 0x14, 0x61, 0x4d, 0x8c, 0xf8, 0x50, 0x04, 0x63, 0xe5, 0x5a, 0xcc, 0x55, 0x56, 0x50, 0x19, 0x8a, + 0x80, 0xac, 0xd7, 0x12, 0x79, 0xe1, 0x31, 0x26, 0x7b, 0x2c, 0xf9, 0xfb, 0xb5, 0x44, 0xf2, 0xf7, + 0x3c, 0xc3, 0x92, 0x33, 0xbc, 0x6b, 0x7f, 0x9f, 0x81, 0xc2, 0x03, 0xca, 0x95, 0xa1, 0xac, 0x61, + 0xb6, 0xec, 0xe2, 0x0e, 0x2c, 0x56, 0x07, 0x0e, 0x57, 0x17, 0x71, 0xaf, 0x34, 0x66, 0x63, 0xdd, + 0x1b, 0x38, 0x42, 0xf3, 0xe4, 0x9b, 0x32, 0xd2, 0x53, 0xc2, 0x60, 0xdc, 0x83, 0x79, 0xa6, 0xbe, + 0xe3, 0x62, 0x34, 0xc1, 0x97, 0x07, 0x2d, 0x7a, 0x89, 0x15, 0x4b, 0x1a, 0x0e, 0xa6, 0x02, 0x94, + 0x99, 0x44, 0x6e, 0x70, 0x2d, 0x49, 0x56, 0xe6, 0x4e, 0x26, 0x59, 0x91, 0x42, 0x68, 0xce, 0x9f, + 0x24, 0x84, 0xe6, 0xb9, 0xbb, 0xb0, 0x28, 0xb5, 0xe7, 0x99, 0xd8, 0xf4, 0x6f, 0x65, 0x60, 0x19, + 0x7b, 0x15, 0xd8, 0xf2, 0xfc, 0x7a, 0xca, 0x89, 0x3e, 0x11, 0x91, 0x13, 0x6d, 0xca, 0xf3, 0xc5, + 0x7a, 0x36, 0x43, 0x40, 0x74, 0x0f, 0xd6, 0x12, 0x88, 0xe4, 0x55, 0x98, 0xa3, 0xcd, 0x17, 0xef, + 0x6a, 0x35, 0xbe, 0x02, 0xc2, 0x70, 0xeb, 0xb4, 0xe3, 0xbe, 0xc9, 0xb0, 0xb5, 0x7f, 0x53, 0x60, + 0x89, 0x67, 0x3b, 0xea, 0xef, 0x0f, 0x9e, 0x3a, 0x9c, 0x37, 0xe2, 0xc3, 0xc9, 0x82, 0x3a, 0xf1, + 0xe1, 0xfc, 0xaf, 0x1e, 0xc4, 0xbb, 0x91, 0x41, 0xdc, 0x08, 0x82, 0xaf, 0x8a, 0xee, 0xcc, 0x18, + 0xc3, 0x1f, 0x61, 0x38, 0xf2, 0x28, 0x22, 0xf9, 0x32, 0x14, 0xea, 0xee, 0x93, 0xc8, 0xf3, 0xf4, + 0xc6, 0x14, 0xa2, 0x2f, 0x05, 0x88, 0x6c, 0x4f, 0x31, 0xb7, 0x07, 0xf7, 0x89, 0x9d, 0xd0, 0x1c, + 0x86, 0x24, 0xe9, 0x0b, 0x35, 0x5a, 0xed, 0x59, 0x96, 0x3e, 0x77, 0x91, 0xc7, 0x38, 0x65, 0xdf, + 0xc9, 0x02, 0x84, 0xde, 0xc5, 0x74, 0x03, 0x46, 0x8c, 0x26, 0x84, 0x64, 0x1f, 0x41, 0xf2, 0x1a, + 0x17, 0xb6, 0x14, 0x37, 0xb8, 0x04, 0x3a, 0x33, 0x3d, 0x38, 0x2e, 0xca, 0xa2, 0x4b, 0xdc, 0x9d, + 0xb5, 0xeb, 0xf6, 0x1c, 0x76, 0xb6, 0x67, 0xb7, 0xae, 0x61, 0x2c, 0xf4, 0x00, 0x3a, 0x25, 0xcb, + 0x3d, 0x3a, 0xbd, 0x6e, 0x53, 0x84, 0x84, 0xc7, 0x7e, 0xee, 0xd9, 0x3c, 0xf6, 0x9b, 0x50, 0xf0, + 0xfa, 0x6f, 0xb9, 0xfd, 0xf1, 0x60, 0x74, 0x8c, 0x62, 0xf7, 0x50, 0x9e, 0x47, 0x87, 0xa0, 0x22, + 0xca, 0xd8, 0x3c, 0xe0, 0x9d, 0x1b, 0xe0, 0xcb, 0xd3, 0x10, 0x00, 0x83, 0x88, 0x03, 0x73, 0xea, + 0xfc, 0xbd, 0x5c, 0x7e, 0x5e, 0x5d, 0xb8, 0x97, 0xcb, 0xe7, 0xd5, 0xc2, 0xbd, 0x5c, 0xbe, 0xa0, + 0x82, 0x29, 0xe9, 0xcc, 0x02, 0x9d, 0x98, 0xa4, 0xc6, 0x8a, 0xaa, 0xa8, 0xb4, 0x5f, 0x66, 0x80, + 0x24, 0x9b, 0x41, 0x3e, 0x01, 0x8b, 0xec, 0x80, 0xb5, 0x47, 0xfe, 0xd7, 0xb8, 0x23, 0x08, 0x8b, + 0xf6, 0x26, 0x81, 0xe5, 0x68, 0x6f, 0x0c, 0x6c, 0xfa, 0x5f, 0xeb, 0x91, 0x2f, 0xc1, 0x69, 0x1c, + 0xde, 0xa1, 0x3b, 0xf2, 0x06, 0x5d, 0x1b, 0x43, 0x73, 0x3b, 0x3d, 0x9e, 0x91, 0xf6, 0x45, 0x4c, + 0x9d, 0x9e, 0x2c, 0x9e, 0x32, 0x0d, 0xe8, 0x44, 0xdc, 0x44, 0xcc, 0x26, 0x43, 0x24, 0x2d, 0x50, + 0xe5, 0xfa, 0xfb, 0x93, 0x5e, 0x8f, 0xcf, 0x6c, 0x91, 0xbe, 0xe8, 0xe3, 0x65, 0x53, 0x08, 0xaf, + 0x84, 0x84, 0x77, 0x26, 0xbd, 0x1e, 0x79, 0x0d, 0x60, 0xd0, 0xb7, 0x8f, 0x3c, 0xdf, 0x67, 0xca, + 0x9c, 0xc0, 0x15, 0x28, 0x84, 0xca, 0x93, 0x31, 0xe8, 0xd7, 0x18, 0x90, 0xfc, 0x2f, 0xc0, 0x20, + 0x31, 0x18, 0x3d, 0x89, 0x59, 0x23, 0xf1, 0xa4, 0x51, 0x02, 0x18, 0x0d, 0xaf, 0x70, 0xe0, 0x5a, + 0xde, 0x37, 0x84, 0x8b, 0xdf, 0x17, 0x60, 0x8d, 0xdb, 0x4b, 0x3f, 0xf0, 0xc6, 0x87, 0xfc, 0x29, + 0xf1, 0x7e, 0xde, 0x21, 0xd2, 0x5b, 0xe2, 0xaf, 0x73, 0x00, 0xfa, 0x03, 0x4b, 0x04, 0x26, 0xbc, + 0x05, 0x73, 0xf4, 0x81, 0x24, 0x04, 0x2d, 0x28, 0xa6, 0x46, 0xba, 0xb2, 0x98, 0x1a, 0x31, 0xe8, + 0x6e, 0x34, 0xd1, 0xdd, 0x41, 0x08, 0x59, 0x70, 0x37, 0x32, 0x0f, 0x88, 0x48, 0x60, 0x78, 0x8e, + 0x45, 0xaa, 0x00, 0x61, 0xa8, 0x40, 0xce, 0xf2, 0xaf, 0x85, 0x31, 0xb7, 0x78, 0x01, 0x4f, 0x4e, + 0x13, 0x86, 0x1b, 0x94, 0x97, 0x4f, 0x88, 0x46, 0xee, 0x43, 0xae, 0xe5, 0x04, 0xde, 0xfc, 0x53, + 0x02, 0x28, 0x3e, 0xcf, 0x33, 0x06, 0x87, 0x41, 0x14, 0x57, 0xc6, 0x4e, 0x24, 0xb1, 0x3a, 0x12, + 0x21, 0x06, 0xcc, 0x37, 0x9d, 0x91, 0x73, 0xe4, 0x4f, 0x0b, 0xbc, 0xcb, 0x4a, 0x45, 0xb8, 0x7d, + 0x04, 0xca, 0x3c, 0x05, 0x2b, 0x26, 0x77, 0x20, 0x6b, 0x59, 0x35, 0x1e, 0x36, 0x68, 0x39, 0x7c, + 0x7e, 0x59, 0x56, 0x8d, 0xe9, 0x7d, 0x7d, 0xff, 0x48, 0xaa, 0x46, 0x91, 0xc9, 0x27, 0x61, 0x51, + 0x62, 0x8a, 0x79, 0xc0, 0x2d, 0x1c, 0x03, 0xc9, 0x5f, 0x52, 0x3e, 0x34, 0x24, 0x6c, 0x52, 0x05, + 0xf5, 0xfe, 0xe4, 0xb1, 0xab, 0x0f, 0x87, 0xe8, 0x48, 0xfd, 0x96, 0x3b, 0x62, 0x6c, 0x5b, 0x3e, + 0x8c, 0x54, 0x8f, 0xde, 0x2b, 0x5d, 0x51, 0x2a, 0x0b, 0x9b, 0xe2, 0x35, 0x49, 0x13, 0xd6, 0x2c, + 0x77, 0x3c, 0x19, 0x32, 0xfb, 0x9a, 0x9d, 0xc1, 0x88, 0xbe, 0x6f, 0x58, 0x78, 0x2e, 0x0c, 0xea, + 0xed, 0xd3, 0x42, 0x61, 0xd4, 0xb4, 0x3f, 0x18, 0xc5, 0xde, 0x3a, 0xc9, 0xca, 0x9a, 0x2b, 0x4f, + 0x39, 0xbd, 0x55, 0xa3, 0xaf, 0x26, 0xbc, 0x55, 0xc5, 0xab, 0x29, 0x7c, 0x2b, 0x7d, 0x2c, 0x25, + 0x84, 0x24, 0x6a, 0x06, 0xa5, 0x10, 0x92, 0x91, 0xc0, 0x91, 0xef, 0xe4, 0xa4, 0x28, 0xc6, 0x7c, + 0x2e, 0xde, 0x00, 0xb8, 0x37, 0xf0, 0xfa, 0x35, 0x77, 0x7c, 0x38, 0xe8, 0x4a, 0x91, 0x2c, 0x17, + 0xbf, 0x3a, 0xf0, 0xfa, 0xf6, 0x11, 0x82, 0x7f, 0xf9, 0xee, 0x65, 0x09, 0xc9, 0x94, 0xfe, 0x27, + 0x1f, 0x85, 0x02, 0xfd, 0xd5, 0x0a, 0xad, 0x84, 0x98, 0x4c, 0x16, 0x6b, 0xb3, 0x5c, 0x3f, 0x21, + 0x02, 0xb9, 0x8b, 0xd9, 0xad, 0xbc, 0xe1, 0x58, 0x62, 0x5e, 0x45, 0x2a, 0x2b, 0x6f, 0x38, 0x8e, + 0x07, 0xa6, 0x97, 0x90, 0x49, 0x39, 0x68, 0xba, 0x48, 0x48, 0xc7, 0x93, 0x68, 0xa1, 0xe0, 0x91, + 0xaf, 0x35, 0x5b, 0x44, 0xc4, 0x96, 0x5d, 0x34, 0x63, 0xd5, 0xb0, 0x11, 0x56, 0x79, 0x9b, 0x69, + 0x8a, 0x38, 0x53, 0xcb, 0x1a, 0xe1, 0x1f, 0x76, 0xed, 0x0e, 0x82, 0x23, 0x8d, 0x08, 0x90, 0xc9, + 0x16, 0xac, 0x32, 0x1e, 0x3f, 0x48, 0x6c, 0xcb, 0x59, 0x5c, 0x3c, 0xdb, 0xc2, 0xcc, 0xb7, 0xf2, + 0xe7, 0x63, 0x15, 0xc8, 0x0e, 0xcc, 0xe1, 0x5b, 0x93, 0x7b, 0x43, 0x9c, 0x97, 0xc5, 0x04, 0xf1, + 0x7d, 0x84, 0xe7, 0x0a, 0x0a, 0x08, 0xe4, 0x73, 0x05, 0x51, 0xc9, 0xe7, 0x01, 0x8c, 0xfe, 0x68, + 0xd0, 0xeb, 0x61, 0xcc, 0xf6, 0x7c, 0xc4, 0x31, 0x96, 0xd3, 0x41, 0x2a, 0x21, 0x12, 0x8f, 0x2f, + 0x8a, 0xbf, 0xed, 0x58, 0x64, 0x77, 0x89, 0x96, 0x56, 0x81, 0x79, 0xb6, 0x19, 0x31, 0xff, 0x01, + 0xcf, 0xe8, 0x24, 0x45, 0xcf, 0x67, 0xf9, 0x0f, 0x38, 0x3c, 0x99, 0xff, 0x40, 0xaa, 0xa0, 0xdd, + 0x87, 0xf5, 0xb4, 0x8e, 0x45, 0x5e, 0xc7, 0xca, 0x49, 0x5f, 0xc7, 0x3f, 0xc8, 0xc2, 0x12, 0x52, + 0x13, 0xa7, 0xb0, 0x0e, 0xcb, 0xd6, 0xe4, 0x71, 0x10, 0x1c, 0x50, 0x9c, 0xc6, 0xd8, 0x3e, 0x5f, + 0x2e, 0x90, 0x75, 0x78, 0x91, 0x1a, 0xc4, 0x80, 0x15, 0x71, 0x13, 0xec, 0x0a, 0xcf, 0x81, 0x20, + 0xf5, 0x80, 0x70, 0xa8, 0x48, 0x26, 0xf6, 0x8e, 0x55, 0x0a, 0xef, 0x83, 0xec, 0xb3, 0xdc, 0x07, + 0xb9, 0x13, 0xdd, 0x07, 0x8f, 0x60, 0x49, 0x7c, 0x0d, 0x4f, 0xf2, 0xb9, 0xf7, 0x77, 0x92, 0x47, + 0x88, 0x91, 0x6a, 0x70, 0xa2, 0xcf, 0xcf, 0x3c, 0xd1, 0x51, 0x31, 0x2a, 0x76, 0xd9, 0x10, 0x61, + 0xc9, 0x83, 0x1d, 0x33, 0xdf, 0xee, 0x96, 0x9a, 0xbf, 0xc2, 0x2d, 0xf9, 0x2a, 0x14, 0xaa, 0x03, + 0xa1, 0x13, 0x93, 0x94, 0x11, 0x3d, 0x01, 0x94, 0xd9, 0x85, 0x00, 0x33, 0xb8, 0xdd, 0xb2, 0x1f, + 0xc4, 0xed, 0x76, 0x17, 0x80, 0xbb, 0xa4, 0x84, 0x19, 0x2b, 0x71, 0xcb, 0x88, 0x18, 0x47, 0x51, + 0x9d, 0x88, 0x84, 0x4c, 0x4f, 0x27, 0x6e, 0x6e, 0x23, 0x5c, 0xb8, 0xe5, 0x14, 0xef, 0xc2, 0x07, + 0x5e, 0x78, 0x85, 0xcb, 0xc7, 0x43, 0xac, 0xda, 0x07, 0x3b, 0x21, 0xe4, 0x73, 0x81, 0xf1, 0xe3, + 0xc2, 0xac, 0x11, 0xd2, 0x12, 0x23, 0x34, 0xd5, 0xe4, 0x51, 0xfb, 0xa9, 0x22, 0xe7, 0x7d, 0xf9, + 0x15, 0xa6, 0xfa, 0x75, 0x80, 0xc0, 0x28, 0x41, 0xcc, 0x75, 0xe0, 0x26, 0xce, 0xa0, 0xf2, 0x28, + 0x87, 0xb8, 0x52, 0x6f, 0xb2, 0x1f, 0x54, 0x6f, 0x5a, 0xb0, 0xd8, 0x78, 0x73, 0xec, 0x84, 0x56, + 0x2c, 0x60, 0x05, 0x9c, 0x2c, 0x9e, 0x4c, 0xd9, 0xad, 0xeb, 0x78, 0x37, 0x84, 0x7c, 0xf0, 0x14, + 0x16, 0x58, 0xaa, 0xa8, 0xfd, 0x87, 0x02, 0xab, 0x72, 0xe0, 0x8e, 0xe3, 0x7e, 0x87, 0x7c, 0x9a, + 0x85, 0xa1, 0x56, 0x22, 0x4f, 0x16, 0x09, 0x89, 0x1e, 0xb9, 0xc7, 0xfd, 0x0e, 0x63, 0x80, 0x9c, + 0x27, 0x72, 0x63, 0x69, 0x45, 0xf2, 0x18, 0x96, 0x9a, 0x83, 0x5e, 0x8f, 0xb2, 0x35, 0xa3, 0xb7, + 0xf8, 0x03, 0x80, 0x12, 0x8a, 0xab, 0x46, 0x44, 0x83, 0xb6, 0xae, 0xf2, 0x77, 0xee, 0xc6, 0x90, + 0x9e, 0xf7, 0x1e, 0xaf, 0x17, 0x92, 0x7d, 0x1b, 0x5d, 0x03, 0x65, 0x9a, 0xe1, 0xdd, 0x14, 0xcd, + 0x5f, 0x22, 0xb7, 0x92, 0x16, 0x63, 0x3b, 0x67, 0xdc, 0x4d, 0xda, 0xcf, 0x15, 0x20, 0xc9, 0xae, + 0xc9, 0x47, 0x9f, 0xf2, 0xdf, 0xc0, 0x0a, 0xc7, 0x58, 0xc8, 0xdc, 0xb3, 0xb0, 0x90, 0xda, 0xf7, + 0x15, 0x58, 0x4f, 0x1b, 0x07, 0x7a, 0x83, 0xc8, 0x57, 0x4a, 0x70, 0xa1, 0xe1, 0x0d, 0x22, 0xdf, + 0x42, 0xd1, 0x6b, 0x2d, 0x56, 0x29, 0xde, 0xb8, 0xcc, 0xb3, 0x34, 0xae, 0xf8, 0x7b, 0x0a, 0xac, + 0x56, 0xf4, 0x1a, 0x4f, 0x77, 0xc3, 0xd4, 0x54, 0x57, 0xe0, 0x62, 0x45, 0xaf, 0xd9, 0xcd, 0x46, + 0xb5, 0x52, 0x7a, 0x68, 0xa7, 0x46, 0xb1, 0xbf, 0x08, 0xcf, 0x25, 0x51, 0x42, 0x75, 0xd6, 0x05, + 0xd8, 0x4c, 0x16, 0x8b, 0x48, 0xf7, 0xe9, 0x95, 0x45, 0x50, 0xfc, 0x6c, 0xf1, 0x33, 0xb0, 0x2a, + 0xa2, 0xba, 0xb7, 0xaa, 0x16, 0xe6, 0x8d, 0x59, 0x85, 0xc5, 0x3d, 0xc3, 0xac, 0xec, 0x3c, 0xb4, + 0x77, 0xda, 0xd5, 0xaa, 0x7a, 0x8a, 0x2c, 0x43, 0x81, 0x03, 0x4a, 0xba, 0xaa, 0x90, 0x25, 0xc8, + 0x57, 0xea, 0x96, 0x51, 0x6a, 0x9b, 0x86, 0x9a, 0x29, 0x7e, 0x06, 0x56, 0x9a, 0x23, 0xef, 0x2d, + 0x67, 0xec, 0xde, 0x77, 0x8f, 0x51, 0x1b, 0xb5, 0x00, 0x59, 0x53, 0x7f, 0xa0, 0x9e, 0x22, 0x00, + 0xf3, 0xcd, 0xfb, 0x25, 0xeb, 0xf6, 0x6d, 0x55, 0x21, 0x8b, 0xb0, 0xb0, 0x5b, 0x6a, 0xda, 0xf7, + 0x6b, 0x96, 0x9a, 0xa1, 0x3f, 0xf4, 0x07, 0x16, 0xfe, 0xc8, 0x16, 0x5f, 0x86, 0x35, 0xe4, 0xba, + 0xaa, 0x9e, 0x3f, 0x76, 0xfb, 0xee, 0x08, 0xdb, 0xb0, 0x04, 0x79, 0xcb, 0xa5, 0xc7, 0xe5, 0xd8, + 0x65, 0x0d, 0xa8, 0x4d, 0x7a, 0x63, 0x6f, 0xd8, 0x73, 0xbf, 0xae, 0x2a, 0xc5, 0xbb, 0xb0, 0x6a, + 0x0e, 0x26, 0x63, 0xaf, 0x7f, 0x60, 0x8d, 0x29, 0xc6, 0xc1, 0x31, 0x39, 0x03, 0x6b, 0xed, 0xba, + 0x5e, 0xdb, 0xaa, 0xec, 0xb6, 0x1b, 0x6d, 0xcb, 0xae, 0xe9, 0xad, 0x52, 0x99, 0xe9, 0xc2, 0x6a, + 0x0d, 0xab, 0x65, 0x9b, 0x46, 0xc9, 0xa8, 0xb7, 0x54, 0xa5, 0xf8, 0x5d, 0x14, 0x20, 0x75, 0x06, + 0xfd, 0xee, 0x8e, 0xd3, 0x19, 0x0f, 0x46, 0xd8, 0x60, 0x0d, 0x2e, 0x59, 0x46, 0xa9, 0x51, 0xdf, + 0xb6, 0x77, 0xf4, 0x52, 0xab, 0x61, 0xa6, 0xa5, 0x51, 0x38, 0x07, 0x67, 0x53, 0x70, 0x1a, 0xad, + 0xa6, 0xaa, 0x90, 0xcb, 0x70, 0x3e, 0xa5, 0xec, 0x81, 0xb1, 0xa5, 0xb7, 0x5b, 0xe5, 0xba, 0x9a, + 0x99, 0x52, 0xd9, 0xb2, 0x1a, 0x6a, 0xb6, 0xf8, 0x5b, 0x0a, 0xac, 0xb4, 0x7d, 0x6e, 0x57, 0xdf, + 0x46, 0x2f, 0xe2, 0xe7, 0xe1, 0x42, 0xdb, 0x32, 0x4c, 0xbb, 0xd5, 0xb8, 0x6f, 0xd4, 0xed, 0xb6, + 0xa5, 0xef, 0xc6, 0x5b, 0x73, 0x19, 0xce, 0x4b, 0x18, 0xa6, 0x51, 0x6a, 0xec, 0x19, 0xa6, 0xdd, + 0xd4, 0x2d, 0xeb, 0x41, 0xc3, 0xdc, 0x56, 0x15, 0xfa, 0xc5, 0x14, 0x84, 0xda, 0x8e, 0xce, 0x5a, + 0x13, 0x29, 0xab, 0x1b, 0x0f, 0xf4, 0xaa, 0xbd, 0xd5, 0x68, 0xa9, 0xd9, 0x62, 0x8d, 0x32, 0x31, + 0x18, 0xcc, 0x9c, 0x99, 0x4f, 0xe6, 0x21, 0x57, 0x6f, 0xd4, 0x8d, 0xb8, 0x06, 0x75, 0x09, 0xf2, + 0x7a, 0xb3, 0x69, 0x36, 0xf6, 0x70, 0x89, 0x01, 0xcc, 0x6f, 0x1b, 0x75, 0xda, 0xb2, 0x2c, 0x2d, + 0x69, 0x9a, 0x8d, 0x5a, 0xa3, 0x65, 0x6c, 0xab, 0xb9, 0xa2, 0x29, 0xce, 0x17, 0x41, 0xb4, 0x33, + 0x60, 0xea, 0xca, 0x6d, 0x63, 0x47, 0x6f, 0x57, 0x5b, 0x7c, 0x8a, 0x1e, 0xda, 0xa6, 0xf1, 0xb9, + 0xb6, 0x61, 0xb5, 0x2c, 0x55, 0x21, 0x2a, 0x2c, 0xd5, 0x0d, 0x63, 0xdb, 0xb2, 0x4d, 0x63, 0xaf, + 0x62, 0x3c, 0x50, 0x33, 0x94, 0x26, 0xfb, 0x9f, 0x7e, 0xa1, 0xf8, 0x8e, 0x02, 0x84, 0x05, 0x82, + 0x17, 0xd9, 0xc5, 0x70, 0xc5, 0x5c, 0x82, 0x73, 0x65, 0x3a, 0xd5, 0xd8, 0xb5, 0x5a, 0x63, 0x3b, + 0x3e, 0x64, 0x67, 0x81, 0xc4, 0xca, 0x1b, 0x3b, 0x3b, 0xaa, 0x42, 0xce, 0xc3, 0xe9, 0x18, 0x7c, + 0xdb, 0x6c, 0x34, 0xd5, 0xcc, 0xb9, 0x4c, 0x5e, 0x21, 0x1b, 0x89, 0xc2, 0xfb, 0x86, 0xd1, 0x54, + 0xb3, 0x74, 0x8a, 0x62, 0x05, 0x62, 0x4b, 0xb0, 0xea, 0xb9, 0xe2, 0xb7, 0x15, 0x38, 0xcb, 0x9a, + 0x29, 0xf6, 0x57, 0xd0, 0xd4, 0x0b, 0xb0, 0xc9, 0xd3, 0x5b, 0xa4, 0x35, 0x74, 0x1d, 0xd4, 0x48, + 0x29, 0x6b, 0xe6, 0x19, 0x58, 0x8b, 0x40, 0xb1, 0x1d, 0x19, 0x7a, 0x7a, 0x44, 0xc0, 0x5b, 0x86, + 0xd5, 0xb2, 0x8d, 0x9d, 0x9d, 0x86, 0xd9, 0x62, 0x0d, 0xc9, 0x16, 0x35, 0x58, 0x2b, 0xb9, 0xa3, + 0x31, 0x7d, 0x5f, 0xf6, 0x7d, 0x6f, 0xd0, 0xc7, 0x26, 0x2c, 0x43, 0xc1, 0xf8, 0x7c, 0xcb, 0xa8, + 0x5b, 0x95, 0x46, 0x5d, 0x3d, 0x55, 0xbc, 0x10, 0xc3, 0x11, 0xfb, 0xd8, 0xb2, 0xca, 0xea, 0xa9, + 0xa2, 0x03, 0xcb, 0xc2, 0xba, 0x9c, 0xad, 0x8a, 0x4b, 0x70, 0x4e, 0xac, 0x35, 0x3c, 0x51, 0xe2, + 0x5d, 0xd8, 0x84, 0xf5, 0x64, 0xb9, 0xd1, 0x52, 0x15, 0x3a, 0x0b, 0xb1, 0x12, 0x0a, 0xcf, 0x14, + 0xff, 0xaf, 0x02, 0xcb, 0x81, 0x66, 0x08, 0x65, 0xd1, 0x97, 0xe1, 0x7c, 0x6d, 0x47, 0xb7, 0xb7, + 0x8d, 0xbd, 0x4a, 0xc9, 0xb0, 0xef, 0x57, 0xea, 0xdb, 0xb1, 0x8f, 0x3c, 0x07, 0x67, 0x52, 0x10, + 0xf0, 0x2b, 0x9b, 0xb0, 0x1e, 0x2f, 0x6a, 0xd1, 0xad, 0x9a, 0xa1, 0x43, 0x1f, 0x2f, 0x09, 0xf6, + 0x69, 0xb6, 0xb8, 0x07, 0x2b, 0x96, 0x5e, 0xab, 0xee, 0x0c, 0x46, 0x1d, 0x57, 0x9f, 0x8c, 0x0f, + 0xfb, 0xe4, 0x3c, 0x6c, 0xec, 0x34, 0xcc, 0x92, 0x61, 0x23, 0x4a, 0xac, 0x05, 0xa7, 0x61, 0x55, + 0x2e, 0x7c, 0x68, 0xd0, 0xe5, 0x4b, 0x60, 0x45, 0x06, 0xd6, 0x1b, 0x6a, 0xa6, 0xf8, 0x45, 0x58, + 0x8a, 0x24, 0x19, 0xdd, 0x80, 0xd3, 0xf2, 0xef, 0xa6, 0xdb, 0xef, 0x7a, 0xfd, 0x03, 0xf5, 0x54, + 0xbc, 0xc0, 0x9c, 0xf4, 0xfb, 0xb4, 0x00, 0xf7, 0xb3, 0x5c, 0xd0, 0x72, 0x47, 0x47, 0x5e, 0xdf, + 0x19, 0xbb, 0x5d, 0x35, 0x53, 0x7c, 0x09, 0x96, 0x23, 0xa9, 0x0d, 0xe8, 0xc4, 0x55, 0x1b, 0xfc, + 0x00, 0xae, 0x19, 0xdb, 0x95, 0x76, 0x4d, 0x9d, 0xa3, 0x3b, 0xb9, 0x5c, 0xd9, 0x2d, 0xab, 0x50, + 0xfc, 0x9e, 0x42, 0x1f, 0x53, 0x98, 0xb0, 0xac, 0xb6, 0xa3, 0x8b, 0xa9, 0xa6, 0xcb, 0x8c, 0x25, + 0x4c, 0x31, 0x2c, 0x8b, 0x19, 0x0e, 0x5c, 0x80, 0x4d, 0xfe, 0xc3, 0xd6, 0xeb, 0xdb, 0x76, 0x59, + 0x37, 0xb7, 0x1f, 0xe8, 0x26, 0x5d, 0x7b, 0x0f, 0xd5, 0x0c, 0x6e, 0x28, 0x09, 0x62, 0xb7, 0x1a, + 0xed, 0x52, 0x59, 0xcd, 0xd2, 0xf5, 0x1b, 0x81, 0x37, 0x2b, 0x75, 0x35, 0x87, 0xdb, 0x33, 0x81, + 0x8d, 0x64, 0x69, 0xf9, 0x5c, 0xf1, 0x3d, 0x05, 0x36, 0x2c, 0xef, 0xa0, 0xef, 0x8c, 0x27, 0x23, + 0x57, 0xef, 0x1d, 0x0c, 0x46, 0xde, 0xf8, 0xf0, 0xc8, 0x9a, 0x78, 0x63, 0x97, 0xdc, 0x82, 0xeb, + 0x56, 0x65, 0xb7, 0xae, 0xb7, 0xe8, 0xf6, 0xd2, 0xab, 0xbb, 0x0d, 0xb3, 0xd2, 0x2a, 0xd7, 0x6c, + 0xab, 0x5d, 0x49, 0xac, 0xbc, 0x6b, 0xf0, 0xfc, 0x74, 0xd4, 0xaa, 0xb1, 0xab, 0x97, 0x1e, 0xaa, + 0xca, 0x6c, 0x82, 0x5b, 0x7a, 0x55, 0xaf, 0x97, 0x8c, 0x6d, 0x7b, 0xef, 0xb6, 0x9a, 0x21, 0xd7, + 0xe1, 0xca, 0x74, 0xd4, 0x9d, 0x4a, 0xd3, 0xa2, 0x68, 0xd9, 0xd9, 0xdf, 0x2d, 0x5b, 0x35, 0x8a, + 0x95, 0x2b, 0x7e, 0x5f, 0x81, 0xcd, 0x69, 0xa1, 0xea, 0xc8, 0x0d, 0xd0, 0x8c, 0x7a, 0xcb, 0xd4, + 0x2b, 0xdb, 0x76, 0xc9, 0x34, 0xb6, 0x8d, 0x7a, 0xab, 0xa2, 0x57, 0x2d, 0xdb, 0x6a, 0xb4, 0xe9, + 0x6a, 0x0a, 0xed, 0x3b, 0xae, 0xc2, 0xe5, 0x19, 0x78, 0x8d, 0xca, 0x76, 0x49, 0x55, 0xc8, 0x6d, + 0x78, 0x71, 0x06, 0x92, 0xf5, 0xd0, 0x6a, 0x19, 0x35, 0xb9, 0x44, 0xcd, 0xe0, 0x81, 0x95, 0x1e, + 0xa9, 0x8b, 0xf6, 0x0e, 0x4b, 0x66, 0x37, 0xec, 0x0a, 0x5c, 0x9c, 0x8a, 0xc5, 0x9b, 0x75, 0x15, + 0x2e, 0x4f, 0x45, 0x61, 0x8d, 0x52, 0x33, 0xc5, 0x12, 0x9c, 0x9b, 0x1e, 0xac, 0x88, 0xde, 0x17, + 0xd1, 0x29, 0xcf, 0x43, 0x6e, 0x9b, 0x5e, 0x51, 0x91, 0x04, 0x3f, 0x45, 0x0f, 0xd4, 0x78, 0x20, + 0x8f, 0x84, 0x45, 0x90, 0xd9, 0xae, 0xd7, 0xd9, 0x7d, 0xb6, 0x0a, 0x8b, 0x8d, 0x56, 0xd9, 0x30, + 0x79, 0x8a, 0x24, 0xcc, 0x89, 0xd4, 0xae, 0xd3, 0x1d, 0xdc, 0x30, 0x2b, 0x5f, 0xc0, 0x8b, 0x6d, + 0x13, 0xd6, 0xad, 0xaa, 0x5e, 0xba, 0x6f, 0xd7, 0x1b, 0x2d, 0xbb, 0x52, 0xb7, 0x4b, 0x65, 0xbd, + 0x5e, 0x37, 0xaa, 0x2a, 0xe0, 0xac, 0x4e, 0xf3, 0x64, 0x25, 0x1f, 0x85, 0x9b, 0x8d, 0xfb, 0x2d, + 0xdd, 0x6e, 0x56, 0xdb, 0xbb, 0x95, 0xba, 0x6d, 0x3d, 0xac, 0x97, 0x04, 0x13, 0x56, 0x4a, 0x9e, + 0xfd, 0x37, 0xe1, 0xda, 0x4c, 0xec, 0x30, 0x99, 0xd1, 0x0d, 0xd0, 0x66, 0x62, 0xf2, 0x8e, 0x14, + 0x7f, 0xa6, 0xc0, 0xf9, 0x19, 0x1a, 0x7b, 0xf2, 0x22, 0xdc, 0x2a, 0x1b, 0xfa, 0x76, 0xd5, 0xb0, + 0x2c, 0x3c, 0xb1, 0xe8, 0xa4, 0x30, 0xcb, 0xa1, 0xd4, 0x93, 0xfd, 0x16, 0x5c, 0x9f, 0x8d, 0x1e, + 0xf2, 0x08, 0x37, 0xe1, 0xda, 0x6c, 0x54, 0xce, 0x33, 0x64, 0x48, 0x11, 0x6e, 0xcc, 0xc6, 0x0c, + 0x78, 0x8d, 0x6c, 0xf1, 0x77, 0x14, 0x38, 0x9b, 0x2e, 0x36, 0xa3, 0x6d, 0xab, 0xd4, 0xad, 0x96, + 0x5e, 0xad, 0xda, 0x4d, 0xdd, 0xd4, 0x6b, 0xb6, 0x51, 0x37, 0x1b, 0xd5, 0x6a, 0xda, 0x1d, 0x7b, + 0x0d, 0x9e, 0x9f, 0x8e, 0x6a, 0x95, 0xcc, 0x4a, 0x93, 0x5e, 0x23, 0x1a, 0x5c, 0x9a, 0x8e, 0x65, + 0x54, 0x4a, 0x86, 0x9a, 0xd9, 0x7a, 0xe3, 0x27, 0x7f, 0x77, 0xe9, 0xd4, 0x4f, 0xde, 0xbb, 0xa4, + 0xfc, 0xfc, 0xbd, 0x4b, 0xca, 0xdf, 0xbe, 0x77, 0x49, 0xf9, 0xc2, 0x0b, 0x27, 0xcb, 0x03, 0x88, + 0xaf, 0xa3, 0xc7, 0xf3, 0xf8, 0x1e, 0x7c, 0xe5, 0x3f, 0x03, 0x00, 0x00, 0xff, 0xff, 0x4d, 0x1b, + 0xb6, 0x26, 0xcd, 0xc3, 0x01, 0x00, } func (this *PluginSpecV1) Equal(that interface{}) bool { @@ -51106,6 +51156,20 @@ func (m *AccessGraphSync) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if len(m.Azure) > 0 { + for iNdEx := len(m.Azure) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Azure[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } n431, err431 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.PollInterval, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.PollInterval):]) if err431 != nil { return 0, err431 @@ -51186,6 +51250,47 @@ func (m *AccessGraphAWSSync) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *AccessGraphAzureSync) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AccessGraphAzureSync) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AccessGraphAzureSync) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Integration) > 0 { + i -= len(m.Integration) + copy(dAtA[i:], m.Integration) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Integration))) + i-- + dAtA[i] = 0x12 + } + if len(m.SubscriptionID) > 0 { + i -= len(m.SubscriptionID) + copy(dAtA[i:], m.SubscriptionID) + i = encodeVarintTypes(dAtA, i, uint64(len(m.SubscriptionID))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { offset -= sovTypes(v) base := offset @@ -62680,6 +62785,12 @@ func (m *AccessGraphSync) Size() (n int) { } l = github_com_gogo_protobuf_types.SizeOfStdDuration(m.PollInterval) n += 1 + l + sovTypes(uint64(l)) + if len(m.Azure) > 0 { + for _, e := range m.Azure { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -62712,6 +62823,26 @@ func (m *AccessGraphAWSSync) Size() (n int) { return n } +func (m *AccessGraphAzureSync) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.SubscriptionID) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.Integration) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + func sovTypes(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -135649,6 +135780,40 @@ func (m *AccessGraphSync) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Azure", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Azure = append(m.Azure, &AccessGraphAzureSync{}) + if err := m.Azure[len(m.Azure)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTypes(dAtA[iNdEx:]) @@ -135822,6 +135987,121 @@ func (m *AccessGraphAWSSync) Unmarshal(dAtA []byte) error { } return nil } +func (m *AccessGraphAzureSync) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AccessGraphAzureSync: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AccessGraphAzureSync: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SubscriptionID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SubscriptionID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Integration", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Integration = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipTypes(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/gen/proto/go/accessgraph/v1alpha/access_graph_service.pb.go b/gen/proto/go/accessgraph/v1alpha/access_graph_service.pb.go index a8c4176608eda..1c5a3663ce56b 100644 --- a/gen/proto/go/accessgraph/v1alpha/access_graph_service.pb.go +++ b/gen/proto/go/accessgraph/v1alpha/access_graph_service.pb.go @@ -1519,6 +1519,179 @@ func (*NetIQEventsStreamResponse) Descriptor() ([]byte, []int) { return file_accessgraph_v1alpha_access_graph_service_proto_rawDescGZIP(), []int{23} } +// AzureEventsStreamRequest is a request to send commands to the Azure importer +type AzureEventsStreamRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Operation: + // + // *AzureEventsStreamRequest_Sync + // *AzureEventsStreamRequest_Upsert + // *AzureEventsStreamRequest_Delete + Operation isAzureEventsStreamRequest_Operation `protobuf_oneof:"operation"` +} + +func (x *AzureEventsStreamRequest) Reset() { + *x = AzureEventsStreamRequest{} + mi := &file_accessgraph_v1alpha_access_graph_service_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AzureEventsStreamRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AzureEventsStreamRequest) ProtoMessage() {} + +func (x *AzureEventsStreamRequest) ProtoReflect() protoreflect.Message { + mi := &file_accessgraph_v1alpha_access_graph_service_proto_msgTypes[24] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AzureEventsStreamRequest.ProtoReflect.Descriptor instead. +func (*AzureEventsStreamRequest) Descriptor() ([]byte, []int) { + return file_accessgraph_v1alpha_access_graph_service_proto_rawDescGZIP(), []int{24} +} + +func (m *AzureEventsStreamRequest) GetOperation() isAzureEventsStreamRequest_Operation { + if m != nil { + return m.Operation + } + return nil +} + +func (x *AzureEventsStreamRequest) GetSync() *AzureSyncOperation { + if x, ok := x.GetOperation().(*AzureEventsStreamRequest_Sync); ok { + return x.Sync + } + return nil +} + +func (x *AzureEventsStreamRequest) GetUpsert() *AzureResourceList { + if x, ok := x.GetOperation().(*AzureEventsStreamRequest_Upsert); ok { + return x.Upsert + } + return nil +} + +func (x *AzureEventsStreamRequest) GetDelete() *AzureResourceList { + if x, ok := x.GetOperation().(*AzureEventsStreamRequest_Delete); ok { + return x.Delete + } + return nil +} + +type isAzureEventsStreamRequest_Operation interface { + isAzureEventsStreamRequest_Operation() +} + +type AzureEventsStreamRequest_Sync struct { + // sync is a command to sync the access graph with the Teleport database state. + // it's issued once Teleport finishes syncing all resources with the database. + Sync *AzureSyncOperation `protobuf:"bytes,1,opt,name=sync,proto3,oneof"` +} + +type AzureEventsStreamRequest_Upsert struct { + // upsert is a command to put a resource into the access graph or update it. + Upsert *AzureResourceList `protobuf:"bytes,2,opt,name=upsert,proto3,oneof"` +} + +type AzureEventsStreamRequest_Delete struct { + // delete is a command to delete a resource from the access graph when it's deleted from Teleport. + Delete *AzureResourceList `protobuf:"bytes,3,opt,name=delete,proto3,oneof"` +} + +func (*AzureEventsStreamRequest_Sync) isAzureEventsStreamRequest_Operation() {} + +func (*AzureEventsStreamRequest_Upsert) isAzureEventsStreamRequest_Operation() {} + +func (*AzureEventsStreamRequest_Delete) isAzureEventsStreamRequest_Operation() {} + +// AzureSyncOperation is a command that Teleport sends to the access graph service +// at the end of the sync process. +type AzureSyncOperation struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *AzureSyncOperation) Reset() { + *x = AzureSyncOperation{} + mi := &file_accessgraph_v1alpha_access_graph_service_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AzureSyncOperation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AzureSyncOperation) ProtoMessage() {} + +func (x *AzureSyncOperation) ProtoReflect() protoreflect.Message { + mi := &file_accessgraph_v1alpha_access_graph_service_proto_msgTypes[25] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AzureSyncOperation.ProtoReflect.Descriptor instead. +func (*AzureSyncOperation) Descriptor() ([]byte, []int) { + return file_accessgraph_v1alpha_access_graph_service_proto_rawDescGZIP(), []int{25} +} + +// AzureEventsStreamResponse is a response from AzureEventsStream +type AzureEventsStreamResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *AzureEventsStreamResponse) Reset() { + *x = AzureEventsStreamResponse{} + mi := &file_accessgraph_v1alpha_access_graph_service_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AzureEventsStreamResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AzureEventsStreamResponse) ProtoMessage() {} + +func (x *AzureEventsStreamResponse) ProtoReflect() protoreflect.Message { + mi := &file_accessgraph_v1alpha_access_graph_service_proto_msgTypes[26] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AzureEventsStreamResponse.ProtoReflect.Descriptor instead. +func (*AzureEventsStreamResponse) Descriptor() ([]byte, []int) { + return file_accessgraph_v1alpha_access_graph_service_proto_rawDescGZIP(), []int{26} +} + var File_accessgraph_v1alpha_access_graph_service_proto protoreflect.FileDescriptor var file_accessgraph_v1alpha_access_graph_service_proto_rawDesc = []byte{ @@ -1529,34 +1702,63 @@ var file_accessgraph_v1alpha_access_graph_service_proto_rawDesc = []byte{ 0x61, 0x6c, 0x70, 0x68, 0x61, 0x1a, 0x1d, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2f, 0x61, 0x77, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, - 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2f, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, - 0x70, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, - 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, - 0x72, 0x61, 0x70, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2f, 0x67, 0x69, 0x74, - 0x6c, 0x61, 0x62, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x61, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2f, 0x67, - 0x72, 0x61, 0x70, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x61, 0x63, 0x63, 0x65, + 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2f, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, + 0x70, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2f, 0x65, 0x6e, 0x74, 0x72, 0x61, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, + 0x61, 0x70, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2f, 0x65, 0x76, 0x65, 0x6e, + 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2f, 0x67, 0x69, + 0x74, 0x6c, 0x61, 0x62, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2f, - 0x6e, 0x65, 0x74, 0x69, 0x71, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x23, 0x61, 0x63, 0x63, + 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, - 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x22, 0x24, 0x0a, 0x0c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x22, 0x71, 0x0a, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, - 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4e, 0x6f, 0x64, - 0x65, 0x52, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x2f, 0x0a, 0x05, 0x65, 0x64, 0x67, 0x65, - 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x64, - 0x67, 0x65, 0x52, 0x05, 0x65, 0x64, 0x67, 0x65, 0x73, 0x22, 0x2c, 0x0a, 0x0e, 0x47, 0x65, 0x74, - 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x66, - 0x69, 0x6c, 0x65, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, - 0x69, 0x6c, 0x65, 0x70, 0x61, 0x74, 0x68, 0x22, 0x25, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x46, 0x69, - 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, - 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0xaa, - 0x03, 0x0a, 0x13, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, + 0x2f, 0x6e, 0x65, 0x74, 0x69, 0x71, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x23, 0x61, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, + 0x61, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x22, 0x24, 0x0a, 0x0c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x22, 0x71, 0x0a, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x05, 0x6e, 0x6f, 0x64, 0x65, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4e, 0x6f, + 0x64, 0x65, 0x52, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x2f, 0x0a, 0x05, 0x65, 0x64, 0x67, + 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, + 0x64, 0x67, 0x65, 0x52, 0x05, 0x65, 0x64, 0x67, 0x65, 0x73, 0x22, 0x2c, 0x0a, 0x0e, 0x47, 0x65, + 0x74, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, + 0x66, 0x69, 0x6c, 0x65, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x66, 0x69, 0x6c, 0x65, 0x70, 0x61, 0x74, 0x68, 0x22, 0x25, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x46, + 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, + 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, + 0xaa, 0x03, 0x0a, 0x13, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, + 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x53, 0x79, 0x6e, 0x63, + 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x04, 0x73, 0x79, 0x6e, + 0x63, 0x12, 0x3b, 0x0a, 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x21, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, + 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, 0x12, 0x41, + 0x0a, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, + 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, + 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x48, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x12, 0x5b, 0x0a, 0x14, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x69, 0x73, 0x74, + 0x73, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x27, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, + 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, + 0x73, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x48, 0x00, 0x52, 0x12, 0x61, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x6f, + 0x0a, 0x1b, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, + 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x64, + 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x4d, 0x65, 0x6d, 0x62, + 0x65, 0x72, 0x73, 0x48, 0x00, 0x52, 0x18, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x42, + 0x0b, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xac, 0x03, 0x0a, + 0x15, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x56, 0x32, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4f, @@ -1582,202 +1784,201 @@ var file_accessgraph_v1alpha_access_graph_service_proto_rawDesc = []byte{ 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x48, 0x00, 0x52, 0x18, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x42, 0x0b, - 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xac, 0x03, 0x0a, 0x15, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x56, 0x32, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, - 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4f, 0x70, + 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x0f, 0x0a, 0x0d, 0x53, + 0x79, 0x6e, 0x63, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x16, 0x0a, 0x14, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5b, 0x0a, 0x16, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x56, 0x32, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, + 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, + 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, + 0x70, 0x68, 0x61, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, + 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x42, 0x08, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x22, 0x6f, 0x0a, 0x0a, 0x41, 0x75, 0x64, 0x69, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, + 0x58, 0x0a, 0x13, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x63, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x61, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, + 0x68, 0x61, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x50, 0x61, 0x74, 0x68, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x64, 0x48, 0x00, 0x52, 0x11, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x50, 0x61, + 0x74, 0x68, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x42, 0x07, 0x0a, 0x05, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x22, 0x54, 0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x0b, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x63, 0x61, + 0x5f, 0x70, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x68, 0x6f, 0x73, 0x74, + 0x43, 0x61, 0x50, 0x65, 0x6d, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6c, 0x75, + 0x73, 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x12, 0x0a, 0x10, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x33, 0x0a, 0x11, + 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x43, 0x41, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1e, 0x0a, 0x0b, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x63, 0x61, 0x5f, 0x70, 0x65, 0x6d, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x09, 0x68, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x50, 0x65, + 0x6d, 0x22, 0x14, 0x0a, 0x12, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x43, 0x41, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xe2, 0x01, 0x0a, 0x16, 0x41, 0x57, 0x53, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x3b, 0x0a, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x25, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, + 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x57, 0x53, 0x53, 0x79, 0x6e, 0x63, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x12, - 0x3b, 0x0a, 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x21, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, - 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, + 0x3e, 0x0a, 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x24, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, + 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x57, 0x53, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, 0x12, + 0x3e, 0x0a, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x24, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, + 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x57, 0x53, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, + 0x0b, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x12, 0x0a, 0x10, + 0x41, 0x57, 0x53, 0x53, 0x79, 0x6e, 0x63, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x22, 0x19, 0x0a, 0x17, 0x41, 0x57, 0x53, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xee, 0x01, 0x0a, 0x19, + 0x47, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3e, 0x0a, 0x04, 0x73, 0x79, 0x6e, + 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x47, 0x69, + 0x74, 0x6c, 0x61, 0x62, 0x53, 0x79, 0x6e, 0x63, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x48, 0x00, 0x52, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x41, 0x0a, 0x06, 0x75, 0x70, 0x73, + 0x65, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x61, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, + 0x47, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, 0x12, 0x41, 0x0a, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, - 0x68, 0x61, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, - 0x72, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, - 0x5b, 0x0a, 0x14, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x73, 0x5f, - 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, - 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, - 0x70, 0x68, 0x61, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x4d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x48, 0x00, 0x52, 0x12, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x4c, 0x69, 0x73, 0x74, 0x73, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x6f, 0x0a, 0x1b, - 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, - 0x69, 0x73, 0x74, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2e, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, - 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x73, 0x48, 0x00, 0x52, 0x18, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x63, 0x63, 0x65, - 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x42, 0x0b, 0x0a, - 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x0f, 0x0a, 0x0d, 0x53, 0x79, - 0x6e, 0x63, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x16, 0x0a, 0x14, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x5b, 0x0a, 0x16, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, - 0x65, 0x61, 0x6d, 0x56, 0x32, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, - 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x61, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, - 0x68, 0x61, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, - 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x42, 0x08, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x22, 0x6f, 0x0a, 0x0a, 0x41, 0x75, 0x64, 0x69, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x58, - 0x0a, 0x13, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x63, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x61, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, - 0x61, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x50, 0x61, 0x74, 0x68, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x64, 0x48, 0x00, 0x52, 0x11, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x50, 0x61, 0x74, - 0x68, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x42, 0x07, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, - 0x74, 0x22, 0x54, 0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x0b, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x63, 0x61, 0x5f, - 0x70, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x68, 0x6f, 0x73, 0x74, 0x43, - 0x61, 0x50, 0x65, 0x6d, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6c, 0x75, 0x73, - 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x12, 0x0a, 0x10, 0x52, 0x65, 0x67, 0x69, 0x73, - 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x33, 0x0a, 0x11, 0x52, - 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x43, 0x41, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x1e, 0x0a, 0x0b, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x63, 0x61, 0x5f, 0x70, 0x65, 0x6d, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x09, 0x68, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x50, 0x65, 0x6d, - 0x22, 0x14, 0x0a, 0x12, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x43, 0x41, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xe2, 0x01, 0x0a, 0x16, 0x41, 0x57, 0x53, 0x45, 0x76, + 0x68, 0x61, 0x2e, 0x47, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, + 0x0b, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x1c, 0x0a, 0x1a, + 0x47, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xea, 0x01, 0x0a, 0x18, 0x45, + 0x6e, 0x74, 0x72, 0x61, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3d, 0x0a, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, + 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x6e, 0x74, 0x72, + 0x61, 0x53, 0x79, 0x6e, 0x63, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, + 0x52, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x40, 0x0a, 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, + 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x6e, 0x74, + 0x72, 0x61, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, + 0x52, 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, 0x12, 0x40, 0x0a, 0x06, 0x64, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, + 0x6e, 0x74, 0x72, 0x61, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, + 0x48, 0x00, 0x52, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x0b, 0x0a, 0x09, 0x6f, 0x70, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x1b, 0x0a, 0x19, 0x45, 0x6e, 0x74, 0x72, 0x61, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xea, 0x01, 0x0a, 0x18, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x3b, 0x0a, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x25, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, - 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x57, 0x53, 0x53, 0x79, 0x6e, 0x63, 0x4f, 0x70, 0x65, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x3e, - 0x0a, 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, - 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, - 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x57, 0x53, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, 0x12, 0x3e, - 0x0a, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, - 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, - 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x57, 0x53, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x0b, - 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x12, 0x0a, 0x10, 0x41, - 0x57, 0x53, 0x53, 0x79, 0x6e, 0x63, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, - 0x19, 0x0a, 0x17, 0x41, 0x57, 0x53, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, - 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xee, 0x01, 0x0a, 0x19, 0x47, - 0x69, 0x74, 0x6c, 0x61, 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, - 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3e, 0x0a, 0x04, 0x73, 0x79, 0x6e, 0x63, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, - 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x47, 0x69, 0x74, - 0x6c, 0x61, 0x62, 0x53, 0x79, 0x6e, 0x63, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x48, 0x00, 0x52, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x41, 0x0a, 0x06, 0x75, 0x70, 0x73, 0x65, - 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x47, - 0x69, 0x74, 0x6c, 0x61, 0x62, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, - 0x74, 0x48, 0x00, 0x52, 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, 0x12, 0x41, 0x0a, 0x06, 0x64, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x61, 0x63, + 0x74, 0x12, 0x3d, 0x0a, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x27, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, + 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x53, 0x79, 0x6e, 0x63, 0x4f, + 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x04, 0x73, 0x79, 0x6e, 0x63, + 0x12, 0x40, 0x0a, 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x26, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, + 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x75, 0x70, 0x73, 0x65, + 0x72, 0x74, 0x12, 0x40, 0x0a, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, + 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x64, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x42, 0x0b, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x22, 0x14, 0x0a, 0x12, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x53, 0x79, 0x6e, 0x63, 0x4f, 0x70, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x1b, 0x0a, 0x19, 0x4e, 0x65, 0x74, 0x49, 0x51, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xea, 0x01, 0x0a, 0x18, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x3d, 0x0a, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x27, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, + 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x4f, + 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x04, 0x73, 0x79, 0x6e, 0x63, + 0x12, 0x40, 0x0a, 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x26, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, + 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x75, 0x70, 0x73, 0x65, + 0x72, 0x74, 0x12, 0x40, 0x0a, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, + 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x64, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x42, 0x0b, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x22, 0x14, 0x0a, 0x12, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x4f, 0x70, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x1b, 0x0a, 0x19, 0x41, 0x7a, 0x75, 0x72, 0x65, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x9b, 0x09, 0x0a, 0x12, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, + 0x72, 0x61, 0x70, 0x68, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4e, 0x0a, 0x05, 0x51, + 0x75, 0x65, 0x72, 0x79, 0x12, 0x21, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, + 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x51, 0x75, + 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x07, 0x47, + 0x65, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x23, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, + 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x47, 0x65, 0x74, + 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, - 0x61, 0x2e, 0x47, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x0b, - 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x1c, 0x0a, 0x1a, 0x47, - 0x69, 0x74, 0x6c, 0x61, 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, - 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xea, 0x01, 0x0a, 0x18, 0x45, 0x6e, - 0x74, 0x72, 0x61, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3d, 0x0a, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, - 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x6e, 0x74, 0x72, 0x61, - 0x53, 0x79, 0x6e, 0x63, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, - 0x04, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x40, 0x0a, 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, - 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x6e, 0x74, 0x72, - 0x61, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, - 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, 0x12, 0x40, 0x0a, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x6e, - 0x74, 0x72, 0x61, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x48, - 0x00, 0x52, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x0b, 0x0a, 0x09, 0x6f, 0x70, 0x65, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x1b, 0x0a, 0x19, 0x45, 0x6e, 0x74, 0x72, 0x61, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0xea, 0x01, 0x0a, 0x18, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x3d, 0x0a, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, - 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, - 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x53, 0x79, 0x6e, 0x63, 0x4f, 0x70, - 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x12, - 0x40, 0x0a, 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x26, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, - 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, - 0x74, 0x12, 0x40, 0x0a, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x26, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, - 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x64, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x42, 0x0b, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x22, 0x14, 0x0a, 0x12, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x53, 0x79, 0x6e, 0x63, 0x4f, 0x70, 0x65, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x1b, 0x0a, 0x19, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x32, 0xa3, 0x08, 0x0a, 0x12, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, - 0x61, 0x70, 0x68, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4e, 0x0a, 0x05, 0x51, 0x75, - 0x65, 0x72, 0x79, 0x12, 0x21, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, - 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, - 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x51, 0x75, 0x65, - 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x07, 0x47, 0x65, - 0x74, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x23, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, - 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x47, 0x65, 0x74, 0x46, - 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x61, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, - 0x2e, 0x47, 0x65, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x65, 0x0a, 0x0c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, - 0x12, 0x28, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, - 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, - 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x61, 0x63, 0x63, + 0x61, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x65, 0x0a, 0x0c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, + 0x6d, 0x12, 0x28, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, + 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x61, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, + 0x61, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x12, 0x6d, 0x0a, 0x0e, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x56, 0x32, 0x12, 0x2a, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, - 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x12, 0x6d, 0x0a, 0x0e, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x56, 0x32, 0x12, 0x2a, 0x2e, 0x61, 0x63, 0x63, 0x65, + 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x56, 0x32, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, + 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x56, 0x32, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x12, 0x57, 0x0a, 0x08, 0x52, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x65, 0x72, 0x12, 0x24, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, + 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x56, 0x32, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, - 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x56, 0x32, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x12, 0x57, 0x0a, 0x08, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, - 0x65, 0x72, 0x12, 0x24, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, - 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, - 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x52, - 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x5d, 0x0a, 0x0a, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x43, 0x41, 0x73, 0x12, 0x26, 0x2e, - 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, - 0x70, 0x68, 0x61, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x43, 0x41, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, - 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x52, 0x65, 0x70, 0x6c, - 0x61, 0x63, 0x65, 0x43, 0x41, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6e, - 0x0a, 0x0f, 0x41, 0x57, 0x53, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, - 0x6d, 0x12, 0x2b, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, - 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x57, 0x53, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x5d, 0x0a, 0x0a, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x43, 0x41, 0x73, 0x12, 0x26, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, - 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x57, 0x53, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, - 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x12, 0x79, - 0x0a, 0x12, 0x47, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, - 0x72, 0x65, 0x61, 0x6d, 0x12, 0x2e, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, - 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x47, 0x69, 0x74, 0x6c, 0x61, - 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, - 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x47, 0x69, 0x74, 0x6c, 0x61, - 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x12, 0x76, 0x0a, 0x11, 0x45, 0x6e, 0x74, - 0x72, 0x61, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x2d, + 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x43, 0x41, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, + 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x52, 0x65, 0x70, + 0x6c, 0x61, 0x63, 0x65, 0x43, 0x41, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x6e, 0x0a, 0x0f, 0x41, 0x57, 0x53, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x12, 0x2b, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, + 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x57, 0x53, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x2c, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, + 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x57, 0x53, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x12, + 0x79, 0x0a, 0x12, 0x47, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x2e, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, + 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x47, 0x69, 0x74, 0x6c, + 0x61, 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, + 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x47, 0x69, 0x74, 0x6c, + 0x61, 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x12, 0x76, 0x0a, 0x11, 0x45, 0x6e, + 0x74, 0x72, 0x61, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, + 0x2d, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, + 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x6e, 0x74, 0x72, 0x61, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x6e, 0x74, 0x72, 0x61, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, - 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, - 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, - 0x70, 0x68, 0x61, 0x2e, 0x45, 0x6e, 0x74, 0x72, 0x61, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, - 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, - 0x01, 0x12, 0x76, 0x0a, 0x11, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, - 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x2d, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, + 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, + 0x30, 0x01, 0x12, 0x76, 0x0a, 0x11, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x2d, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4e, 0x65, + 0x74, 0x49, 0x51, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, - 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4e, 0x65, 0x74, 0x49, - 0x51, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x42, 0x57, 0x5a, 0x55, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x67, - 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x61, 0x63, 0x63, 0x65, - 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x3b, - 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x76, 0x31, 0x61, 0x6c, 0x70, - 0x68, 0x61, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x12, 0x76, 0x0a, 0x11, 0x41, 0x7a, + 0x75, 0x72, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, + 0x2d, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, + 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, + 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, + 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, + 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, + 0x30, 0x01, 0x42, 0x57, 0x5a, 0x55, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, + 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, + 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x3b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, + 0x72, 0x61, 0x70, 0x68, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( @@ -1792,7 +1993,7 @@ func file_accessgraph_v1alpha_access_graph_service_proto_rawDescGZIP() []byte { return file_accessgraph_v1alpha_access_graph_service_proto_rawDescData } -var file_accessgraph_v1alpha_access_graph_service_proto_msgTypes = make([]protoimpl.MessageInfo, 24) +var file_accessgraph_v1alpha_access_graph_service_proto_msgTypes = make([]protoimpl.MessageInfo, 27) var file_accessgraph_v1alpha_access_graph_service_proto_goTypes = []any{ (*QueryRequest)(nil), // 0: accessgraph.v1alpha.QueryRequest (*QueryResponse)(nil), // 1: accessgraph.v1alpha.QueryResponse @@ -1818,72 +2019,81 @@ var file_accessgraph_v1alpha_access_graph_service_proto_goTypes = []any{ (*NetIQEventsStreamRequest)(nil), // 21: accessgraph.v1alpha.NetIQEventsStreamRequest (*NetIQSyncOperation)(nil), // 22: accessgraph.v1alpha.NetIQSyncOperation (*NetIQEventsStreamResponse)(nil), // 23: accessgraph.v1alpha.NetIQEventsStreamResponse - (*Node)(nil), // 24: accessgraph.v1alpha.Node - (*Edge)(nil), // 25: accessgraph.v1alpha.Edge - (*ResourceList)(nil), // 26: accessgraph.v1alpha.ResourceList - (*ResourceHeaderList)(nil), // 27: accessgraph.v1alpha.ResourceHeaderList - (*AccessListsMembers)(nil), // 28: accessgraph.v1alpha.AccessListsMembers - (*ExcludeAccessListsMembers)(nil), // 29: accessgraph.v1alpha.ExcludeAccessListsMembers - (*AccessPathChanged)(nil), // 30: accessgraph.v1alpha.AccessPathChanged - (*AWSResourceList)(nil), // 31: accessgraph.v1alpha.AWSResourceList - (*GitlabSyncOperation)(nil), // 32: accessgraph.v1alpha.GitlabSyncOperation - (*GitlabResourceList)(nil), // 33: accessgraph.v1alpha.GitlabResourceList - (*EntraSyncOperation)(nil), // 34: accessgraph.v1alpha.EntraSyncOperation - (*EntraResourceList)(nil), // 35: accessgraph.v1alpha.EntraResourceList - (*NetIQResourceList)(nil), // 36: accessgraph.v1alpha.NetIQResourceList + (*AzureEventsStreamRequest)(nil), // 24: accessgraph.v1alpha.AzureEventsStreamRequest + (*AzureSyncOperation)(nil), // 25: accessgraph.v1alpha.AzureSyncOperation + (*AzureEventsStreamResponse)(nil), // 26: accessgraph.v1alpha.AzureEventsStreamResponse + (*Node)(nil), // 27: accessgraph.v1alpha.Node + (*Edge)(nil), // 28: accessgraph.v1alpha.Edge + (*ResourceList)(nil), // 29: accessgraph.v1alpha.ResourceList + (*ResourceHeaderList)(nil), // 30: accessgraph.v1alpha.ResourceHeaderList + (*AccessListsMembers)(nil), // 31: accessgraph.v1alpha.AccessListsMembers + (*ExcludeAccessListsMembers)(nil), // 32: accessgraph.v1alpha.ExcludeAccessListsMembers + (*AccessPathChanged)(nil), // 33: accessgraph.v1alpha.AccessPathChanged + (*AWSResourceList)(nil), // 34: accessgraph.v1alpha.AWSResourceList + (*GitlabSyncOperation)(nil), // 35: accessgraph.v1alpha.GitlabSyncOperation + (*GitlabResourceList)(nil), // 36: accessgraph.v1alpha.GitlabResourceList + (*EntraSyncOperation)(nil), // 37: accessgraph.v1alpha.EntraSyncOperation + (*EntraResourceList)(nil), // 38: accessgraph.v1alpha.EntraResourceList + (*NetIQResourceList)(nil), // 39: accessgraph.v1alpha.NetIQResourceList + (*AzureResourceList)(nil), // 40: accessgraph.v1alpha.AzureResourceList } var file_accessgraph_v1alpha_access_graph_service_proto_depIdxs = []int32{ - 24, // 0: accessgraph.v1alpha.QueryResponse.nodes:type_name -> accessgraph.v1alpha.Node - 25, // 1: accessgraph.v1alpha.QueryResponse.edges:type_name -> accessgraph.v1alpha.Edge + 27, // 0: accessgraph.v1alpha.QueryResponse.nodes:type_name -> accessgraph.v1alpha.Node + 28, // 1: accessgraph.v1alpha.QueryResponse.edges:type_name -> accessgraph.v1alpha.Edge 6, // 2: accessgraph.v1alpha.EventsStreamRequest.sync:type_name -> accessgraph.v1alpha.SyncOperation - 26, // 3: accessgraph.v1alpha.EventsStreamRequest.upsert:type_name -> accessgraph.v1alpha.ResourceList - 27, // 4: accessgraph.v1alpha.EventsStreamRequest.delete:type_name -> accessgraph.v1alpha.ResourceHeaderList - 28, // 5: accessgraph.v1alpha.EventsStreamRequest.access_lists_members:type_name -> accessgraph.v1alpha.AccessListsMembers - 29, // 6: accessgraph.v1alpha.EventsStreamRequest.exclude_access_list_members:type_name -> accessgraph.v1alpha.ExcludeAccessListsMembers + 29, // 3: accessgraph.v1alpha.EventsStreamRequest.upsert:type_name -> accessgraph.v1alpha.ResourceList + 30, // 4: accessgraph.v1alpha.EventsStreamRequest.delete:type_name -> accessgraph.v1alpha.ResourceHeaderList + 31, // 5: accessgraph.v1alpha.EventsStreamRequest.access_lists_members:type_name -> accessgraph.v1alpha.AccessListsMembers + 32, // 6: accessgraph.v1alpha.EventsStreamRequest.exclude_access_list_members:type_name -> accessgraph.v1alpha.ExcludeAccessListsMembers 6, // 7: accessgraph.v1alpha.EventsStreamV2Request.sync:type_name -> accessgraph.v1alpha.SyncOperation - 26, // 8: accessgraph.v1alpha.EventsStreamV2Request.upsert:type_name -> accessgraph.v1alpha.ResourceList - 27, // 9: accessgraph.v1alpha.EventsStreamV2Request.delete:type_name -> accessgraph.v1alpha.ResourceHeaderList - 28, // 10: accessgraph.v1alpha.EventsStreamV2Request.access_lists_members:type_name -> accessgraph.v1alpha.AccessListsMembers - 29, // 11: accessgraph.v1alpha.EventsStreamV2Request.exclude_access_list_members:type_name -> accessgraph.v1alpha.ExcludeAccessListsMembers + 29, // 8: accessgraph.v1alpha.EventsStreamV2Request.upsert:type_name -> accessgraph.v1alpha.ResourceList + 30, // 9: accessgraph.v1alpha.EventsStreamV2Request.delete:type_name -> accessgraph.v1alpha.ResourceHeaderList + 31, // 10: accessgraph.v1alpha.EventsStreamV2Request.access_lists_members:type_name -> accessgraph.v1alpha.AccessListsMembers + 32, // 11: accessgraph.v1alpha.EventsStreamV2Request.exclude_access_list_members:type_name -> accessgraph.v1alpha.ExcludeAccessListsMembers 9, // 12: accessgraph.v1alpha.EventsStreamV2Response.event:type_name -> accessgraph.v1alpha.AuditEvent - 30, // 13: accessgraph.v1alpha.AuditEvent.access_path_changed:type_name -> accessgraph.v1alpha.AccessPathChanged + 33, // 13: accessgraph.v1alpha.AuditEvent.access_path_changed:type_name -> accessgraph.v1alpha.AccessPathChanged 15, // 14: accessgraph.v1alpha.AWSEventsStreamRequest.sync:type_name -> accessgraph.v1alpha.AWSSyncOperation - 31, // 15: accessgraph.v1alpha.AWSEventsStreamRequest.upsert:type_name -> accessgraph.v1alpha.AWSResourceList - 31, // 16: accessgraph.v1alpha.AWSEventsStreamRequest.delete:type_name -> accessgraph.v1alpha.AWSResourceList - 32, // 17: accessgraph.v1alpha.GitlabEventsStreamRequest.sync:type_name -> accessgraph.v1alpha.GitlabSyncOperation - 33, // 18: accessgraph.v1alpha.GitlabEventsStreamRequest.upsert:type_name -> accessgraph.v1alpha.GitlabResourceList - 33, // 19: accessgraph.v1alpha.GitlabEventsStreamRequest.delete:type_name -> accessgraph.v1alpha.GitlabResourceList - 34, // 20: accessgraph.v1alpha.EntraEventsStreamRequest.sync:type_name -> accessgraph.v1alpha.EntraSyncOperation - 35, // 21: accessgraph.v1alpha.EntraEventsStreamRequest.upsert:type_name -> accessgraph.v1alpha.EntraResourceList - 35, // 22: accessgraph.v1alpha.EntraEventsStreamRequest.delete:type_name -> accessgraph.v1alpha.EntraResourceList + 34, // 15: accessgraph.v1alpha.AWSEventsStreamRequest.upsert:type_name -> accessgraph.v1alpha.AWSResourceList + 34, // 16: accessgraph.v1alpha.AWSEventsStreamRequest.delete:type_name -> accessgraph.v1alpha.AWSResourceList + 35, // 17: accessgraph.v1alpha.GitlabEventsStreamRequest.sync:type_name -> accessgraph.v1alpha.GitlabSyncOperation + 36, // 18: accessgraph.v1alpha.GitlabEventsStreamRequest.upsert:type_name -> accessgraph.v1alpha.GitlabResourceList + 36, // 19: accessgraph.v1alpha.GitlabEventsStreamRequest.delete:type_name -> accessgraph.v1alpha.GitlabResourceList + 37, // 20: accessgraph.v1alpha.EntraEventsStreamRequest.sync:type_name -> accessgraph.v1alpha.EntraSyncOperation + 38, // 21: accessgraph.v1alpha.EntraEventsStreamRequest.upsert:type_name -> accessgraph.v1alpha.EntraResourceList + 38, // 22: accessgraph.v1alpha.EntraEventsStreamRequest.delete:type_name -> accessgraph.v1alpha.EntraResourceList 22, // 23: accessgraph.v1alpha.NetIQEventsStreamRequest.sync:type_name -> accessgraph.v1alpha.NetIQSyncOperation - 36, // 24: accessgraph.v1alpha.NetIQEventsStreamRequest.upsert:type_name -> accessgraph.v1alpha.NetIQResourceList - 36, // 25: accessgraph.v1alpha.NetIQEventsStreamRequest.delete:type_name -> accessgraph.v1alpha.NetIQResourceList - 0, // 26: accessgraph.v1alpha.AccessGraphService.Query:input_type -> accessgraph.v1alpha.QueryRequest - 2, // 27: accessgraph.v1alpha.AccessGraphService.GetFile:input_type -> accessgraph.v1alpha.GetFileRequest - 4, // 28: accessgraph.v1alpha.AccessGraphService.EventsStream:input_type -> accessgraph.v1alpha.EventsStreamRequest - 5, // 29: accessgraph.v1alpha.AccessGraphService.EventsStreamV2:input_type -> accessgraph.v1alpha.EventsStreamV2Request - 10, // 30: accessgraph.v1alpha.AccessGraphService.Register:input_type -> accessgraph.v1alpha.RegisterRequest - 12, // 31: accessgraph.v1alpha.AccessGraphService.ReplaceCAs:input_type -> accessgraph.v1alpha.ReplaceCAsRequest - 14, // 32: accessgraph.v1alpha.AccessGraphService.AWSEventsStream:input_type -> accessgraph.v1alpha.AWSEventsStreamRequest - 17, // 33: accessgraph.v1alpha.AccessGraphService.GitlabEventsStream:input_type -> accessgraph.v1alpha.GitlabEventsStreamRequest - 19, // 34: accessgraph.v1alpha.AccessGraphService.EntraEventsStream:input_type -> accessgraph.v1alpha.EntraEventsStreamRequest - 21, // 35: accessgraph.v1alpha.AccessGraphService.NetIQEventsStream:input_type -> accessgraph.v1alpha.NetIQEventsStreamRequest - 1, // 36: accessgraph.v1alpha.AccessGraphService.Query:output_type -> accessgraph.v1alpha.QueryResponse - 3, // 37: accessgraph.v1alpha.AccessGraphService.GetFile:output_type -> accessgraph.v1alpha.GetFileResponse - 7, // 38: accessgraph.v1alpha.AccessGraphService.EventsStream:output_type -> accessgraph.v1alpha.EventsStreamResponse - 8, // 39: accessgraph.v1alpha.AccessGraphService.EventsStreamV2:output_type -> accessgraph.v1alpha.EventsStreamV2Response - 11, // 40: accessgraph.v1alpha.AccessGraphService.Register:output_type -> accessgraph.v1alpha.RegisterResponse - 13, // 41: accessgraph.v1alpha.AccessGraphService.ReplaceCAs:output_type -> accessgraph.v1alpha.ReplaceCAsResponse - 16, // 42: accessgraph.v1alpha.AccessGraphService.AWSEventsStream:output_type -> accessgraph.v1alpha.AWSEventsStreamResponse - 18, // 43: accessgraph.v1alpha.AccessGraphService.GitlabEventsStream:output_type -> accessgraph.v1alpha.GitlabEventsStreamResponse - 20, // 44: accessgraph.v1alpha.AccessGraphService.EntraEventsStream:output_type -> accessgraph.v1alpha.EntraEventsStreamResponse - 23, // 45: accessgraph.v1alpha.AccessGraphService.NetIQEventsStream:output_type -> accessgraph.v1alpha.NetIQEventsStreamResponse - 36, // [36:46] is the sub-list for method output_type - 26, // [26:36] is the sub-list for method input_type - 26, // [26:26] is the sub-list for extension type_name - 26, // [26:26] is the sub-list for extension extendee - 0, // [0:26] is the sub-list for field type_name + 39, // 24: accessgraph.v1alpha.NetIQEventsStreamRequest.upsert:type_name -> accessgraph.v1alpha.NetIQResourceList + 39, // 25: accessgraph.v1alpha.NetIQEventsStreamRequest.delete:type_name -> accessgraph.v1alpha.NetIQResourceList + 25, // 26: accessgraph.v1alpha.AzureEventsStreamRequest.sync:type_name -> accessgraph.v1alpha.AzureSyncOperation + 40, // 27: accessgraph.v1alpha.AzureEventsStreamRequest.upsert:type_name -> accessgraph.v1alpha.AzureResourceList + 40, // 28: accessgraph.v1alpha.AzureEventsStreamRequest.delete:type_name -> accessgraph.v1alpha.AzureResourceList + 0, // 29: accessgraph.v1alpha.AccessGraphService.Query:input_type -> accessgraph.v1alpha.QueryRequest + 2, // 30: accessgraph.v1alpha.AccessGraphService.GetFile:input_type -> accessgraph.v1alpha.GetFileRequest + 4, // 31: accessgraph.v1alpha.AccessGraphService.EventsStream:input_type -> accessgraph.v1alpha.EventsStreamRequest + 5, // 32: accessgraph.v1alpha.AccessGraphService.EventsStreamV2:input_type -> accessgraph.v1alpha.EventsStreamV2Request + 10, // 33: accessgraph.v1alpha.AccessGraphService.Register:input_type -> accessgraph.v1alpha.RegisterRequest + 12, // 34: accessgraph.v1alpha.AccessGraphService.ReplaceCAs:input_type -> accessgraph.v1alpha.ReplaceCAsRequest + 14, // 35: accessgraph.v1alpha.AccessGraphService.AWSEventsStream:input_type -> accessgraph.v1alpha.AWSEventsStreamRequest + 17, // 36: accessgraph.v1alpha.AccessGraphService.GitlabEventsStream:input_type -> accessgraph.v1alpha.GitlabEventsStreamRequest + 19, // 37: accessgraph.v1alpha.AccessGraphService.EntraEventsStream:input_type -> accessgraph.v1alpha.EntraEventsStreamRequest + 21, // 38: accessgraph.v1alpha.AccessGraphService.NetIQEventsStream:input_type -> accessgraph.v1alpha.NetIQEventsStreamRequest + 24, // 39: accessgraph.v1alpha.AccessGraphService.AzureEventsStream:input_type -> accessgraph.v1alpha.AzureEventsStreamRequest + 1, // 40: accessgraph.v1alpha.AccessGraphService.Query:output_type -> accessgraph.v1alpha.QueryResponse + 3, // 41: accessgraph.v1alpha.AccessGraphService.GetFile:output_type -> accessgraph.v1alpha.GetFileResponse + 7, // 42: accessgraph.v1alpha.AccessGraphService.EventsStream:output_type -> accessgraph.v1alpha.EventsStreamResponse + 8, // 43: accessgraph.v1alpha.AccessGraphService.EventsStreamV2:output_type -> accessgraph.v1alpha.EventsStreamV2Response + 11, // 44: accessgraph.v1alpha.AccessGraphService.Register:output_type -> accessgraph.v1alpha.RegisterResponse + 13, // 45: accessgraph.v1alpha.AccessGraphService.ReplaceCAs:output_type -> accessgraph.v1alpha.ReplaceCAsResponse + 16, // 46: accessgraph.v1alpha.AccessGraphService.AWSEventsStream:output_type -> accessgraph.v1alpha.AWSEventsStreamResponse + 18, // 47: accessgraph.v1alpha.AccessGraphService.GitlabEventsStream:output_type -> accessgraph.v1alpha.GitlabEventsStreamResponse + 20, // 48: accessgraph.v1alpha.AccessGraphService.EntraEventsStream:output_type -> accessgraph.v1alpha.EntraEventsStreamResponse + 23, // 49: accessgraph.v1alpha.AccessGraphService.NetIQEventsStream:output_type -> accessgraph.v1alpha.NetIQEventsStreamResponse + 26, // 50: accessgraph.v1alpha.AccessGraphService.AzureEventsStream:output_type -> accessgraph.v1alpha.AzureEventsStreamResponse + 40, // [40:51] is the sub-list for method output_type + 29, // [29:40] is the sub-list for method input_type + 29, // [29:29] is the sub-list for extension type_name + 29, // [29:29] is the sub-list for extension extendee + 0, // [0:29] is the sub-list for field type_name } func init() { file_accessgraph_v1alpha_access_graph_service_proto_init() } @@ -1892,6 +2102,7 @@ func file_accessgraph_v1alpha_access_graph_service_proto_init() { return } file_accessgraph_v1alpha_aws_proto_init() + file_accessgraph_v1alpha_azure_proto_init() file_accessgraph_v1alpha_entra_proto_init() file_accessgraph_v1alpha_events_proto_init() file_accessgraph_v1alpha_gitlab_proto_init() @@ -1938,13 +2149,18 @@ func file_accessgraph_v1alpha_access_graph_service_proto_init() { (*NetIQEventsStreamRequest_Upsert)(nil), (*NetIQEventsStreamRequest_Delete)(nil), } + file_accessgraph_v1alpha_access_graph_service_proto_msgTypes[24].OneofWrappers = []any{ + (*AzureEventsStreamRequest_Sync)(nil), + (*AzureEventsStreamRequest_Upsert)(nil), + (*AzureEventsStreamRequest_Delete)(nil), + } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_accessgraph_v1alpha_access_graph_service_proto_rawDesc, NumEnums: 0, - NumMessages: 24, + NumMessages: 27, NumExtensions: 0, NumServices: 1, }, diff --git a/gen/proto/go/accessgraph/v1alpha/access_graph_service_grpc.pb.go b/gen/proto/go/accessgraph/v1alpha/access_graph_service_grpc.pb.go index 6ac7cb8f4de55..0d91b2ea22a8f 100644 --- a/gen/proto/go/accessgraph/v1alpha/access_graph_service_grpc.pb.go +++ b/gen/proto/go/accessgraph/v1alpha/access_graph_service_grpc.pb.go @@ -46,6 +46,7 @@ const ( AccessGraphService_GitlabEventsStream_FullMethodName = "/accessgraph.v1alpha.AccessGraphService/GitlabEventsStream" AccessGraphService_EntraEventsStream_FullMethodName = "/accessgraph.v1alpha.AccessGraphService/EntraEventsStream" AccessGraphService_NetIQEventsStream_FullMethodName = "/accessgraph.v1alpha.AccessGraphService/NetIQEventsStream" + AccessGraphService_AzureEventsStream_FullMethodName = "/accessgraph.v1alpha.AccessGraphService/AzureEventsStream" ) // AccessGraphServiceClient is the client API for AccessGraphService service. @@ -95,6 +96,8 @@ type AccessGraphServiceClient interface { EntraEventsStream(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[EntraEventsStreamRequest, EntraEventsStreamResponse], error) // NetIQEventsStream is a stream of commands to the NetIQ importer. NetIQEventsStream(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[NetIQEventsStreamRequest, NetIQEventsStreamResponse], error) + // AzureEventsStream is a stream of commands to the Azure importer + AzureEventsStream(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[AzureEventsStreamRequest, AzureEventsStreamResponse], error) } type accessGraphServiceClient struct { @@ -223,6 +226,19 @@ func (c *accessGraphServiceClient) NetIQEventsStream(ctx context.Context, opts . // This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. type AccessGraphService_NetIQEventsStreamClient = grpc.BidiStreamingClient[NetIQEventsStreamRequest, NetIQEventsStreamResponse] +func (c *accessGraphServiceClient) AzureEventsStream(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[AzureEventsStreamRequest, AzureEventsStreamResponse], error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &AccessGraphService_ServiceDesc.Streams[6], AccessGraphService_AzureEventsStream_FullMethodName, cOpts...) + if err != nil { + return nil, err + } + x := &grpc.GenericClientStream[AzureEventsStreamRequest, AzureEventsStreamResponse]{ClientStream: stream} + return x, nil +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type AccessGraphService_AzureEventsStreamClient = grpc.BidiStreamingClient[AzureEventsStreamRequest, AzureEventsStreamResponse] + // AccessGraphServiceServer is the server API for AccessGraphService service. // All implementations must embed UnimplementedAccessGraphServiceServer // for forward compatibility. @@ -270,6 +286,8 @@ type AccessGraphServiceServer interface { EntraEventsStream(grpc.BidiStreamingServer[EntraEventsStreamRequest, EntraEventsStreamResponse]) error // NetIQEventsStream is a stream of commands to the NetIQ importer. NetIQEventsStream(grpc.BidiStreamingServer[NetIQEventsStreamRequest, NetIQEventsStreamResponse]) error + // AzureEventsStream is a stream of commands to the Azure importer + AzureEventsStream(grpc.BidiStreamingServer[AzureEventsStreamRequest, AzureEventsStreamResponse]) error mustEmbedUnimplementedAccessGraphServiceServer() } @@ -310,6 +328,9 @@ func (UnimplementedAccessGraphServiceServer) EntraEventsStream(grpc.BidiStreamin func (UnimplementedAccessGraphServiceServer) NetIQEventsStream(grpc.BidiStreamingServer[NetIQEventsStreamRequest, NetIQEventsStreamResponse]) error { return status.Errorf(codes.Unimplemented, "method NetIQEventsStream not implemented") } +func (UnimplementedAccessGraphServiceServer) AzureEventsStream(grpc.BidiStreamingServer[AzureEventsStreamRequest, AzureEventsStreamResponse]) error { + return status.Errorf(codes.Unimplemented, "method AzureEventsStream not implemented") +} func (UnimplementedAccessGraphServiceServer) mustEmbedUnimplementedAccessGraphServiceServer() {} func (UnimplementedAccessGraphServiceServer) testEmbeddedByValue() {} @@ -445,6 +466,13 @@ func _AccessGraphService_NetIQEventsStream_Handler(srv interface{}, stream grpc. // This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. type AccessGraphService_NetIQEventsStreamServer = grpc.BidiStreamingServer[NetIQEventsStreamRequest, NetIQEventsStreamResponse] +func _AccessGraphService_AzureEventsStream_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(AccessGraphServiceServer).AzureEventsStream(&grpc.GenericServerStream[AzureEventsStreamRequest, AzureEventsStreamResponse]{ServerStream: stream}) +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type AccessGraphService_AzureEventsStreamServer = grpc.BidiStreamingServer[AzureEventsStreamRequest, AzureEventsStreamResponse] + // AccessGraphService_ServiceDesc is the grpc.ServiceDesc for AccessGraphService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -504,6 +532,12 @@ var AccessGraphService_ServiceDesc = grpc.ServiceDesc{ ServerStreams: true, ClientStreams: true, }, + { + StreamName: "AzureEventsStream", + Handler: _AccessGraphService_AzureEventsStream_Handler, + ServerStreams: true, + ClientStreams: true, + }, }, Metadata: "accessgraph/v1alpha/access_graph_service.proto", } diff --git a/gen/proto/go/accessgraph/v1alpha/azure.pb.go b/gen/proto/go/accessgraph/v1alpha/azure.pb.go new file mode 100644 index 0000000000000..614433025a228 --- /dev/null +++ b/gen/proto/go/accessgraph/v1alpha/azure.pb.go @@ -0,0 +1,979 @@ +// +// 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 . + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.35.1 +// protoc (unknown) +// source: accessgraph/v1alpha/azure.proto + +package accessgraphv1alpha + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// AzureResourceList is a list of Azure resources +type AzureResourceList struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Resources []*AzureResource `protobuf:"bytes,1,rep,name=resources,proto3" json:"resources,omitempty"` +} + +func (x *AzureResourceList) Reset() { + *x = AzureResourceList{} + mi := &file_accessgraph_v1alpha_azure_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AzureResourceList) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AzureResourceList) ProtoMessage() {} + +func (x *AzureResourceList) ProtoReflect() protoreflect.Message { + mi := &file_accessgraph_v1alpha_azure_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AzureResourceList.ProtoReflect.Descriptor instead. +func (*AzureResourceList) Descriptor() ([]byte, []int) { + return file_accessgraph_v1alpha_azure_proto_rawDescGZIP(), []int{0} +} + +func (x *AzureResourceList) GetResources() []*AzureResource { + if x != nil { + return x.Resources + } + return nil +} + +// AzureResource is a list of Azure resources supported by the access graph. +type AzureResource struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Resource: + // + // *AzureResource_Principal + // *AzureResource_RoleDefinition + // *AzureResource_RoleAssignment + // *AzureResource_VirtualMachine + Resource isAzureResource_Resource `protobuf_oneof:"resource"` +} + +func (x *AzureResource) Reset() { + *x = AzureResource{} + mi := &file_accessgraph_v1alpha_azure_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AzureResource) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AzureResource) ProtoMessage() {} + +func (x *AzureResource) ProtoReflect() protoreflect.Message { + mi := &file_accessgraph_v1alpha_azure_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AzureResource.ProtoReflect.Descriptor instead. +func (*AzureResource) Descriptor() ([]byte, []int) { + return file_accessgraph_v1alpha_azure_proto_rawDescGZIP(), []int{1} +} + +func (m *AzureResource) GetResource() isAzureResource_Resource { + if m != nil { + return m.Resource + } + return nil +} + +func (x *AzureResource) GetPrincipal() *AzurePrincipal { + if x, ok := x.GetResource().(*AzureResource_Principal); ok { + return x.Principal + } + return nil +} + +func (x *AzureResource) GetRoleDefinition() *AzureRoleDefinition { + if x, ok := x.GetResource().(*AzureResource_RoleDefinition); ok { + return x.RoleDefinition + } + return nil +} + +func (x *AzureResource) GetRoleAssignment() *AzureRoleAssignment { + if x, ok := x.GetResource().(*AzureResource_RoleAssignment); ok { + return x.RoleAssignment + } + return nil +} + +func (x *AzureResource) GetVirtualMachine() *AzureVirtualMachine { + if x, ok := x.GetResource().(*AzureResource_VirtualMachine); ok { + return x.VirtualMachine + } + return nil +} + +type isAzureResource_Resource interface { + isAzureResource_Resource() +} + +type AzureResource_Principal struct { + // principal is an Azure principal + Principal *AzurePrincipal `protobuf:"bytes,1,opt,name=principal,proto3,oneof"` +} + +type AzureResource_RoleDefinition struct { + // role_definition is an Azure role definition + RoleDefinition *AzureRoleDefinition `protobuf:"bytes,2,opt,name=role_definition,json=roleDefinition,proto3,oneof"` +} + +type AzureResource_RoleAssignment struct { + // role_assignment is an Azure role assignment, which assigns a role definition to a principal + RoleAssignment *AzureRoleAssignment `protobuf:"bytes,3,opt,name=role_assignment,json=roleAssignment,proto3,oneof"` +} + +type AzureResource_VirtualMachine struct { + // virtual_machine is an Azure virtual machine, an instance of a compute resource + VirtualMachine *AzureVirtualMachine `protobuf:"bytes,4,opt,name=virtual_machine,json=virtualMachine,proto3,oneof"` +} + +func (*AzureResource_Principal) isAzureResource_Resource() {} + +func (*AzureResource_RoleDefinition) isAzureResource_Resource() {} + +func (*AzureResource_RoleAssignment) isAzureResource_Resource() {} + +func (*AzureResource_VirtualMachine) isAzureResource_Resource() {} + +// AzureVirtualMachine is an Azure virtual machine +type AzureVirtualMachine struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // id is the ID of the virtual machine + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // subscription_id is the ID of the subscription to which the virtual machine belongs + SubscriptionId string `protobuf:"bytes,2,opt,name=subscription_id,json=subscriptionId,proto3" json:"subscription_id,omitempty"` + // last_sync_time is when the virtual machine was last fetched from Azure + LastSyncTime *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=last_sync_time,json=lastSyncTime,proto3" json:"last_sync_time,omitempty"` + // name is the given name of the virtual machine + Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name,omitempty"` + // resource_group is the name of the resource group to which the virtual machine belongs + ResourceGroup string `protobuf:"bytes,5,opt,name=resource_group,json=resourceGroup,proto3" json:"resource_group,omitempty"` + // tags are a collection of arbitrary key-values applied to the virtual machine + Tags map[string]string `protobuf:"bytes,6,rep,name=tags,proto3" json:"tags,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // location is the geographical location of the Virtual Machine + Location string `protobuf:"bytes,7,opt,name=location,proto3" json:"location,omitempty"` +} + +func (x *AzureVirtualMachine) Reset() { + *x = AzureVirtualMachine{} + mi := &file_accessgraph_v1alpha_azure_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AzureVirtualMachine) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AzureVirtualMachine) ProtoMessage() {} + +func (x *AzureVirtualMachine) ProtoReflect() protoreflect.Message { + mi := &file_accessgraph_v1alpha_azure_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AzureVirtualMachine.ProtoReflect.Descriptor instead. +func (*AzureVirtualMachine) Descriptor() ([]byte, []int) { + return file_accessgraph_v1alpha_azure_proto_rawDescGZIP(), []int{2} +} + +func (x *AzureVirtualMachine) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *AzureVirtualMachine) GetSubscriptionId() string { + if x != nil { + return x.SubscriptionId + } + return "" +} + +func (x *AzureVirtualMachine) GetLastSyncTime() *timestamppb.Timestamp { + if x != nil { + return x.LastSyncTime + } + return nil +} + +func (x *AzureVirtualMachine) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *AzureVirtualMachine) GetResourceGroup() string { + if x != nil { + return x.ResourceGroup + } + return "" +} + +func (x *AzureVirtualMachine) GetTags() map[string]string { + if x != nil { + return x.Tags + } + return nil +} + +func (x *AzureVirtualMachine) GetLocation() string { + if x != nil { + return x.Location + } + return "" +} + +// AzureIdentity is a Graph API object identity +type AzureIdentity struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // sign_in_type is the type of identity used when signing in, e.g. "emailAddress" or "userName" + SignInType string `protobuf:"bytes,1,opt,name=sign_in_type,json=signInType,proto3" json:"sign_in_type,omitempty"` + // issuer is the issuer of the identity, such as a domain name like "goteleport.com" + Issuer string `protobuf:"bytes,2,opt,name=issuer,proto3" json:"issuer,omitempty"` + // issuer_assigned_id unique identifier assigned to the user by the issuer + IssuerAssignedId string `protobuf:"bytes,3,opt,name=issuer_assigned_id,json=issuerAssignedId,proto3" json:"issuer_assigned_id,omitempty"` +} + +func (x *AzureIdentity) Reset() { + *x = AzureIdentity{} + mi := &file_accessgraph_v1alpha_azure_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AzureIdentity) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AzureIdentity) ProtoMessage() {} + +func (x *AzureIdentity) ProtoReflect() protoreflect.Message { + mi := &file_accessgraph_v1alpha_azure_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AzureIdentity.ProtoReflect.Descriptor instead. +func (*AzureIdentity) Descriptor() ([]byte, []int) { + return file_accessgraph_v1alpha_azure_proto_rawDescGZIP(), []int{3} +} + +func (x *AzureIdentity) GetSignInType() string { + if x != nil { + return x.SignInType + } + return "" +} + +func (x *AzureIdentity) GetIssuer() string { + if x != nil { + return x.Issuer + } + return "" +} + +func (x *AzureIdentity) GetIssuerAssignedId() string { + if x != nil { + return x.IssuerAssignedId + } + return "" +} + +// AzurePrincipal is a Graph API principal (user, group, service principal) +type AzurePrincipal struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // id is the ID of the principal + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // subscription_id is the ID of the subscription to which the principal belongs + SubscriptionId string `protobuf:"bytes,2,opt,name=subscription_id,json=subscriptionId,proto3" json:"subscription_id,omitempty"` + // last_sync_time is when the principal was last fetched from Azure + LastSyncTime *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=last_sync_time,json=lastSyncTime,proto3" json:"last_sync_time,omitempty"` + // display_name is the given name for the principal, e.g. a user's first+last name + DisplayName string `protobuf:"bytes,4,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` + // member_of lists the groups and directories the principal is assigned to + MemberOf []string `protobuf:"bytes,5,rep,name=member_of,json=memberOf,proto3" json:"member_of,omitempty"` + // identities lists the identities that can be used to sign in to the account + Identities []*AzureIdentity `protobuf:"bytes,6,rep,name=identities,proto3" json:"identities,omitempty"` + // object_type defines the type of principal, e.g. "user" or "group" + ObjectType string `protobuf:"bytes,7,opt,name=object_type,json=objectType,proto3" json:"object_type,omitempty"` +} + +func (x *AzurePrincipal) Reset() { + *x = AzurePrincipal{} + mi := &file_accessgraph_v1alpha_azure_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AzurePrincipal) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AzurePrincipal) ProtoMessage() {} + +func (x *AzurePrincipal) ProtoReflect() protoreflect.Message { + mi := &file_accessgraph_v1alpha_azure_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AzurePrincipal.ProtoReflect.Descriptor instead. +func (*AzurePrincipal) Descriptor() ([]byte, []int) { + return file_accessgraph_v1alpha_azure_proto_rawDescGZIP(), []int{4} +} + +func (x *AzurePrincipal) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *AzurePrincipal) GetSubscriptionId() string { + if x != nil { + return x.SubscriptionId + } + return "" +} + +func (x *AzurePrincipal) GetLastSyncTime() *timestamppb.Timestamp { + if x != nil { + return x.LastSyncTime + } + return nil +} + +func (x *AzurePrincipal) GetDisplayName() string { + if x != nil { + return x.DisplayName + } + return "" +} + +func (x *AzurePrincipal) GetMemberOf() []string { + if x != nil { + return x.MemberOf + } + return nil +} + +func (x *AzurePrincipal) GetIdentities() []*AzureIdentity { + if x != nil { + return x.Identities + } + return nil +} + +func (x *AzurePrincipal) GetObjectType() string { + if x != nil { + return x.ObjectType + } + return "" +} + +// AzureRoleAssignment links an Azure principal to a role definition with a scope +type AzureRoleAssignment struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // id is the ID of the role assignment + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // subscription_id is the ID of the subscription to which the role assignment belongs + SubscriptionId string `protobuf:"bytes,2,opt,name=subscription_id,json=subscriptionId,proto3" json:"subscription_id,omitempty"` + // last_sync_time is when the role assignment was last fetched from Azure + LastSyncTime *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=last_sync_time,json=lastSyncTime,proto3" json:"last_sync_time,omitempty"` + // principal_id is the ID of the principal being assigned a role + PrincipalId string `protobuf:"bytes,4,opt,name=principal_id,json=principalId,proto3" json:"principal_id,omitempty"` + // role_definition_id is the ID of the role definition assigned to the principal + RoleDefinitionId string `protobuf:"bytes,5,opt,name=role_definition_id,json=roleDefinitionId,proto3" json:"role_definition_id,omitempty"` + // scope constrains which resources the assignment applies to + Scope string `protobuf:"bytes,6,opt,name=scope,proto3" json:"scope,omitempty"` + // condition further which resources the assignment applies to + Condition string `protobuf:"bytes,7,opt,name=condition,proto3" json:"condition,omitempty"` +} + +func (x *AzureRoleAssignment) Reset() { + *x = AzureRoleAssignment{} + mi := &file_accessgraph_v1alpha_azure_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AzureRoleAssignment) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AzureRoleAssignment) ProtoMessage() {} + +func (x *AzureRoleAssignment) ProtoReflect() protoreflect.Message { + mi := &file_accessgraph_v1alpha_azure_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AzureRoleAssignment.ProtoReflect.Descriptor instead. +func (*AzureRoleAssignment) Descriptor() ([]byte, []int) { + return file_accessgraph_v1alpha_azure_proto_rawDescGZIP(), []int{5} +} + +func (x *AzureRoleAssignment) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *AzureRoleAssignment) GetSubscriptionId() string { + if x != nil { + return x.SubscriptionId + } + return "" +} + +func (x *AzureRoleAssignment) GetLastSyncTime() *timestamppb.Timestamp { + if x != nil { + return x.LastSyncTime + } + return nil +} + +func (x *AzureRoleAssignment) GetPrincipalId() string { + if x != nil { + return x.PrincipalId + } + return "" +} + +func (x *AzureRoleAssignment) GetRoleDefinitionId() string { + if x != nil { + return x.RoleDefinitionId + } + return "" +} + +func (x *AzureRoleAssignment) GetScope() string { + if x != nil { + return x.Scope + } + return "" +} + +func (x *AzureRoleAssignment) GetCondition() string { + if x != nil { + return x.Condition + } + return "" +} + +// AzureRoleDefinition defines a role by its permissions +type AzureRoleDefinition struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // id is the ID of the role definition + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // subscription_id is the ID of the subscription to which the role definition belongs + SubscriptionId string `protobuf:"bytes,2,opt,name=subscription_id,json=subscriptionId,proto3" json:"subscription_id,omitempty"` + // last_sync_time is when the role definition was last fetched from Azure + LastSyncTime *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=last_sync_time,json=lastSyncTime,proto3" json:"last_sync_time,omitempty"` + // name is the given name for the role definition + Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name,omitempty"` + // description provides additional detail about the role definition + Description string `protobuf:"bytes,5,opt,name=description,proto3" json:"description,omitempty"` + // assignable_scopes limits the scopes defined in corresponding role assignments + AssignableScopes []string `protobuf:"bytes,6,rep,name=assignable_scopes,json=assignableScopes,proto3" json:"assignable_scopes,omitempty"` + // permissions define the actions and not (disallowed) actions + Permissions []*AzureRBACPermission `protobuf:"bytes,7,rep,name=permissions,proto3" json:"permissions,omitempty"` + // role_name is the given name for the role itself + RoleName string `protobuf:"bytes,8,opt,name=role_name,json=roleName,proto3" json:"role_name,omitempty"` + // type defines the type of role + Type string `protobuf:"bytes,9,opt,name=type,proto3" json:"type,omitempty"` +} + +func (x *AzureRoleDefinition) Reset() { + *x = AzureRoleDefinition{} + mi := &file_accessgraph_v1alpha_azure_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AzureRoleDefinition) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AzureRoleDefinition) ProtoMessage() {} + +func (x *AzureRoleDefinition) ProtoReflect() protoreflect.Message { + mi := &file_accessgraph_v1alpha_azure_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AzureRoleDefinition.ProtoReflect.Descriptor instead. +func (*AzureRoleDefinition) Descriptor() ([]byte, []int) { + return file_accessgraph_v1alpha_azure_proto_rawDescGZIP(), []int{6} +} + +func (x *AzureRoleDefinition) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *AzureRoleDefinition) GetSubscriptionId() string { + if x != nil { + return x.SubscriptionId + } + return "" +} + +func (x *AzureRoleDefinition) GetLastSyncTime() *timestamppb.Timestamp { + if x != nil { + return x.LastSyncTime + } + return nil +} + +func (x *AzureRoleDefinition) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *AzureRoleDefinition) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *AzureRoleDefinition) GetAssignableScopes() []string { + if x != nil { + return x.AssignableScopes + } + return nil +} + +func (x *AzureRoleDefinition) GetPermissions() []*AzureRBACPermission { + if x != nil { + return x.Permissions + } + return nil +} + +func (x *AzureRoleDefinition) GetRoleName() string { + if x != nil { + return x.RoleName + } + return "" +} + +func (x *AzureRoleDefinition) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +// AzureRBACPermission defines the actions and not (disallowed) actions for a role definition +type AzureRBACPermission struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // actions define the resources and verbs allowed on the resources + Actions []string `protobuf:"bytes,1,rep,name=actions,proto3" json:"actions,omitempty"` + // not_actions define the resources and verbs disallowed on the resources + NotActions []string `protobuf:"bytes,2,rep,name=not_actions,json=notActions,proto3" json:"not_actions,omitempty"` + // data_actions define fine-grained resources and verbs allowed within the resource + DataActions []string `protobuf:"bytes,3,rep,name=data_actions,json=dataActions,proto3" json:"data_actions,omitempty"` + // not_data_actions define fine-grained resources and verbs disallowed within the resource + NotDataActions []string `protobuf:"bytes,4,rep,name=not_data_actions,json=notDataActions,proto3" json:"not_data_actions,omitempty"` +} + +func (x *AzureRBACPermission) Reset() { + *x = AzureRBACPermission{} + mi := &file_accessgraph_v1alpha_azure_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AzureRBACPermission) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AzureRBACPermission) ProtoMessage() {} + +func (x *AzureRBACPermission) ProtoReflect() protoreflect.Message { + mi := &file_accessgraph_v1alpha_azure_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AzureRBACPermission.ProtoReflect.Descriptor instead. +func (*AzureRBACPermission) Descriptor() ([]byte, []int) { + return file_accessgraph_v1alpha_azure_proto_rawDescGZIP(), []int{7} +} + +func (x *AzureRBACPermission) GetActions() []string { + if x != nil { + return x.Actions + } + return nil +} + +func (x *AzureRBACPermission) GetNotActions() []string { + if x != nil { + return x.NotActions + } + return nil +} + +func (x *AzureRBACPermission) GetDataActions() []string { + if x != nil { + return x.DataActions + } + return nil +} + +func (x *AzureRBACPermission) GetNotDataActions() []string { + if x != nil { + return x.NotDataActions + } + return nil +} + +var File_accessgraph_v1alpha_azure_proto protoreflect.FileDescriptor + +var file_accessgraph_v1alpha_azure_proto_rawDesc = []byte{ + 0x0a, 0x1f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x76, 0x31, + 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2f, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x12, 0x13, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, + 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x55, 0x0a, 0x11, 0x41, 0x7a, 0x75, 0x72, 0x65, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x09, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x22, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, + 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x22, 0xdf, + 0x02, 0x0a, 0x0d, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x12, 0x43, 0x0a, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, + 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x50, + 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x48, 0x00, 0x52, 0x09, 0x70, 0x72, 0x69, 0x6e, + 0x63, 0x69, 0x70, 0x61, 0x6c, 0x12, 0x53, 0x0a, 0x0f, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x64, 0x65, + 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, + 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, + 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x44, 0x65, + 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0e, 0x72, 0x6f, 0x6c, 0x65, + 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x53, 0x0a, 0x0f, 0x72, 0x6f, + 0x6c, 0x65, 0x5f, 0x61, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, + 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x52, + 0x6f, 0x6c, 0x65, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, + 0x0e, 0x72, 0x6f, 0x6c, 0x65, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x12, + 0x53, 0x0a, 0x0f, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x5f, 0x6d, 0x61, 0x63, 0x68, 0x69, + 0x6e, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, + 0x7a, 0x75, 0x72, 0x65, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x4d, 0x61, 0x63, 0x68, 0x69, + 0x6e, 0x65, 0x48, 0x00, 0x52, 0x0e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x4d, 0x61, 0x63, + 0x68, 0x69, 0x6e, 0x65, 0x42, 0x0a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x22, 0xe8, 0x02, 0x0a, 0x13, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, + 0x6c, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x75, 0x62, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x12, 0x40, 0x0a, 0x0e, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x74, + 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x53, 0x79, 0x6e, 0x63, 0x54, + 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x46, + 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x61, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, + 0x68, 0x61, 0x2e, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x4d, + 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2e, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x1a, 0x37, 0x0a, 0x09, 0x54, 0x61, 0x67, 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, 0x77, 0x0a, 0x0d, 0x41, + 0x7a, 0x75, 0x72, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x20, 0x0a, 0x0c, + 0x73, 0x69, 0x67, 0x6e, 0x5f, 0x69, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x73, 0x69, 0x67, 0x6e, 0x49, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, + 0x0a, 0x06, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x12, 0x2c, 0x0a, 0x12, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, + 0x5f, 0x61, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x10, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, + 0x65, 0x64, 0x49, 0x64, 0x22, 0xb0, 0x02, 0x0a, 0x0e, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x50, 0x72, + 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x75, 0x62, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, + 0x12, 0x40, 0x0a, 0x0e, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x74, 0x69, + 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x53, 0x79, 0x6e, 0x63, 0x54, 0x69, + 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, + 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, + 0x6f, 0x66, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, + 0x4f, 0x66, 0x12, 0x42, 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x69, 0x65, 0x73, + 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, + 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x7a, 0x75, + 0x72, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x0a, 0x69, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x69, 0x65, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x22, 0x95, 0x02, 0x0a, 0x13, 0x41, 0x7a, 0x75, 0x72, + 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x27, 0x0a, 0x0f, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x40, 0x0a, 0x0e, 0x6c, 0x61, 0x73, 0x74, + 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x6c, 0x61, + 0x73, 0x74, 0x53, 0x79, 0x6e, 0x63, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, + 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x2c, 0x0a, + 0x12, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x72, 0x6f, 0x6c, 0x65, 0x44, + 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x73, + 0x63, 0x6f, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x70, + 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, + 0xf0, 0x02, 0x0a, 0x13, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x44, 0x65, 0x66, + 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x75, 0x62, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, + 0x12, 0x40, 0x0a, 0x0e, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x74, 0x69, + 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x53, 0x79, 0x6e, 0x63, 0x54, 0x69, + 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2b, 0x0a, 0x11, 0x61, 0x73, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x18, 0x06, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x10, 0x61, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x53, + 0x63, 0x6f, 0x70, 0x65, 0x73, 0x12, 0x4a, 0x0a, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x61, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, + 0x2e, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x52, 0x42, 0x41, 0x43, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x08, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x6f, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, + 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x22, 0x9d, 0x01, 0x0a, 0x13, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x52, 0x42, 0x41, 0x43, + 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x6e, 0x6f, 0x74, 0x5f, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x6e, 0x6f, 0x74, 0x41, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x61, 0x74, + 0x61, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x28, 0x0a, 0x10, 0x6e, 0x6f, 0x74, 0x5f, + 0x64, 0x61, 0x74, 0x61, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x0e, 0x6e, 0x6f, 0x74, 0x44, 0x61, 0x74, 0x61, 0x41, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x42, 0x57, 0x5a, 0x55, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, + 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, + 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x3b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, + 0x72, 0x61, 0x70, 0x68, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, +} + +var ( + file_accessgraph_v1alpha_azure_proto_rawDescOnce sync.Once + file_accessgraph_v1alpha_azure_proto_rawDescData = file_accessgraph_v1alpha_azure_proto_rawDesc +) + +func file_accessgraph_v1alpha_azure_proto_rawDescGZIP() []byte { + file_accessgraph_v1alpha_azure_proto_rawDescOnce.Do(func() { + file_accessgraph_v1alpha_azure_proto_rawDescData = protoimpl.X.CompressGZIP(file_accessgraph_v1alpha_azure_proto_rawDescData) + }) + return file_accessgraph_v1alpha_azure_proto_rawDescData +} + +var file_accessgraph_v1alpha_azure_proto_msgTypes = make([]protoimpl.MessageInfo, 9) +var file_accessgraph_v1alpha_azure_proto_goTypes = []any{ + (*AzureResourceList)(nil), // 0: accessgraph.v1alpha.AzureResourceList + (*AzureResource)(nil), // 1: accessgraph.v1alpha.AzureResource + (*AzureVirtualMachine)(nil), // 2: accessgraph.v1alpha.AzureVirtualMachine + (*AzureIdentity)(nil), // 3: accessgraph.v1alpha.AzureIdentity + (*AzurePrincipal)(nil), // 4: accessgraph.v1alpha.AzurePrincipal + (*AzureRoleAssignment)(nil), // 5: accessgraph.v1alpha.AzureRoleAssignment + (*AzureRoleDefinition)(nil), // 6: accessgraph.v1alpha.AzureRoleDefinition + (*AzureRBACPermission)(nil), // 7: accessgraph.v1alpha.AzureRBACPermission + nil, // 8: accessgraph.v1alpha.AzureVirtualMachine.TagsEntry + (*timestamppb.Timestamp)(nil), // 9: google.protobuf.Timestamp +} +var file_accessgraph_v1alpha_azure_proto_depIdxs = []int32{ + 1, // 0: accessgraph.v1alpha.AzureResourceList.resources:type_name -> accessgraph.v1alpha.AzureResource + 4, // 1: accessgraph.v1alpha.AzureResource.principal:type_name -> accessgraph.v1alpha.AzurePrincipal + 6, // 2: accessgraph.v1alpha.AzureResource.role_definition:type_name -> accessgraph.v1alpha.AzureRoleDefinition + 5, // 3: accessgraph.v1alpha.AzureResource.role_assignment:type_name -> accessgraph.v1alpha.AzureRoleAssignment + 2, // 4: accessgraph.v1alpha.AzureResource.virtual_machine:type_name -> accessgraph.v1alpha.AzureVirtualMachine + 9, // 5: accessgraph.v1alpha.AzureVirtualMachine.last_sync_time:type_name -> google.protobuf.Timestamp + 8, // 6: accessgraph.v1alpha.AzureVirtualMachine.tags:type_name -> accessgraph.v1alpha.AzureVirtualMachine.TagsEntry + 9, // 7: accessgraph.v1alpha.AzurePrincipal.last_sync_time:type_name -> google.protobuf.Timestamp + 3, // 8: accessgraph.v1alpha.AzurePrincipal.identities:type_name -> accessgraph.v1alpha.AzureIdentity + 9, // 9: accessgraph.v1alpha.AzureRoleAssignment.last_sync_time:type_name -> google.protobuf.Timestamp + 9, // 10: accessgraph.v1alpha.AzureRoleDefinition.last_sync_time:type_name -> google.protobuf.Timestamp + 7, // 11: accessgraph.v1alpha.AzureRoleDefinition.permissions:type_name -> accessgraph.v1alpha.AzureRBACPermission + 12, // [12:12] is the sub-list for method output_type + 12, // [12:12] is the sub-list for method input_type + 12, // [12:12] is the sub-list for extension type_name + 12, // [12:12] is the sub-list for extension extendee + 0, // [0:12] is the sub-list for field type_name +} + +func init() { file_accessgraph_v1alpha_azure_proto_init() } +func file_accessgraph_v1alpha_azure_proto_init() { + if File_accessgraph_v1alpha_azure_proto != nil { + return + } + file_accessgraph_v1alpha_azure_proto_msgTypes[1].OneofWrappers = []any{ + (*AzureResource_Principal)(nil), + (*AzureResource_RoleDefinition)(nil), + (*AzureResource_RoleAssignment)(nil), + (*AzureResource_VirtualMachine)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_accessgraph_v1alpha_azure_proto_rawDesc, + NumEnums: 0, + NumMessages: 9, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_accessgraph_v1alpha_azure_proto_goTypes, + DependencyIndexes: file_accessgraph_v1alpha_azure_proto_depIdxs, + MessageInfos: file_accessgraph_v1alpha_azure_proto_msgTypes, + }.Build() + File_accessgraph_v1alpha_azure_proto = out.File + file_accessgraph_v1alpha_azure_proto_rawDesc = nil + file_accessgraph_v1alpha_azure_proto_goTypes = nil + file_accessgraph_v1alpha_azure_proto_depIdxs = nil +} diff --git a/go.mod b/go.mod index e9bd3d3ff7343..2fc6d791cc3b1 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( connectrpc.com/connect v1.17.0 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 + github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2 v2.2.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v3 v3.0.1 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v2 v2.4.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/msi/armmsi v1.2.0 diff --git a/go.sum b/go.sum index a179b9d2656c6..fb47c97e0b736 100644 --- a/go.sum +++ b/go.sum @@ -662,6 +662,8 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLC github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.1/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2 v2.2.0 h1:Hp+EScFOu9HeCbeW8WU2yQPJd4gGwhMgKxWe+G6jNzw= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2 v2.2.0/go.mod h1:/pz8dyNQe+Ey3yBp/XuYz7oqX8YDNWVpPB0hH3XWfbc= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v3 v3.0.1 h1:H3g2mkmu105ON0c/Gqx3Bm+bzoIijLom8LmV9Gjn7X0= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v3 v3.0.1/go.mod h1:EAc3kjhZf9soch7yLID8PeKcE6VfKvQTllSBHYVdXd8= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v2 v2.4.0 h1:1u/K2BFv0MwkG6he8RYuUcbbeK22rkoZbg4lKa/msZU= diff --git a/integrations/event-handler/go.mod b/integrations/event-handler/go.mod index 83471ba1b715a..a8ef92c58a26e 100644 --- a/integrations/event-handler/go.mod +++ b/integrations/event-handler/go.mod @@ -37,6 +37,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2 v2.2.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v3 v3.0.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v2 v2.4.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/msi/armmsi v1.2.0 // indirect diff --git a/integrations/event-handler/go.sum b/integrations/event-handler/go.sum index a853692edb905..b244fdc3a2555 100644 --- a/integrations/event-handler/go.sum +++ b/integrations/event-handler/go.sum @@ -34,6 +34,8 @@ github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 h1:tfLQ34V6F7tVSwoTf/4lH github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2 v2.2.0 h1:Hp+EScFOu9HeCbeW8WU2yQPJd4gGwhMgKxWe+G6jNzw= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2 v2.2.0/go.mod h1:/pz8dyNQe+Ey3yBp/XuYz7oqX8YDNWVpPB0hH3XWfbc= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v3 v3.0.1 h1:H3g2mkmu105ON0c/Gqx3Bm+bzoIijLom8LmV9Gjn7X0= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v3 v3.0.1/go.mod h1:EAc3kjhZf9soch7yLID8PeKcE6VfKvQTllSBHYVdXd8= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v2 v2.4.0 h1:1u/K2BFv0MwkG6he8RYuUcbbeK22rkoZbg4lKa/msZU= diff --git a/integrations/terraform/go.mod b/integrations/terraform/go.mod index 0a1c20e045fcf..8fa22fbcb1d26 100644 --- a/integrations/terraform/go.mod +++ b/integrations/terraform/go.mod @@ -44,6 +44,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2 v2.2.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v3 v3.0.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v2 v2.4.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/msi/armmsi v1.2.0 // indirect diff --git a/integrations/terraform/go.sum b/integrations/terraform/go.sum index 968993e28479d..a65f94e7bb3ef 100644 --- a/integrations/terraform/go.sum +++ b/integrations/terraform/go.sum @@ -77,6 +77,8 @@ github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 h1:tfLQ34V6F7tVSwoTf/4lH github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2 v2.2.0 h1:Hp+EScFOu9HeCbeW8WU2yQPJd4gGwhMgKxWe+G6jNzw= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2 v2.2.0/go.mod h1:/pz8dyNQe+Ey3yBp/XuYz7oqX8YDNWVpPB0hH3XWfbc= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v3 v3.0.1 h1:H3g2mkmu105ON0c/Gqx3Bm+bzoIijLom8LmV9Gjn7X0= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v3 v3.0.1/go.mod h1:EAc3kjhZf9soch7yLID8PeKcE6VfKvQTllSBHYVdXd8= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v2 v2.4.0 h1:1u/K2BFv0MwkG6he8RYuUcbbeK22rkoZbg4lKa/msZU= diff --git a/lib/auth/auth.go b/lib/auth/auth.go index 454ce422bf0ff..deca423e09066 100644 --- a/lib/auth/auth.go +++ b/lib/auth/auth.go @@ -749,6 +749,11 @@ func (r *Services) GenerateAWSOIDCToken(ctx context.Context, integration string) return r.IntegrationsTokenGenerator.GenerateAWSOIDCToken(ctx, integration) } +// GenerateAzureOIDCToken generates a token to be used to execute an Azure OIDC Integration action. +func (r *Services) GenerateAzureOIDCToken(ctx context.Context, integration string) (string, error) { + return r.IntegrationsTokenGenerator.GenerateAzureOIDCToken(ctx, integration) +} + var ( generateRequestsCount = prometheus.NewCounter( prometheus.CounterOpts{ diff --git a/lib/auth/authclient/api.go b/lib/auth/authclient/api.go index c59bb595a2afd..2d0fc4abd6c4b 100644 --- a/lib/auth/authclient/api.go +++ b/lib/auth/authclient/api.go @@ -808,6 +808,9 @@ type DiscoveryAccessPoint interface { // GenerateAWSOIDCToken generates a token to be used to execute an AWS OIDC Integration action. GenerateAWSOIDCToken(ctx context.Context, integration string) (string, error) + // GenerateAzureOIDCToken generates a token to be used to execute an Azure OIDC Integration action. + GenerateAzureOIDCToken(ctx context.Context, integration string) (string, error) + // EnrollEKSClusters enrolls EKS clusters into Teleport by installing teleport-kube-agent chart on the clusters. EnrollEKSClusters(context.Context, *integrationpb.EnrollEKSClustersRequest, ...grpc.CallOption) (*integrationpb.EnrollEKSClustersResponse, error) @@ -1491,6 +1494,11 @@ func (w *DiscoveryWrapper) GenerateAWSOIDCToken(ctx context.Context, integration return w.NoCache.GenerateAWSOIDCToken(ctx, integration) } +// GenerateAzureOIDCToken generates a token to be used to execute an Azure OIDC Integration action. +func (w *DiscoveryWrapper) GenerateAzureOIDCToken(ctx context.Context, integration string) (string, error) { + return w.NoCache.GenerateAzureOIDCToken(ctx, integration) +} + // EnrollEKSClusters enrolls EKS clusters into Teleport by installing teleport-kube-agent chart on the clusters. func (w *DiscoveryWrapper) EnrollEKSClusters(ctx context.Context, req *integrationpb.EnrollEKSClustersRequest, _ ...grpc.CallOption) (*integrationpb.EnrollEKSClustersResponse, error) { return w.NoCache.EnrollEKSClusters(ctx, req) diff --git a/lib/auth/authclient/clt.go b/lib/auth/authclient/clt.go index a8961866a46b4..41bcaabc4762e 100644 --- a/lib/auth/authclient/clt.go +++ b/lib/auth/authclient/clt.go @@ -1724,6 +1724,9 @@ type ClientI interface { // GenerateAWSOIDCToken generates a token to be used to execute an AWS OIDC Integration action. GenerateAWSOIDCToken(ctx context.Context, integration string) (string, error) + // GenerateAzureOIDCToken generates a token to be used to execute an Azure OIDC Integration action. + GenerateAzureOIDCToken(ctx context.Context, integration string) (string, error) + // ResetAuthPreference resets cluster auth preference to defaults. ResetAuthPreference(ctx context.Context) error diff --git a/lib/auth/integration/integrationv1/azureoidc.go b/lib/auth/integration/integrationv1/azureoidc.go new file mode 100644 index 0000000000000..0db1fd50e59d6 --- /dev/null +++ b/lib/auth/integration/integrationv1/azureoidc.go @@ -0,0 +1,52 @@ +/* + * Teleport + * Copyright (C) 2025 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 integrationv1 + +import ( + "context" + + "github.com/gravitational/trace" + + integrationpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/integration/v1" + "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/lib/authz" + "github.com/gravitational/teleport/lib/integrations/azureoidc" +) + +// GenerateAzureOIDCToken generates a token to be used to execute an Azure OIDC Integration action. +func (s *Service) GenerateAzureOIDCToken(ctx context.Context, req *integrationpb.GenerateAzureOIDCTokenRequest) (*integrationpb.GenerateAzureOIDCTokenResponse, error) { + authCtx, err := s.authorizer.Authorize(ctx) + if err != nil { + return nil, trace.Wrap(err) + } + _, err = s.cache.GetIntegration(ctx, req.Integration) + if err != nil { + return nil, trace.Wrap(err) + } + for _, allowedRole := range []types.SystemRole{types.RoleDiscovery, types.RoleAuth, types.RoleProxy} { + if authz.HasBuiltinRole(*authCtx, string(allowedRole)) { + token, err := azureoidc.GenerateEntraOIDCToken(ctx, s.cache, s.keyStoreManager, s.clock) + if err != nil { + return nil, trace.Wrap(err) + } + return &integrationpb.GenerateAzureOIDCTokenResponse{Token: token}, nil + } + } + return nil, trace.AccessDenied("token generation is only available to auth, proxy or discovery services") +} diff --git a/lib/auth/integration/integrationv1/azureoidc_test.go b/lib/auth/integration/integrationv1/azureoidc_test.go new file mode 100644 index 0000000000000..f235d51538d71 --- /dev/null +++ b/lib/auth/integration/integrationv1/azureoidc_test.go @@ -0,0 +1,113 @@ +/* + * Teleport + * Copyright (C) 2025 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 integrationv1 + +import ( + "testing" + + "github.com/gravitational/trace" + "github.com/stretchr/testify/require" + + integrationv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/integration/v1" + "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/api/utils/keys" + "github.com/gravitational/teleport/lib/authz" + "github.com/gravitational/teleport/lib/jwt" + "github.com/gravitational/teleport/lib/tlsca" +) + +func TestGenerateAzureOIDCToken(t *testing.T) { + t.Parallel() + clusterName := "test-cluster" + integrationName := "my-integration" + + publicURL := "https://example.com" + + ca := newCertAuthority(t, types.HostCA, clusterName) + ctx, localClient, resourceSvc := initSvc(t, ca, clusterName, publicURL) + + // Create integration + ig, err := types.NewIntegrationAzureOIDC( + types.Metadata{Name: integrationName}, + &types.AzureOIDCIntegrationSpecV1{ + TenantID: "foo", + ClientID: "bar", + }, + ) + require.NoError(t, err) + _, err = localClient.CreateIntegration(ctx, ig) + require.NoError(t, err) + + t.Run("only Auth, Discovery, and Proxy roles should be able to generate Azure tokens", func(t *testing.T) { + // A dummy user should not be able to generate Azure OIDC tokens + ctx = authorizerForDummyUser(t, ctx, types.RoleSpecV6{ + Allow: types.RoleConditions{Rules: []types.Rule{ + {Resources: []string{types.KindIntegration}, Verbs: []string{types.VerbUse}}, + }}, + }, localClient) + _, err = resourceSvc.GenerateAzureOIDCToken(ctx, &integrationv1.GenerateAzureOIDCTokenRequest{Integration: integrationName}) + require.True(t, trace.IsAccessDenied(err), "expected AccessDenied error, got %T", err) + + // Auth, Discovery, and Proxy roles should be able to generate Azure OIDC tokens + for _, allowedRole := range []types.SystemRole{types.RoleAuth, types.RoleDiscovery, types.RoleProxy} { + ctx = authz.ContextWithUser(ctx, authz.BuiltinRole{ + Role: types.RoleInstance, + AdditionalSystemRoles: []types.SystemRole{allowedRole}, + Username: string(allowedRole), + Identity: tlsca.Identity{ + Username: string(allowedRole), + }, + }) + + _, err := resourceSvc.GenerateAzureOIDCToken(ctx, &integrationv1.GenerateAzureOIDCTokenRequest{Integration: integrationName}) + require.NoError(t, err) + } + }) + + t.Run("validate the Azure token", func(t *testing.T) { + ctx = authz.ContextWithUser(ctx, authz.BuiltinRole{ + Role: types.RoleInstance, + AdditionalSystemRoles: []types.SystemRole{types.RoleDiscovery}, + Username: string(types.RoleDiscovery), + Identity: tlsca.Identity{ + Username: string(types.RoleDiscovery), + }, + }) + resp, err := resourceSvc.GenerateAzureOIDCToken(ctx, &integrationv1.GenerateAzureOIDCTokenRequest{ + Integration: integrationName, + }) + require.NoError(t, err) + + // Validate JWT against public key + require.NotEmpty(t, ca.GetActiveKeys().JWT) + jwtPubKey := ca.GetActiveKeys().JWT[0].PublicKey + publicKey, err := keys.ParsePublicKey(jwtPubKey) + require.NoError(t, err) + key, err := jwt.New(&jwt.Config{ + ClusterName: clusterName, + Clock: resourceSvc.clock, + PublicKey: publicKey, + }) + require.NoError(t, err) + + // Verify the Azure token using the JWT + _, err = key.VerifyAzureToken(resp.Token) + require.NoError(t, err) + }) +} diff --git a/lib/cloud/azure/roleassignments.go b/lib/cloud/azure/roleassignments.go new file mode 100644 index 0000000000000..114bceef88b96 --- /dev/null +++ b/lib/cloud/azure/roleassignments.go @@ -0,0 +1,57 @@ +/* + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package azure + +import ( + "context" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2" + "github.com/gravitational/trace" +) + +// RoleAssignmentsClient wraps the Azure API to provide a high level subset of functionality +type RoleAssignmentsClient struct { + cli *armauthorization.RoleAssignmentsClient +} + +// NewRoleAssignmentsClient creates a new client for a given subscription and credentials +func NewRoleAssignmentsClient(subscription string, cred azcore.TokenCredential, options *arm.ClientOptions) (*RoleAssignmentsClient, error) { + clientFactory, err := armauthorization.NewClientFactory(subscription, cred, options) + if err != nil { + return nil, trace.Wrap(err) + } + roleDefCli := clientFactory.NewRoleAssignmentsClient() + return &RoleAssignmentsClient{cli: roleDefCli}, nil +} + +// ListRoleAssignments returns role assignments for a given scope +func (c *RoleAssignmentsClient) ListRoleAssignments(ctx context.Context, scope string) ([]*armauthorization.RoleAssignment, error) { + pager := c.cli.NewListForScopePager(scope, nil) + var roleDefs []*armauthorization.RoleAssignment + for pager.More() { + page, err := pager.NextPage(ctx) + if err != nil { + return nil, trace.Wrap(err) + } + roleDefs = append(roleDefs, page.Value...) + } + return roleDefs, nil +} diff --git a/lib/cloud/azure/roledefinitions.go b/lib/cloud/azure/roledefinitions.go new file mode 100644 index 0000000000000..cdc46196aa530 --- /dev/null +++ b/lib/cloud/azure/roledefinitions.go @@ -0,0 +1,57 @@ +/* + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package azure + +import ( + "context" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2" + "github.com/gravitational/trace" +) + +// RoleDefinitionsClient wraps the Azure API to provide a high level subset of functionality +type RoleDefinitionsClient struct { + cli *armauthorization.RoleDefinitionsClient +} + +// NewRoleDefinitionsClient creates a new client for a given subscription and credentials +func NewRoleDefinitionsClient(subscription string, cred azcore.TokenCredential, options *arm.ClientOptions) (*RoleDefinitionsClient, error) { + clientFactory, err := armauthorization.NewClientFactory(subscription, cred, options) + if err != nil { + return nil, trace.Wrap(err) + } + roleDefCli := clientFactory.NewRoleDefinitionsClient() + return &RoleDefinitionsClient{cli: roleDefCli}, nil +} + +// ListRoleDefinitions returns role definitions for a given scope +func (c *RoleDefinitionsClient) ListRoleDefinitions(ctx context.Context, scope string) ([]*armauthorization.RoleDefinition, error) { + pager := c.cli.NewListPager(scope, nil) + var roleDefs []*armauthorization.RoleDefinition + for pager.More() { + page, err := pager.NextPage(ctx) + if err != nil { + return nil, trace.Wrap(err) + } + roleDefs = append(roleDefs, page.Value...) + } + return roleDefs, nil +} diff --git a/lib/cloud/clients.go b/lib/cloud/clients.go index a100cdb4a4605..bc2b77d2d0abb 100644 --- a/lib/cloud/clients.go +++ b/lib/cloud/clients.go @@ -364,6 +364,10 @@ type azureClients struct { azurePostgresFlexServersClients azure.ClientMap[azure.PostgresFlexServersClient] // azureRunCommandClients contains the cached Azure Run Command clients. azureRunCommandClients azure.ClientMap[azure.RunCommandClient] + // azureRoleDefinitionsClients contains the cached Azure Role Definitions clients. + azureRoleDefinitionsClients azure.ClientMap[azure.RoleDefinitionsClient] + // azureRoleAssignmentsClients contains the cached Azure Role Assignments clients. + azureRoleAssignmentsClients azure.ClientMap[azure.RoleAssignmentsClient] } // credentialsSource defines where the credentials must come from. @@ -782,6 +786,16 @@ func (c *cloudClients) GetAzureRunCommandClient(subscription string) (azure.RunC return c.azureRunCommandClients.Get(subscription, c.GetAzureCredential) } +// GetAzureRoleDefinitionsClient returns an Azure Role Definitions client +func (c *cloudClients) GetAzureRoleDefinitionsClient(subscription string) (azure.RoleDefinitionsClient, error) { + return c.azureRoleDefinitionsClients.Get(subscription, c.GetAzureCredential) +} + +// GetAzureRoleAssignmentsClient returns an Azure Role Assignments client +func (c *cloudClients) GetAzureRoleAssignmentsClient(subscription string) (azure.RoleAssignmentsClient, error) { + return c.azureRoleAssignmentsClients.Get(subscription, c.GetAzureCredential) +} + // Close closes all initialized clients. func (c *cloudClients) Close() (err error) { c.mtx.Lock() @@ -1094,6 +1108,8 @@ type TestCloudClients struct { AzureMySQLFlex azure.MySQLFlexServersClient AzurePostgresFlex azure.PostgresFlexServersClient AzureRunCommand azure.RunCommandClient + AzureRoleDefinitions azure.RoleDefinitionsClient + AzureRoleAssignments azure.RoleAssignmentsClient } // GetAWSSession returns AWS session for the specified region, optionally @@ -1365,11 +1381,21 @@ func (c *TestCloudClients) GetAzurePostgresFlexServersClient(subscription string return c.AzurePostgresFlex, nil } -// GetAzureRunCommand returns an Azure Run Command client for the given subscription. +// GetAzureRunCommandClient returns an Azure Run Command client for the given subscription. func (c *TestCloudClients) GetAzureRunCommandClient(subscription string) (azure.RunCommandClient, error) { return c.AzureRunCommand, nil } +// GetAzureRoleDefinitionsClient returns an Azure Role Definitions client for the given subscription. +func (c *TestCloudClients) GetAzureRoleDefinitionsClient(subscription string) (azure.RoleDefinitionsClient, error) { + return c.AzureRoleDefinitions, nil +} + +// GetAzureRoleAssignmentsClient returns an Azure Role Assignments client for the given subscription. +func (c *TestCloudClients) GetAzureRoleAssignmentsClient(subscription string) (azure.RoleAssignmentsClient, error) { + return c.AzureRoleAssignments, nil +} + // Close closes all initialized clients. func (c *TestCloudClients) Close() error { return nil diff --git a/lib/config/configuration.go b/lib/config/configuration.go index e5a06e9b432c2..8e553f463c995 100644 --- a/lib/config/configuration.go +++ b/lib/config/configuration.go @@ -251,6 +251,10 @@ type CommandLineFlags struct { // `teleport integration configure access-graph aws-iam` command IntegrationConfAccessGraphAWSSyncArguments IntegrationConfAccessGraphAWSSync + // IntegrationConfAccessGarphAzureSyncArguments contains the arguments of + // `teleport integration configure access-graph azure` command + IntegrationConfAccessGraphAzureSyncArguments IntegrationConfAccessGraphAzureSync + // IntegrationConfAzureOIDCArguments contains the arguments of // `teleport integration configure azure-oidc` command IntegrationConfAzureOIDCArguments IntegrationConfAzureOIDC @@ -283,6 +287,19 @@ type IntegrationConfAccessGraphAWSSync struct { AutoConfirm bool } +// IntegrationConfAccessGraphAzureSync contains the arguments of +// `teleport integration configure access-graph azure` command. +type IntegrationConfAccessGraphAzureSync struct { + // ManagedIdentity is the principal performing the discovery + ManagedIdentity string + // RoleName is the name of the Azure Role to create and assign to the managed identity + RoleName string + // SubscriptionID is the Azure subscription containing resources for sync + SubscriptionID string + // AutoConfirm skips user confirmation of the operation plan if true + AutoConfirm bool +} + // IntegrationConfAzureOIDC contains the arguments of // `teleport integration configure azure-oidc` command type IntegrationConfAzureOIDC struct { @@ -1754,6 +1771,12 @@ kubernetes matchers are present`) AssumeRole: assumeRole, }) } + for _, azureMatcher := range fc.Discovery.AccessGraph.Azure { + subscriptionID := azureMatcher.SubscriptionID + tMatcher.Azure = append(tMatcher.Azure, &types.AccessGraphAzureSync{ + SubscriptionID: subscriptionID, + }) + } if fc.Discovery.AccessGraph.PollInterval > 0 { tMatcher.PollInterval = fc.Discovery.AccessGraph.PollInterval } diff --git a/lib/config/fileconf.go b/lib/config/fileconf.go index a86cae7c9a214..6ed09e4af04cb 100644 --- a/lib/config/fileconf.go +++ b/lib/config/fileconf.go @@ -1523,6 +1523,8 @@ type GCPMatcher struct { type AccessGraphSync struct { // AWS is the AWS configuration for the AccessGraph Sync service. AWS []AccessGraphAWSSync `yaml:"aws,omitempty"` + // Azure is the Azure configuration for the AccessGraph Sync service. + Azure []AccessGraphAzureSync `yaml:"azure,omitempty"` // PollInterval is the frequency at which to poll for AWS resources PollInterval time.Duration `yaml:"poll_interval,omitempty"` } @@ -1538,6 +1540,12 @@ type AccessGraphAWSSync struct { ExternalID string `yaml:"external_id,omitempty"` } +// AccessGraphAzureSync represents the configuration for the Azure AccessGraph Sync service. +type AccessGraphAzureSync struct { + // SubscriptionID is the Azure subscription ID configured for syncing + SubscriptionID string `yaml:"subscription_id,omitempty"` +} + // CommandLabel is `command` section of `ssh_service` in the config file type CommandLabel struct { Name string `yaml:"name"` diff --git a/lib/integrations/awsoidc/access_graph_aws_sync.go b/lib/integrations/awsoidc/accessgraph_sync.go similarity index 100% rename from lib/integrations/awsoidc/access_graph_aws_sync.go rename to lib/integrations/awsoidc/accessgraph_sync.go diff --git a/lib/integrations/awsoidc/access_graph_aws_sync_test.go b/lib/integrations/awsoidc/accessgraph_sync_test.go similarity index 100% rename from lib/integrations/awsoidc/access_graph_aws_sync_test.go rename to lib/integrations/awsoidc/accessgraph_sync_test.go diff --git a/lib/integrations/azureoidc/accessgraph_sync.go b/lib/integrations/azureoidc/accessgraph_sync.go new file mode 100644 index 0000000000000..91731ca98bd39 --- /dev/null +++ b/lib/integrations/azureoidc/accessgraph_sync.go @@ -0,0 +1,276 @@ +/* + * Teleport + * Copyright (C) 2025 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 azureoidc + +import ( + "context" + "io" + "maps" + "slices" + "strings" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore" + armpolicy "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/policy" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" + "github.com/Azure/azure-sdk-for-go/sdk/azidentity" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2" + "github.com/google/uuid" + "github.com/gravitational/trace" + + "github.com/gravitational/teleport/lib/cloud/provisioning" + "github.com/gravitational/teleport/lib/msgraph" + libslices "github.com/gravitational/teleport/lib/utils/slices" +) + +// graphAppID is the pre-defined application ID of the Graph API +// Ref: [https://learn.microsoft.com/en-us/troubleshoot/entra/entra-id/governance/verify-first-party-apps-sign-in#application-ids-of-commonly-used-microsoft-applications]. +const graphAppID = "00000003-0000-0000-c000-000000000000" + +// azureUserAgent defines the user agent for the Azure SDK to better identify misbehaving clients +const azureUserAgent = "teleport" + +// requiredGraphRoleNames is the list of Graph API roles required for the managed identity to fetch resources from Azure +var requiredGraphRoleNames = map[string]struct{}{ + "User.ReadBasic.All": {}, + "Group.Read.All": {}, + "Directory.Read.All": {}, + "User.Read.All": {}, + "Policy.Read.All": {}, +} + +// AccessGraphAzureConfigureClient provides an interface for granting the managed identity the necessary permissions +// to fetch Azure resources +type AccessGraphAzureConfigureClient interface { + // CreateRoleDefinition creates an Azure role definition + CreateRoleDefinition(ctx context.Context, scope string, roleDefinition armauthorization.RoleDefinition) (string, error) + // CreateRoleAssignment assigns a role to an Azure principal + CreateRoleAssignment(ctx context.Context, scope string, roleAssignment armauthorization.RoleAssignmentCreateParameters) error + // GetServicePrincipalByAppID returns a service principal based on its application ID + GetServicePrincipalByAppID(ctx context.Context, appID string) (*msgraph.ServicePrincipal, error) + // GrantAppRoleToServicePrincipal grants a specific type of application role to a service principal + GrantAppRoleToServicePrincipal(ctx context.Context, roleAssignment msgraph.AppRoleAssignment) error +} + +// azureConfigClient wraps the role definition, role assignments, and Graph API clients +type azureConfigClient struct { + roleDefCli *armauthorization.RoleDefinitionsClient + roleAssignCli *armauthorization.RoleAssignmentsClient + graphCli *msgraph.Client +} + +// NewAzureConfigClient returns a new config client for granting the managed identity the necessary permissions +// to fetch Azure resources +func NewAzureConfigClient(subscriptionID string) (AccessGraphAzureConfigureClient, error) { + telemetryOpts := policy.TelemetryOptions{ + ApplicationID: azureUserAgent, + } + opts := &armpolicy.ClientOptions{ + ClientOptions: policy.ClientOptions{ + Telemetry: telemetryOpts, + }, + } + cred, err := azidentity.NewDefaultAzureCredential(&azidentity.DefaultAzureCredentialOptions{ + ClientOptions: azcore.ClientOptions{ + Telemetry: telemetryOpts, + }, + }) + if err != nil { + return nil, trace.Wrap(err) + } + roleDefCli, err := armauthorization.NewRoleDefinitionsClient(cred, opts) + if err != nil { + return nil, trace.BadParameter("failed to create role definitions client: %v", err) + } + roleAssignCli, err := armauthorization.NewRoleAssignmentsClient(subscriptionID, cred, opts) + if err != nil { + return nil, trace.BadParameter("failed to create role assignments client: %v", err) + } + graphCli, err := msgraph.NewClient(msgraph.Config{ + TokenProvider: cred, + }) + if err != nil { + return nil, trace.BadParameter("failed to create msgraph client: %v", err) + } + return &azureConfigClient{ + roleDefCli: roleDefCli, + roleAssignCli: roleAssignCli, + graphCli: graphCli, + }, nil +} + +// CreateRoleDefinition creates an Azure role definition +func (c *azureConfigClient) CreateRoleDefinition(ctx context.Context, scope string, roleDefinition armauthorization.RoleDefinition) (string, error) { + newUuid, err := uuid.NewRandom() + if err != nil { + return "", trace.Wrap(err) + } + roleDefID := newUuid.String() + roleRes, err := c.roleDefCli.CreateOrUpdate(ctx, scope, roleDefID, roleDefinition, nil) + if err != nil { + return "", trace.Wrap(err) + } + return *roleRes.ID, err +} + +// CreateRoleAssignment assigns a role to an Azure principal +func (c *azureConfigClient) CreateRoleAssignment(ctx context.Context, scope string, roleAssignment armauthorization.RoleAssignmentCreateParameters) error { + newUuid, err := uuid.NewRandom() + if err != nil { + return trace.Wrap(err) + } + assignID := newUuid.String() + if _, err = c.roleAssignCli.Create(ctx, scope, assignID, roleAssignment, nil); err != nil { + return trace.Wrap(err) + } + return nil +} + +// GetServicePrincipalByAppID returns a service principal based on its application ID +func (c *azureConfigClient) GetServicePrincipalByAppID(ctx context.Context, appID string) (*msgraph.ServicePrincipal, error) { + graphPrincipal, err := c.graphCli.GetServicePrincipalByAppId(ctx, appID) + if err != nil { + return nil, trace.BadParameter("failed to get the graph API service principal: %v", err) + } + return graphPrincipal, nil +} + +// GrantAppRoleToServicePrincipal grants a specific type of application role to a service principal +func (c *azureConfigClient) GrantAppRoleToServicePrincipal(ctx context.Context, roleAssignment msgraph.AppRoleAssignment) error { + _, err := c.graphCli.GrantAppRoleToServicePrincipal(ctx, *roleAssignment.PrincipalID, &roleAssignment) + if err != nil { + return trace.Wrap(err) + } + return nil +} + +// AccessGraphAzureConfigureRequest is a request to configure the required Policies to use the TAG AWS Sync. +type AccessGraphAzureConfigureRequest struct { + // ManagedIdentity is the principal performing the discovery + ManagedIdentity string + // RoleName is the name of the Azure Role to create and assign to the managed identity + RoleName string + // SubscriptionID is the Azure subscription containing resources for sync + SubscriptionID 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 +} + +// roleAssignmentAction assigns both the Azure role and Graph API roles to the managed identity +func roleAssignmentAction(clt AccessGraphAzureConfigureClient, subscriptionID string, managedID string, roleName string) (*provisioning.Action, error) { + customRole := "CustomRole" + scope := "/subscriptions/" + subscriptionID + runnerFn := func(ctx context.Context) error { + // Create the role + roleDefinition := armauthorization.RoleDefinition{ + Name: &roleName, + Properties: &armauthorization.RoleDefinitionProperties{ + RoleName: &roleName, + RoleType: &customRole, + Permissions: []*armauthorization.Permission{ + { + Actions: libslices.ToPointers([]string{ + "Microsoft.Compute/virtualMachines/read", + "Microsoft.Compute/virtualMachineScaleSets/virtualMachines/read", + "Microsoft.Authorization/roleDefinitions/read", + "Microsoft.Authorization/roleAssignments/read", + }), + }, + }, + AssignableScopes: []*string{&scope}, // Scope must be provided + }, + } + roleID, err := clt.CreateRoleDefinition(ctx, scope, roleDefinition) + if err != nil { + return trace.Errorf("failed to create custom role: %v", err) + } + + // Assign the new role to the managed identity + roleAssignParams := armauthorization.RoleAssignmentCreateParameters{ + Properties: &armauthorization.RoleAssignmentProperties{ + PrincipalID: &managedID, + RoleDefinitionID: &roleID, + }, + } + if err = clt.CreateRoleAssignment(ctx, scope, roleAssignParams); err != nil { + return trace.Errorf("failed to assign role %s to principal %s: %v", roleName, managedID, err) + } + + // Assign the Graph API permissions to the managed identity + graphPrincipal, err := clt.GetServicePrincipalByAppID(ctx, graphAppID) + if err != nil { + return trace.Errorf("could not get the graph API service principal: %v", err) + } + rolesNotAssigned := make(map[string]struct{}) + for k, v := range requiredGraphRoleNames { + rolesNotAssigned[k] = v + } + for _, appRole := range graphPrincipal.AppRoles { + if _, ok := requiredGraphRoleNames[*appRole.Value]; ok { + roleAssignment := msgraph.AppRoleAssignment{ + AppRoleID: appRole.ID, + PrincipalID: &managedID, + ResourceID: graphPrincipal.ID, + } + if err = clt.GrantAppRoleToServicePrincipal(ctx, roleAssignment); err != nil { + return trace.Errorf("failed to assign graph API role to %s: %v", managedID, err) + } + delete(rolesNotAssigned, *appRole.Value) + } + } + if len(rolesNotAssigned) > 0 { + return trace.Errorf("could not assign all required roles: %v", slices.Collect(maps.Keys(rolesNotAssigned))) + } + return nil + } + cfg := provisioning.ActionConfig{ + Name: "AssignRole", + Summary: "Creates a new Azure role and attaches it to a managed identity for the Discovery service", + Details: strings.Join([]string{ + "The Discovery Service needs to run as a credentialed Azure managed identity. This managed identity ", + "can be system assigned (i.e. tied to the lifecycle of a virtual machine running the Discovery service), ", + "or user-assigned (i.e. a persistent identity). The managed identity requires two types of permissions:\n\n", + "\t1) Azure resource permissions in order to fetch virtual machines, role definitions, etc, and\n", + "\t2) Graph API permissions to fetch users, groups, and service principals.\n\n", + "The command assigns both Azure resource permissions as well as Graph API permissions to the specified ", + "managed identity.", + }, ""), + RunnerFn: runnerFn, + } + return provisioning.NewAction(cfg) +} + +// ConfigureAccessGraphSyncAzure sets up the managed identity and role required for Teleport to be able to pull +// Azure resources into Teleport. +func ConfigureAccessGraphSyncAzure(ctx context.Context, clt AccessGraphAzureConfigureClient, req AccessGraphAzureConfigureRequest) error { + managedIDAction, err := roleAssignmentAction(clt, req.SubscriptionID, req.ManagedIdentity, req.RoleName) + if err != nil { + return trace.Wrap(err) + } + opCfg := provisioning.OperationConfig{ + Name: "access-graph-azure-sync", + Actions: []provisioning.Action{ + *managedIDAction, + }, + AutoConfirm: req.AutoConfirm, + Output: req.stdout, + } + return trace.Wrap(provisioning.Run(ctx, opCfg)) +} diff --git a/lib/integrations/azureoidc/accessgraph_sync_test.go b/lib/integrations/azureoidc/accessgraph_sync_test.go new file mode 100644 index 0000000000000..91020aab1c2e4 --- /dev/null +++ b/lib/integrations/azureoidc/accessgraph_sync_test.go @@ -0,0 +1,142 @@ +/* + * Teleport + * Copyright (C) 2025 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 azureoidc + +import ( + "bytes" + "context" + "fmt" + "maps" + "slices" + "testing" + + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2" + "github.com/google/uuid" + "github.com/gravitational/trace" + "github.com/stretchr/testify/require" + + "github.com/gravitational/teleport/lib/msgraph" +) + +type mockClientConfig struct { + createRoleErr bool + assignRoleErr bool + fetchPrincipalErr bool + grantAppRoleErr bool +} + +type mockAzureConfigClient struct { + cfg mockClientConfig +} + +func (c *mockAzureConfigClient) CreateRoleDefinition(ctx context.Context, scope string, roleDefinition armauthorization.RoleDefinition) (string, error) { + if c.cfg.createRoleErr { + return "", trace.Errorf("failed to create role definition") + } + return "foo", nil +} + +func (c *mockAzureConfigClient) CreateRoleAssignment(ctx context.Context, scope string, roleAssignment armauthorization.RoleAssignmentCreateParameters) error { + if c.cfg.assignRoleErr { + return trace.Errorf("failed to assign role") + } + return nil +} + +func (c *mockAzureConfigClient) GetServicePrincipalByAppID(ctx context.Context, appID string) (*msgraph.ServicePrincipal, error) { + if c.cfg.fetchPrincipalErr { + return nil, trace.Errorf("failed to fetch principal") + } + spID := uuid.NewString() + appRoleValues := slices.Collect(maps.Keys(requiredGraphRoleNames)) + var roles []*msgraph.AppRole + for _, rv := range appRoleValues { + roleID := uuid.NewString() + roles = append(roles, &msgraph.AppRole{ + ID: &roleID, + Value: &rv, + }) + } + return &msgraph.ServicePrincipal{ + DirectoryObject: msgraph.DirectoryObject{ + ID: &spID, + }, + AppRoles: roles, + }, nil +} + +func (c *mockAzureConfigClient) GrantAppRoleToServicePrincipal(ctx context.Context, roleAssignment msgraph.AppRoleAssignment) error { + if c.cfg.grantAppRoleErr { + return fmt.Errorf("failed to grant app role") + } + return nil +} + +func TestAccessGraphAzureConfigOutput(t *testing.T) { + ctx := context.Background() + for _, tt := range []struct { + clientCfg mockClientConfig + hasError bool + }{ + { + clientCfg: mockClientConfig{}, + hasError: false, + }, + { + clientCfg: mockClientConfig{ + createRoleErr: true, + }, + hasError: true, + }, + { + clientCfg: mockClientConfig{ + assignRoleErr: true, + }, + hasError: true, + }, + { + clientCfg: mockClientConfig{ + fetchPrincipalErr: true, + }, + hasError: true, + }, + { + clientCfg: mockClientConfig{ + grantAppRoleErr: true, + }, + hasError: true, + }, + } { + var buf bytes.Buffer + req := AccessGraphAzureConfigureRequest{ + ManagedIdentity: "foo", + RoleName: "bar", + SubscriptionID: "1234567890", + AutoConfirm: true, + stdout: &buf, + } + clt := &mockAzureConfigClient{ + cfg: tt.clientCfg, + } + err := ConfigureAccessGraphSyncAzure(ctx, clt, req) + if !tt.hasError { + require.NoError(t, err) + } + } +} diff --git a/lib/kube/proxy/resource_filters_test.go b/lib/kube/proxy/resource_filters_test.go index 3d49563712b81..4cc79b8c4a0df 100644 --- a/lib/kube/proxy/resource_filters_test.go +++ b/lib/kube/proxy/resource_filters_test.go @@ -42,6 +42,7 @@ import ( "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/kube/proxy/responsewriters" + libslices "github.com/gravitational/teleport/lib/utils/slices" ) func Test_filterBuffer(t *testing.T) { @@ -188,43 +189,43 @@ func Test_filterBuffer(t *testing.T) { var resources []string switch o := obj.(type) { case *corev1.SecretList: - resources = collectResourcesFromResponse(arrayToPointerArray(o.Items)) + resources = collectResourcesFromResponse(libslices.ToPointers(o.Items)) case *appsv1.DeploymentList: - resources = collectResourcesFromResponse(arrayToPointerArray(o.Items)) + resources = collectResourcesFromResponse(libslices.ToPointers(o.Items)) case *appsv1.DaemonSetList: - resources = collectResourcesFromResponse(arrayToPointerArray(o.Items)) + resources = collectResourcesFromResponse(libslices.ToPointers(o.Items)) case *appsv1.StatefulSetList: - resources = collectResourcesFromResponse(arrayToPointerArray(o.Items)) + resources = collectResourcesFromResponse(libslices.ToPointers(o.Items)) case *authv1.RoleBindingList: - resources = collectResourcesFromResponse(arrayToPointerArray(o.Items)) + resources = collectResourcesFromResponse(libslices.ToPointers(o.Items)) case *batchv1.CronJobList: - resources = collectResourcesFromResponse(arrayToPointerArray(o.Items)) + resources = collectResourcesFromResponse(libslices.ToPointers(o.Items)) case *batchv1.JobList: - resources = collectResourcesFromResponse(arrayToPointerArray(o.Items)) + resources = collectResourcesFromResponse(libslices.ToPointers(o.Items)) case *corev1.PodList: - resources = collectResourcesFromResponse(arrayToPointerArray(o.Items)) + resources = collectResourcesFromResponse(libslices.ToPointers(o.Items)) case *corev1.ConfigMapList: - resources = collectResourcesFromResponse(arrayToPointerArray(o.Items)) + resources = collectResourcesFromResponse(libslices.ToPointers(o.Items)) case *corev1.ServiceAccountList: - resources = collectResourcesFromResponse(arrayToPointerArray(o.Items)) + resources = collectResourcesFromResponse(libslices.ToPointers(o.Items)) case *appsv1.ReplicaSetList: - resources = collectResourcesFromResponse(arrayToPointerArray(o.Items)) + resources = collectResourcesFromResponse(libslices.ToPointers(o.Items)) case *corev1.ServiceList: - resources = collectResourcesFromResponse(arrayToPointerArray(o.Items)) + resources = collectResourcesFromResponse(libslices.ToPointers(o.Items)) case *corev1.PersistentVolumeClaimList: - resources = collectResourcesFromResponse(arrayToPointerArray(o.Items)) + resources = collectResourcesFromResponse(libslices.ToPointers(o.Items)) case *authv1.RoleList: - resources = collectResourcesFromResponse(arrayToPointerArray(o.Items)) + resources = collectResourcesFromResponse(libslices.ToPointers(o.Items)) case *networkingv1.IngressList: - resources = collectResourcesFromResponse(arrayToPointerArray(o.Items)) + resources = collectResourcesFromResponse(libslices.ToPointers(o.Items)) case *extensionsv1beta1.IngressList: - resources = collectResourcesFromResponse(arrayToPointerArray(o.Items)) + resources = collectResourcesFromResponse(libslices.ToPointers(o.Items)) case *extensionsv1beta1.DaemonSetList: - resources = collectResourcesFromResponse(arrayToPointerArray(o.Items)) + resources = collectResourcesFromResponse(libslices.ToPointers(o.Items)) case *extensionsv1beta1.ReplicaSetList: - resources = collectResourcesFromResponse(arrayToPointerArray(o.Items)) + resources = collectResourcesFromResponse(libslices.ToPointers(o.Items)) case *extensionsv1beta1.DeploymentList: - resources = collectResourcesFromResponse(arrayToPointerArray(o.Items)) + resources = collectResourcesFromResponse(libslices.ToPointers(o.Items)) case *metav1.Table: for i := range o.Rows { row := &(o.Rows[i]) diff --git a/lib/msgraph/client.go b/lib/msgraph/client.go index 26ea34e1d45c2..a622ffe673e77 100644 --- a/lib/msgraph/client.go +++ b/lib/msgraph/client.go @@ -1,5 +1,5 @@ // Teleport -// Copyright (C) 2024 Gravitational, Inc. +// Copyright (C) 2025 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 @@ -336,6 +336,17 @@ func (c *Client) GetServicePrincipalsByDisplayName(ctx context.Context, displayN return out.Value, nil } +// GetServicePrincipal returns the service principal for the given principal ID. +// Ref: [https://learn.microsoft.com/en-us/graph/api/serviceprincipal-get]. +func (c *Client) GetServicePrincipal(ctx context.Context, principalId string) (*ServicePrincipal, error) { + uri := c.endpointURI(fmt.Sprintf("servicePrincipals/%s", principalId)) + out, err := roundtrip[*ServicePrincipal](ctx, c, http.MethodGet, uri.String(), nil) + if err != nil { + return nil, trace.Wrap(err) + } + return out, nil +} + // GrantAppRoleToServicePrincipal grants the given app role to the specified Service Principal. // Ref: [https://learn.microsoft.com/en-us/graph/api/serviceprincipal-post-approleassignedto] func (c *Client) GrantAppRoleToServicePrincipal(ctx context.Context, spID string, assignment *AppRoleAssignment) (*AppRoleAssignment, error) { diff --git a/lib/msgraph/models.go b/lib/msgraph/models.go index 52c3e97cfec7b..3984fee85ccdf 100644 --- a/lib/msgraph/models.go +++ b/lib/msgraph/models.go @@ -123,9 +123,10 @@ type WebApplication struct { type ServicePrincipal struct { DirectoryObject - AppRoleAssignmentRequired *bool `json:"appRoleAssignmentRequired,omitempty"` - PreferredSingleSignOnMode *string `json:"preferredSingleSignOnMode,omitempty"` - PreferredTokenSigningKeyThumbprint *string `json:"preferredTokenSigningKeyThumbprint,omitempty"` + AppRoleAssignmentRequired *bool `json:"appRoleAssignmentRequired,omitempty"` + PreferredSingleSignOnMode *string `json:"preferredSingleSignOnMode,omitempty"` + PreferredTokenSigningKeyThumbprint *string `json:"preferredTokenSigningKeyThumbprint,omitempty"` + AppRoles []*AppRole `json:"appRoles,omitempty"` } type ApplicationServicePrincipal struct { @@ -144,6 +145,11 @@ type SelfSignedCertificate struct { Thumbprint *string `json:"thumbprint,omitempty"` } +type AppRole struct { + ID *string `json:"id,omitempty"` + Value *string `json:"value,omitempty"` +} + type AppRoleAssignment struct { ID *string `json:"id,omitempty"` AppRoleID *string `json:"appRoleId,omitempty"` diff --git a/lib/msgraph/paginated.go b/lib/msgraph/paginated.go index 51c587f19d074..a0b9488af9d70 100644 --- a/lib/msgraph/paginated.go +++ b/lib/msgraph/paginated.go @@ -101,6 +101,14 @@ func (c *Client) IterateUsers(ctx context.Context, f func(*User) bool) error { return iterateSimple(c, ctx, "users", f) } +// IterateServicePrincipals lists all service principals in the Entra ID directory using pagination. +// `f` will be called for each object in the result set. +// if `f` returns `false`, the iteration is stopped (equivalent to `break` in a normal loop). +// Ref: [https://learn.microsoft.com/en-us/graph/api/serviceprincipal-list]. +func (c *Client) IterateServicePrincipals(ctx context.Context, f func(principal *ServicePrincipal) bool) error { + return iterateSimple(c, ctx, "servicePrincipals", f) +} + // IterateGroupMembers lists all members for the given Entra ID group using pagination. // `f` will be called for each object in the result set. // if `f` returns `false`, the iteration is stopped (equivalent to `break` in a normal loop). diff --git a/lib/services/integration.go b/lib/services/integration.go index be495d385b4ab..bfe000113ee5c 100644 --- a/lib/services/integration.go +++ b/lib/services/integration.go @@ -52,6 +52,8 @@ type IntegrationsGetter interface { type IntegrationsTokenGenerator interface { // GenerateAWSOIDCToken generates a token to be used to execute an AWS OIDC Integration action. GenerateAWSOIDCToken(ctx context.Context, integration string) (string, error) + // GenerateAzureOIDCToken generates a token to be used to execute an Azure OIDC Integration action. + GenerateAzureOIDCToken(ctx context.Context, integration string) (string, error) } // MarshalIntegration marshals the Integration resource to JSON. diff --git a/lib/srv/discovery/access_graph.go b/lib/srv/discovery/access_graph_aws.go similarity index 91% rename from lib/srv/discovery/access_graph.go rename to lib/srv/discovery/access_graph_aws.go index 7d65f99f88ef5..f341f07312394 100644 --- a/lib/srv/discovery/access_graph.go +++ b/lib/srv/discovery/access_graph_aws.go @@ -50,6 +50,15 @@ const ( batchSize = 500 // defaultPollInterval is the default interval between polling for access graph resources defaultPollInterval = 15 * time.Minute + // Configure health check service to monitor access graph service and + // automatically reconnect if the connection is lost without + // relying on new events from the auth server to trigger a reconnect. + serviceConfig = `{ + "loadBalancingPolicy": "round_robin", + "healthCheckConfig": { + "serviceName": "" + } + }` ) // errNoAccessGraphFetchers is returned when there are no TAG fetchers. @@ -73,8 +82,10 @@ func (s *Server) reconcileAccessGraph(ctx context.Context, currentTAGResources * return trace.Wrap(errNoAccessGraphFetchers) } - s.awsSyncStatus.iterationStarted(allFetchers, s.clock.Now()) - for _, discoveryConfigName := range s.awsSyncStatus.discoveryConfigs() { + for _, fetcher := range allFetchers { + s.tagSyncStatus.syncStarted(fetcher, s.clock.Now()) + } + for _, discoveryConfigName := range s.tagSyncStatus.discoveryConfigs() { s.updateDiscoveryConfigStatus(discoveryConfigName) } @@ -83,7 +94,6 @@ func (s *Server) reconcileAccessGraph(ctx context.Context, currentTAGResources * tokens := make(chan struct{}, 3) accountIds := map[string]struct{}{} for _, fetcher := range allFetchers { - fetcher := fetcher accountIds[fetcher.GetAccountID()] = struct{}{} tokens <- struct{}{} go func() { @@ -118,8 +128,10 @@ func (s *Server) reconcileAccessGraph(ctx context.Context, currentTAGResources * upsert, toDel := aws_sync.ReconcileResults(currentTAGResources, result) pushErr := push(stream, upsert, toDel) - s.awsSyncStatus.iterationFinished(allFetchers, pushErr, s.clock.Now()) - for _, discoveryConfigName := range s.awsSyncStatus.discoveryConfigs() { + for _, fetcher := range allFetchers { + s.tagSyncStatus.syncFinished(fetcher, pushErr, s.clock.Now()) + } + for _, discoveryConfigName := range s.tagSyncStatus.discoveryConfigs() { s.updateDiscoveryConfigStatus(discoveryConfigName) } @@ -144,16 +156,16 @@ func (s *Server) reconcileAccessGraph(ctx context.Context, currentTAGResources * } // getAllAWSSyncFetchers returns all AWS sync fetchers. -func (s *Server) getAllAWSSyncFetchers() []aws_sync.AWSSync { - allFetchers := make([]aws_sync.AWSSync, 0, len(s.dynamicTAGSyncFetchers)) +func (s *Server) getAllAWSSyncFetchers() []*aws_sync.Fetcher { + allFetchers := make([]*aws_sync.Fetcher, 0, len(s.dynamicTAGAWSFetchers)) - s.muDynamicTAGSyncFetchers.RLock() - for _, fetcherSet := range s.dynamicTAGSyncFetchers { + s.muDynamicTAGAWSFetchers.RLock() + for _, fetcherSet := range s.dynamicTAGAWSFetchers { allFetchers = append(allFetchers, fetcherSet...) } - s.muDynamicTAGSyncFetchers.RUnlock() + s.muDynamicTAGAWSFetchers.RUnlock() - allFetchers = append(allFetchers, s.staticTAGSyncFetchers...) + allFetchers = append(allFetchers, s.staticTAGAWSFetchers...) // TODO(tigrato): submit fetchers event return allFetchers } @@ -257,15 +269,6 @@ func (s *Server) initializeAndWatchAccessGraph(ctx context.Context, reloadCh <-c const ( // aws discovery semaphore lock. semaphoreName = "access_graph_aws_sync" - // Configure health check service to monitor access graph service and - // automatically reconnect if the connection is lost without - // relying on new events from the auth server to trigger a reconnect. - serviceConfig = `{ - "loadBalancingPolicy": "round_robin", - "healthCheckConfig": { - "serviceName": "" - } - }` ) clusterFeatures := s.Config.ClusterFeatures() @@ -438,12 +441,12 @@ func grpcCredentials(config AccessGraphConfig, getCert func() (*tls.Certificate, return grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig)), nil } -func (s *Server) initAccessGraphWatchers(ctx context.Context, cfg *Config) error { - fetchers, err := s.accessGraphFetchersFromMatchers(ctx, cfg.Matchers, "" /* discoveryConfigName */) +func (s *Server) initTAGAWSWatchers(ctx context.Context, cfg *Config) error { + fetchers, err := s.accessGraphAWSFetchersFromMatchers(ctx, cfg.Matchers, "" /* discoveryConfigName */) if err != nil { s.Log.ErrorContext(ctx, "Error initializing access graph fetchers", "error", err) } - s.staticTAGSyncFetchers = fetchers + s.staticTAGAWSFetchers = fetchers if cfg.AccessGraphConfig.Enabled { go func() { @@ -482,9 +485,9 @@ func (s *Server) initAccessGraphWatchers(ctx context.Context, cfg *Config) error return nil } -// accessGraphFetchersFromMatchers converts Matchers into a set of AWS Sync Fetchers. -func (s *Server) accessGraphFetchersFromMatchers(ctx context.Context, matchers Matchers, discoveryConfigName string) ([]aws_sync.AWSSync, error) { - var fetchers []aws_sync.AWSSync +// accessGraphAWSFetchersFromMatchers converts Matchers into a set of AWS Sync Fetchers. +func (s *Server) accessGraphAWSFetchersFromMatchers(ctx context.Context, matchers Matchers, discoveryConfigName string) ([]*aws_sync.Fetcher, error) { + var fetchers []*aws_sync.Fetcher var errs []error if matchers.AccessGraph == nil { return fetchers, nil @@ -498,7 +501,7 @@ func (s *Server) accessGraphFetchersFromMatchers(ctx context.Context, matchers M ExternalID: awsFetcher.AssumeRole.ExternalID, } } - fetcher, err := aws_sync.NewAWSFetcher( + fetcher, err := aws_sync.NewFetcher( ctx, aws_sync.Config{ CloudClients: s.CloudClients, diff --git a/lib/srv/discovery/access_graph_azure.go b/lib/srv/discovery/access_graph_azure.go new file mode 100644 index 0000000000000..166c126103284 --- /dev/null +++ b/lib/srv/discovery/access_graph_azure.go @@ -0,0 +1,419 @@ +/* + * Teleport + * Copyright (C) 2025 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 discovery + +import ( + "context" + "errors" + "io" + "sync" + "time" + + "github.com/gravitational/trace" + "google.golang.org/grpc" + "google.golang.org/grpc/connectivity" + + "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/api/utils/retryutils" + "github.com/gravitational/teleport/entitlements" + accessgraphv1alpha "github.com/gravitational/teleport/gen/proto/go/accessgraph/v1alpha" + "github.com/gravitational/teleport/lib/modules" + "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/srv/discovery/fetchers/azuresync" +) + +// reconcileAccessGraphAzure fetches Azure resources, creates a set of resources to delete and upsert based on +// the previous fetch, and then sends the delete and upsert results to the Access Graph stream +func (s *Server) reconcileAccessGraphAzure( + ctx context.Context, + currentTAGResources *azuresync.Resources, + stream accessgraphv1alpha.AccessGraphService_AzureEventsStreamClient, + features azuresync.Features, +) error { + type fetcherResult struct { + result *azuresync.Resources + err error + } + + // Get all the fetchers + allFetchers := s.getAllTAGSyncAzureFetchers() + if len(allFetchers) == 0 { + // If there are no fetchers, we don't need to continue. + // We will send a delete request for all resources and return. + upsert, toDel := azuresync.ReconcileResults(currentTAGResources, &azuresync.Resources{}) + + if err := azurePush(stream, upsert, toDel); err != nil { + s.Log.ErrorContext(ctx, "Error pushing empty resources to TAGs", "error", err) + } + return trace.Wrap(errNoAccessGraphFetchers) + } + + for _, fetcher := range allFetchers { + s.tagSyncStatus.syncStarted(fetcher, s.clock.Now()) + } + for _, discoveryConfigName := range s.tagSyncStatus.discoveryConfigs() { + s.updateDiscoveryConfigStatus(discoveryConfigName) + } + + // Fetch results concurrently + resultsC := make(chan fetcherResult, len(allFetchers)) + // Restricts concurrently running fetchers to 3 + tokens := make(chan struct{}, 3) + accountIds := map[string]struct{}{} + for _, fetcher := range allFetchers { + fetcher := fetcher + accountIds[fetcher.GetSubscriptionID()] = struct{}{} + tokens <- struct{}{} + go func() { + defer func() { + <-tokens + }() + result, err := fetcher.Poll(ctx, features) + resultsC <- fetcherResult{result, trace.Wrap(err)} + }() + } + + // Collect the results from all fetchers. + results := make([]*azuresync.Resources, 0, len(allFetchers)) + errs := make([]error, 0, len(allFetchers)) + for i := 0; i < len(allFetchers); i++ { + // Each fetcher can return an error and a result. + fetcherResult := <-resultsC + if fetcherResult.err != nil { + errs = append(errs, fetcherResult.err) + } + if fetcherResult.result != nil { + results = append(results, fetcherResult.result) + } + } + + // Aggregate all errors into a single error. + err := trace.NewAggregate(errs...) + if err != nil { + s.Log.ErrorContext(ctx, "Error polling TAGs", "error", err) + } + result := azuresync.MergeResources(results...) + + // Merge all results into a single result + upsert, toDel := azuresync.ReconcileResults(currentTAGResources, result) + pushErr := azurePush(stream, upsert, toDel) + + for _, fetcher := range allFetchers { + s.tagSyncStatus.syncFinished(fetcher, pushErr, s.clock.Now()) + } + for _, discoveryConfigName := range s.tagSyncStatus.discoveryConfigs() { + s.updateDiscoveryConfigStatus(discoveryConfigName) + } + + if pushErr != nil { + s.Log.ErrorContext(ctx, "Error pushing TAGs", "error", pushErr) + return nil + } + + // Update the currentTAGResources with the result of the reconciliation. + *currentTAGResources = *result + return nil +} + +// azurePushUpsertInBatches upserts resources to the Access Graph in batches +func azurePushUpsertInBatches( + client accessgraphv1alpha.AccessGraphService_AzureEventsStreamClient, + upsert *accessgraphv1alpha.AzureResourceList, +) error { + for i := 0; i < len(upsert.Resources); i += batchSize { + end := i + batchSize + if end > len(upsert.Resources) { + end = len(upsert.Resources) + } + err := client.Send( + &accessgraphv1alpha.AzureEventsStreamRequest{ + Operation: &accessgraphv1alpha.AzureEventsStreamRequest_Upsert{ + Upsert: &accessgraphv1alpha.AzureResourceList{ + Resources: upsert.Resources[i:end], + }, + }, + }, + ) + if err != nil { + return trace.Wrap(err) + } + } + return nil +} + +// azurePushDeleteInBatches deletes resources from the Access Graph in batches +func azurePushDeleteInBatches( + client accessgraphv1alpha.AccessGraphService_AzureEventsStreamClient, + toDel *accessgraphv1alpha.AzureResourceList, +) error { + for i := 0; i < len(toDel.Resources); i += batchSize { + end := i + batchSize + if end > len(toDel.Resources) { + end = len(toDel.Resources) + } + err := client.Send( + &accessgraphv1alpha.AzureEventsStreamRequest{ + Operation: &accessgraphv1alpha.AzureEventsStreamRequest_Delete{ + Delete: &accessgraphv1alpha.AzureResourceList{ + Resources: toDel.Resources[i:end], + }, + }, + }, + ) + if err != nil { + return trace.Wrap(err) + } + } + return nil +} + +// azurePush upserts and deletes Azure resources to/from the Access Graph +func azurePush( + client accessgraphv1alpha.AccessGraphService_AzureEventsStreamClient, + upsert *accessgraphv1alpha.AzureResourceList, + toDel *accessgraphv1alpha.AzureResourceList, +) error { + err := azurePushUpsertInBatches(client, upsert) + if err != nil { + return trace.Wrap(err) + } + err = azurePushDeleteInBatches(client, toDel) + if err != nil { + return trace.Wrap(err) + } + err = client.Send( + &accessgraphv1alpha.AzureEventsStreamRequest{ + Operation: &accessgraphv1alpha.AzureEventsStreamRequest_Sync{}, + }, + ) + return trace.Wrap(err) +} + +// getAllTAGSyncAzureFetchers returns both static and dynamic TAG Azure fetchers +func (s *Server) getAllTAGSyncAzureFetchers() []*azuresync.Fetcher { + allFetchers := make([]*azuresync.Fetcher, 0, len(s.dynamicTAGAzureFetchers)) + + s.muDynamicTAGAzureFetchers.RLock() + for _, fetcherSet := range s.dynamicTAGAzureFetchers { + allFetchers = append(allFetchers, fetcherSet...) + } + s.muDynamicTAGAzureFetchers.RUnlock() + + allFetchers = append(allFetchers, s.staticTAGAzureFetchers...) + return allFetchers +} + +// initializeAndWatchAzureAccessGraph initializes and watches the TAG Azure stream +func (s *Server) initializeAndWatchAzureAccessGraph(ctx context.Context, reloadCh chan struct{}) error { + // Check if the access graph is enabled + clusterFeatures := s.Config.ClusterFeatures() + policy := modules.GetProtoEntitlement(&clusterFeatures, entitlements.Policy) + if !clusterFeatures.AccessGraph && !policy.Enabled { + return trace.Wrap(errTAGFeatureNotEnabled) + } + + // Configure the access graph semaphore for constraining multiple discovery servers + const ( + semaphoreExpiration = time.Minute + semaphoreName = "access_graph_azure_sync" + ) + lease, err := services.AcquireSemaphoreLockWithRetry( + ctx, + services.SemaphoreLockConfigWithRetry{ + SemaphoreLockConfig: services.SemaphoreLockConfig{ + Service: s.AccessPoint, + Params: types.AcquireSemaphoreRequest{ + SemaphoreKind: types.KindAccessGraph, + SemaphoreName: semaphoreName, + MaxLeases: 1, + Holder: s.Config.ServerID, + }, + Expiry: semaphoreExpiration, + Clock: s.clock, + }, + Retry: retryutils.LinearConfig{ + Clock: s.clock, + First: time.Second, + Step: semaphoreExpiration / 2, + Max: semaphoreExpiration, + Jitter: retryutils.DefaultJitter, + }, + }, + ) + if err != nil { + return trace.Wrap(err) + } + ctx, cancel := context.WithCancel(lease) + defer cancel() + defer func() { + lease.Stop() + if err := lease.Wait(); err != nil { + s.Log.WarnContext(ctx, "error cleaning up semaphore", "error", err, "semaphore", semaphoreName) + } + }() + + // Create the access graph client + accessGraphConn, err := newAccessGraphClient( + ctx, + s.GetClientCert, + s.Config.AccessGraphConfig, + grpc.WithDefaultServiceConfig(serviceConfig), + ) + if err != nil { + return trace.Wrap(err) + } + // Close the connection when the function returns. + defer accessGraphConn.Close() + client := accessgraphv1alpha.NewAccessGraphServiceClient(accessGraphConn) + + // Create the event stream + stream, err := client.AzureEventsStream(ctx) + if err != nil { + s.Log.ErrorContext(ctx, "Failed to get TAG Azure service stream", "error", err) + return trace.Wrap(err) + } + header, err := stream.Header() + if err != nil { + s.Log.ErrorContext(ctx, "Failed to get TAG Azure service stream header", "error", err) + return trace.Wrap(err) + } + const ( + supportedResourcesKey = "supported-kinds" + ) + supportedKinds := header.Get(supportedResourcesKey) + if len(supportedKinds) == 0 { + return trace.BadParameter("TAG Azure service did not return supported kinds") + } + features := azuresync.BuildFeatures(supportedKinds...) + + // Cancels the context to stop the event watcher if the access graph connection fails + var wg sync.WaitGroup + defer wg.Wait() + wg.Add(1) + go func() { + defer wg.Done() + defer cancel() + if !accessGraphConn.WaitForStateChange(ctx, connectivity.Ready) { + s.Log.InfoContext(ctx, "access graph service connection was closed") + } + }() + + // Configure the poll interval + tickerInterval := defaultPollInterval + if s.Config.Matchers.AccessGraph != nil { + if s.Config.Matchers.AccessGraph.PollInterval > defaultPollInterval { + tickerInterval = s.Config.Matchers.AccessGraph.PollInterval + } else { + s.Log.WarnContext(ctx, + "Access graph Azure service poll interval cannot be less than the default", + "default_poll_interval", + defaultPollInterval) + } + } + s.Log.InfoContext(ctx, "Access graph Azure service poll interval", "poll_interval", tickerInterval) + + // Reconciles the resources as they're imported from Azure + azureResources := &azuresync.Resources{} + ticker := time.NewTicker(15 * time.Minute) + defer ticker.Stop() + for { + err := s.reconcileAccessGraphAzure(ctx, azureResources, stream, features) + if errors.Is(err, errNoAccessGraphFetchers) { + err := stream.CloseSend() + if errors.Is(err, io.EOF) { + err = nil + } + return trace.Wrap(err) + } + select { + case <-ctx.Done(): + return trace.Wrap(ctx.Err()) + case <-ticker.C: + case <-reloadCh: + } + } +} + +// initTAGAzureWatchers initializes the TAG Azure watchers +func (s *Server) initTAGAzureWatchers(ctx context.Context, cfg *Config) error { + staticFetchers, err := s.accessGraphAzureFetchersFromMatchers(cfg.Matchers, "" /* discoveryConfigName */) + if err != nil { + s.Log.ErrorContext(ctx, "Error initializing access graph fetchers", "error", err) + } + s.staticTAGAzureFetchers = staticFetchers + if !cfg.AccessGraphConfig.Enabled { + return nil + } + go func() { + reloadCh := s.newDiscoveryConfigChangedSub() + for { + fetchers := s.getAllTAGSyncAzureFetchers() + // Wait for the config to change and re-evaluate the fetchers before starting the sync. + if len(fetchers) == 0 { + s.Log.DebugContext(ctx, "No Azure sync fetchers configured. Access graph sync will not be enabled.") + select { + case <-ctx.Done(): + return + case <-reloadCh: + // if the config changes, we need to get the updated list of fetchers + } + continue + } + // Reset the Azure resources to force a full sync + if err := s.initializeAndWatchAzureAccessGraph(ctx, reloadCh); errors.Is(err, errTAGFeatureNotEnabled) { + s.Log.WarnContext(ctx, "Access Graph specified in config, but the license does not include Teleport Policy. Access graph sync will not be enabled.") + break + } else if err != nil { + s.Log.WarnContext(ctx, "Error initializing and watching access graph", "error", err) + } + + select { + case <-ctx.Done(): + return + case <-time.After(time.Minute): + } + } + }() + return nil +} + +// accessGraphAzureFetchersFromMatchers converts matcher configuration to fetchers for Azure resource synchronization +func (s *Server) accessGraphAzureFetchersFromMatchers( + matchers Matchers, discoveryConfigName string) ([]*azuresync.Fetcher, error) { + var fetchers []*azuresync.Fetcher + var errs []error + if matchers.AccessGraph == nil { + return fetchers, nil + } + for _, matcher := range matchers.AccessGraph.Azure { + fetcherCfg := azuresync.Config{ + SubscriptionID: matcher.SubscriptionID, + Integration: matcher.Integration, + DiscoveryConfigName: discoveryConfigName, + OIDCCredentials: s.AccessPoint, + } + fetcher, err := azuresync.NewFetcher(fetcherCfg, s.ctx) + if err != nil { + errs = append(errs, err) + continue + } + fetchers = append(fetchers, fetcher) + } + return fetchers, trace.NewAggregate(errs...) +} diff --git a/lib/srv/discovery/access_graph_test.go b/lib/srv/discovery/access_graph_test.go index b02c32348c6af..c6efe1064cbfc 100644 --- a/lib/srv/discovery/access_graph_test.go +++ b/lib/srv/discovery/access_graph_test.go @@ -36,7 +36,7 @@ func TestServer_updateDiscoveryConfigStatus(t *testing.T) { testErr := "test error" clock := clockwork.NewFakeClock() type args struct { - fetchers []aws_sync.AWSSync + fetchers []*fakeFetcher pushErr error preRun bool } @@ -48,8 +48,8 @@ func TestServer_updateDiscoveryConfigStatus(t *testing.T) { { name: "test updateDiscoveryConfigStatus", args: args{ - fetchers: []aws_sync.AWSSync{ - &fakeFetcher{ + fetchers: []*fakeFetcher{ + { count: 1, discoveryConfigName: "test", }, @@ -71,8 +71,8 @@ func TestServer_updateDiscoveryConfigStatus(t *testing.T) { { name: "test updateDiscoveryConfigStatus with pushError", args: args{ - fetchers: []aws_sync.AWSSync{ - &fakeFetcher{ + fetchers: []*fakeFetcher{ + { count: 1, discoveryConfigName: "test", }, @@ -94,8 +94,8 @@ func TestServer_updateDiscoveryConfigStatus(t *testing.T) { { name: "test updateDiscoveryConfigStatus with error", args: args{ - fetchers: []aws_sync.AWSSync{ - &fakeFetcher{ + fetchers: []*fakeFetcher{ + { count: 1, discoveryConfigName: "test", err: errors.New(testErr), @@ -117,8 +117,8 @@ func TestServer_updateDiscoveryConfigStatus(t *testing.T) { { name: "discar reports for non-discovery config results", args: args{ - fetchers: []aws_sync.AWSSync{ - &fakeFetcher{ + fetchers: []*fakeFetcher{ + { count: 1, }, }, @@ -128,8 +128,8 @@ func TestServer_updateDiscoveryConfigStatus(t *testing.T) { { name: "test updateDiscoveryConfigStatus pre-run", args: args{ - fetchers: []aws_sync.AWSSync{ - &fakeFetcher{ + fetchers: []*fakeFetcher{ + { discoveryConfigName: "test", }, }, @@ -150,16 +150,16 @@ func TestServer_updateDiscoveryConfigStatus(t *testing.T) { { name: "test multiple aws sync fetchers", args: args{ - fetchers: []aws_sync.AWSSync{ - &fakeFetcher{ + fetchers: []*fakeFetcher{ + { discoveryConfigName: "test1", count: 1, }, - &fakeFetcher{ + { discoveryConfigName: "test1", count: 1, }, - &fakeFetcher{ + { discoveryConfigName: "test2", count: 1, }, @@ -189,7 +189,7 @@ func TestServer_updateDiscoveryConfigStatus(t *testing.T) { { name: "merge two errors", args: args{ - fetchers: []aws_sync.AWSSync{ + fetchers: []*fakeFetcher{ &fakeFetcher{ discoveryConfigName: "test1", err: fmt.Errorf("error in fetcher 1"), @@ -214,12 +214,12 @@ func TestServer_updateDiscoveryConfigStatus(t *testing.T) { { name: "reports error if at least one fetcher fails", args: args{ - fetchers: []aws_sync.AWSSync{ - &fakeFetcher{ + fetchers: []*fakeFetcher{ + { discoveryConfigName: "test1", err: fmt.Errorf("error in fetcher 1"), }, - &fakeFetcher{ + { discoveryConfigName: "test1", count: 2, }, @@ -247,16 +247,20 @@ func TestServer_updateDiscoveryConfigStatus(t *testing.T) { AccessPoint: accessPoint, clock: clock, }, - awsSyncStatus: awsSyncStatus{}, + tagSyncStatus: newTagSyncStatus(), } if tt.args.preRun { - s.awsSyncStatus.iterationStarted(tt.args.fetchers, s.clock.Now()) + for _, fetcher := range tt.args.fetchers { + s.tagSyncStatus.syncStarted(fetcher, s.clock.Now()) + } } else { - s.awsSyncStatus.iterationFinished(tt.args.fetchers, tt.args.pushErr, s.clock.Now()) + for _, fetcher := range tt.args.fetchers { + s.tagSyncStatus.syncFinished(fetcher, tt.args.pushErr, s.clock.Now()) + } } - for _, discoveryConfigName := range s.awsSyncStatus.discoveryConfigs() { + for _, discoveryConfigName := range s.tagSyncStatus.discoveryConfigs() { s.updateDiscoveryConfigStatus(discoveryConfigName) } @@ -270,7 +274,7 @@ func stringPointer(s string) *string { } type fakeFetcher struct { - aws_sync.AWSSync + aws_sync.Fetcher err error count uint64 discoveryConfigName string diff --git a/lib/srv/discovery/discovery.go b/lib/srv/discovery/discovery.go index d7eb68a47cd0e..179b3734e09e6 100644 --- a/lib/srv/discovery/discovery.go +++ b/lib/srv/discovery/discovery.go @@ -60,6 +60,7 @@ import ( "github.com/gravitational/teleport/lib/srv/discovery/common" "github.com/gravitational/teleport/lib/srv/discovery/fetchers" aws_sync "github.com/gravitational/teleport/lib/srv/discovery/fetchers/aws-sync" + azure_sync "github.com/gravitational/teleport/lib/srv/discovery/fetchers/azuresync" "github.com/gravitational/teleport/lib/srv/discovery/fetchers/db" "github.com/gravitational/teleport/lib/srv/server" logutils "github.com/gravitational/teleport/lib/utils/log" @@ -331,11 +332,17 @@ type Server struct { muDynamicServerGCPFetchers sync.RWMutex staticServerGCPFetchers []server.Fetcher - // dynamicTAGSyncFetchers holds the current TAG Fetchers for the Dynamic Matchers (those coming from DiscoveryConfig resource). + // dynamicTAGAWSFetchers holds the current TAG Fetchers for the Dynamic Matchers (those coming from DiscoveryConfig resource). // The key is the DiscoveryConfig name. - dynamicTAGSyncFetchers map[string][]aws_sync.AWSSync - muDynamicTAGSyncFetchers sync.RWMutex - staticTAGSyncFetchers []aws_sync.AWSSync + dynamicTAGAWSFetchers map[string][]*aws_sync.Fetcher + muDynamicTAGAWSFetchers sync.RWMutex + staticTAGAWSFetchers []*aws_sync.Fetcher + + // dynamicTAGAzureFetchers holds the current TAG Fetchers for the Dynamic Matchers (those coming from DiscoveryConfig resource). + // The key is the DiscoveryConfig name. + dynamicTAGAzureFetchers map[string][]*azure_sync.Fetcher + muDynamicTAGAzureFetchers sync.RWMutex + staticTAGAzureFetchers []*azure_sync.Fetcher // dynamicKubeFetchers holds the current kube fetchers that use integration as a source of credentials, // for the Dynamic Matchers (those coming from DiscoveryConfig resource). @@ -345,7 +352,7 @@ type Server struct { dynamicDiscoveryConfig map[string]*discoveryconfig.DiscoveryConfig - awsSyncStatus awsSyncStatus + tagSyncStatus *tagSyncStatus awsEC2ResourcesStatus awsResourcesStatus awsRDSResourcesStatus awsResourcesStatus awsEKSResourcesStatus awsResourcesStatus @@ -382,9 +389,10 @@ func New(ctx context.Context, cfg *Config) (*Server, error) { dynamicServerAWSFetchers: make(map[string][]server.Fetcher), dynamicServerAzureFetchers: make(map[string][]server.Fetcher), dynamicServerGCPFetchers: make(map[string][]server.Fetcher), - dynamicTAGSyncFetchers: make(map[string][]aws_sync.AWSSync), + dynamicTAGAWSFetchers: make(map[string][]*aws_sync.Fetcher), + dynamicTAGAzureFetchers: make(map[string][]*azure_sync.Fetcher), dynamicDiscoveryConfig: make(map[string]*discoveryconfig.DiscoveryConfig), - awsSyncStatus: awsSyncStatus{}, + tagSyncStatus: newTagSyncStatus(), awsEC2ResourcesStatus: newAWSResourceStatusCollector(types.AWSMatcherEC2), awsRDSResourcesStatus: newAWSResourceStatusCollector(types.AWSMatcherRDS), awsEKSResourcesStatus: newAWSResourceStatusCollector(types.AWSMatcherEKS), @@ -423,7 +431,11 @@ func New(ctx context.Context, cfg *Config) (*Server, error) { return nil, trace.Wrap(err) } - if err := s.initAccessGraphWatchers(s.ctx, cfg); err != nil { + if err := s.initTAGAWSWatchers(s.ctx, cfg); err != nil { + return nil, trace.Wrap(err) + } + + if err := s.initTAGAzureWatchers(s.ctx, cfg); err != nil { return nil, trace.Wrap(err) } @@ -1653,9 +1665,13 @@ func (s *Server) deleteDynamicFetchers(name string) { delete(s.dynamicServerGCPFetchers, name) s.muDynamicServerGCPFetchers.Unlock() - s.muDynamicTAGSyncFetchers.Lock() - delete(s.dynamicTAGSyncFetchers, name) - s.muDynamicTAGSyncFetchers.Unlock() + s.muDynamicTAGAWSFetchers.Lock() + delete(s.dynamicTAGAWSFetchers, name) + s.muDynamicTAGAWSFetchers.Unlock() + + s.muDynamicTAGAzureFetchers.Lock() + delete(s.dynamicTAGAzureFetchers, name) + s.muDynamicTAGAzureFetchers.Unlock() s.muDynamicKubeFetchers.Lock() delete(s.dynamicKubeFetchers, name) @@ -1703,15 +1719,23 @@ func (s *Server) upsertDynamicMatchers(ctx context.Context, dc *discoveryconfig. s.dynamicDatabaseFetchers[dc.GetName()] = databaseFetchers s.muDynamicDatabaseFetchers.Unlock() - awsSyncMatchers, err := s.accessGraphFetchersFromMatchers( + awsSyncMatchers, err := s.accessGraphAWSFetchersFromMatchers( ctx, matchers, dc.GetName(), ) if err != nil { return trace.Wrap(err) } - s.muDynamicTAGSyncFetchers.Lock() - s.dynamicTAGSyncFetchers[dc.GetName()] = awsSyncMatchers - s.muDynamicTAGSyncFetchers.Unlock() + s.muDynamicTAGAWSFetchers.Lock() + s.dynamicTAGAWSFetchers[dc.GetName()] = awsSyncMatchers + s.muDynamicTAGAWSFetchers.Unlock() + + azureSyncMatchers, err := s.accessGraphAzureFetchersFromMatchers(matchers, dc.GetName()) + if err != nil { + return trace.Wrap(err) + } + s.muDynamicTAGAzureFetchers.Lock() + s.dynamicTAGAzureFetchers[dc.GetName()] = azureSyncMatchers + s.muDynamicTAGAzureFetchers.Unlock() kubeFetchers, err := s.kubeFetchersFromMatchers(matchers, dc.GetName()) if err != nil { diff --git a/lib/srv/discovery/fetchers/aws-sync/aws-sync.go b/lib/srv/discovery/fetchers/aws-sync/aws-sync.go index 4e2c5510def86..63ebdae041ff3 100644 --- a/lib/srv/discovery/fetchers/aws-sync/aws-sync.go +++ b/lib/srv/discovery/fetchers/aws-sync/aws-sync.go @@ -63,28 +63,14 @@ type AssumeRole struct { ExternalID string } -// awsFetcher is a fetcher that fetches AWS resources. -type awsFetcher struct { +// Fetcher is a fetcher that fetches AWS resources. +type Fetcher struct { Config lastError error lastDiscoveredResources uint64 lastResult *Resources } -// AWSSync is the interface for fetching AWS resources. -type AWSSync interface { - // Poll polls all AWS resources and returns the result. - Poll(context.Context, Features) (*Resources, error) - // Status reports the last known status of the fetcher. - Status() (uint64, error) - // DiscoveryConfigName returns the name of the Discovery Config. - DiscoveryConfigName() string - // IsFromDiscoveryConfig returns true if the fetcher is associated with a Discovery Config. - IsFromDiscoveryConfig() bool - // GetAccountID returns the AWS account ID. - GetAccountID() string -} - // Resources is a collection of polled AWS resources. type Resources struct { // Users is the list of AWS users. @@ -174,9 +160,9 @@ func (r *Resources) UsageReport(numberAccounts int) *usageeventsv1.AccessGraphAW } } -// NewAWSFetcher creates a new AWS fetcher. -func NewAWSFetcher(ctx context.Context, cfg Config) (AWSSync, error) { - a := &awsFetcher{ +// NewFetcher creates a new AWS fetcher. +func NewFetcher(ctx context.Context, cfg Config) (*Fetcher, error) { + a := &Fetcher{ Config: cfg, lastResult: &Resources{}, } @@ -192,14 +178,14 @@ func NewAWSFetcher(ctx context.Context, cfg Config) (AWSSync, error) { // Poll is a blocking call and will return when all resources have been fetched. // It's possible that the call returns Resources and an error at the same time // if some resources were fetched successfully and some were not. -func (a *awsFetcher) Poll(ctx context.Context, features Features) (*Resources, error) { +func (a *Fetcher) Poll(ctx context.Context, features Features) (*Resources, error) { result, err := a.poll(ctx, features) deduplicateResources(result) a.storeReport(result, err) return result, trace.Wrap(err) } -func (a *awsFetcher) storeReport(rec *Resources, err error) { +func (a *Fetcher) storeReport(rec *Resources, err error) { a.lastError = err if rec == nil { return @@ -208,11 +194,11 @@ func (a *awsFetcher) storeReport(rec *Resources, err error) { a.lastDiscoveredResources = uint64(rec.count()) } -func (a *awsFetcher) GetAccountID() string { +func (a *Fetcher) GetAccountID() string { return a.AccountID } -func (a *awsFetcher) poll(ctx context.Context, features Features) (*Resources, error) { +func (a *Fetcher) poll(ctx context.Context, features Features) (*Resources, error) { eGroup, ctx := errgroup.WithContext(ctx) // Set the limit for the number of concurrent pollers running in parallel. // This is to prevent the number of concurrent pollers from growing too large @@ -293,7 +279,7 @@ func (a *awsFetcher) poll(ctx context.Context, features Features) (*Resources, e // getAWSOptions returns a list of AWSAssumeRoleOptionFn to be used when // creating AWS clients. -func (a *awsFetcher) getAWSOptions() []cloud.AWSOptionsFn { +func (a *Fetcher) getAWSOptions() []cloud.AWSOptionsFn { opts := []cloud.AWSOptionsFn{ cloud.WithCredentialsMaybeIntegration(a.Config.Integration), } @@ -318,7 +304,7 @@ func (a *awsFetcher) getAWSOptions() []cloud.AWSOptionsFn { return opts } -func (a *awsFetcher) getAccountId(ctx context.Context) (string, error) { +func (a *Fetcher) getAccountId(ctx context.Context) (string, error) { stsClient, err := a.CloudClients.GetAWSSTSClient( ctx, "", /* region is empty because groups are global */ @@ -337,14 +323,14 @@ func (a *awsFetcher) getAccountId(ctx context.Context) (string, error) { return aws.StringValue(req.Account), nil } -func (a *awsFetcher) DiscoveryConfigName() string { +func (a *Fetcher) DiscoveryConfigName() string { return a.Config.DiscoveryConfigName } -func (a *awsFetcher) IsFromDiscoveryConfig() bool { +func (a *Fetcher) IsFromDiscoveryConfig() bool { return a.Config.DiscoveryConfigName != "" } -func (a *awsFetcher) Status() (uint64, error) { +func (a *Fetcher) Status() (uint64, error) { return a.lastDiscoveredResources, a.lastError } diff --git a/lib/srv/discovery/fetchers/aws-sync/ec2.go b/lib/srv/discovery/fetchers/aws-sync/ec2.go index dcbe9b26f7167..d4cb99540938f 100644 --- a/lib/srv/discovery/fetchers/aws-sync/ec2.go +++ b/lib/srv/discovery/fetchers/aws-sync/ec2.go @@ -36,7 +36,7 @@ import ( // pollAWSEC2Instances is a function that returns a function that fetches // ec2 instances and instance profiles and returns an error if any. -func (a *awsFetcher) pollAWSEC2Instances(ctx context.Context, result *Resources, collectErr func(error)) func() error { +func (a *Fetcher) pollAWSEC2Instances(ctx context.Context, result *Resources, collectErr func(error)) func() error { return func() error { var err error @@ -56,7 +56,7 @@ func (a *awsFetcher) pollAWSEC2Instances(ctx context.Context, result *Resources, // as a slice of accessgraphv1alpha.AWSInstanceV1. // It uses ec2.DescribeInstancesPagesWithContext to iterate over all instances // in all regions. -func (a *awsFetcher) fetchAWSEC2Instances(ctx context.Context) ([]*accessgraphv1alpha.AWSInstanceV1, error) { +func (a *Fetcher) fetchAWSEC2Instances(ctx context.Context) ([]*accessgraphv1alpha.AWSInstanceV1, error) { var ( hosts []*accessgraphv1alpha.AWSInstanceV1 hostsMu sync.Mutex @@ -147,7 +147,7 @@ func awsInstanceToProtoInstance(instance *ec2.Instance, region string, accountID // fetchInstanceProfiles fetches instance profiles from all regions and returns them // as a slice of accessgraphv1alpha.AWSInstanceProfileV1. -func (a *awsFetcher) fetchInstanceProfiles(ctx context.Context) ([]*accessgraphv1alpha.AWSInstanceProfileV1, error) { +func (a *Fetcher) fetchInstanceProfiles(ctx context.Context) ([]*accessgraphv1alpha.AWSInstanceProfileV1, error) { var existing = a.lastResult.InstanceProfiles var profiles []*accessgraphv1alpha.AWSInstanceProfileV1 iamClient, err := a.CloudClients.GetAWSIAMClient( diff --git a/lib/srv/discovery/fetchers/aws-sync/eks.go b/lib/srv/discovery/fetchers/aws-sync/eks.go index e4a7cc768ecd2..6a5f689de49ef 100644 --- a/lib/srv/discovery/fetchers/aws-sync/eks.go +++ b/lib/srv/discovery/fetchers/aws-sync/eks.go @@ -34,7 +34,7 @@ import ( // pollAWSEKSClusters is a function that returns a function that fetches // eks clusters and their access scope levels. -func (a *awsFetcher) pollAWSEKSClusters(ctx context.Context, result *Resources, collectErr func(error)) func() error { +func (a *Fetcher) pollAWSEKSClusters(ctx context.Context, result *Resources, collectErr func(error)) func() error { return func() error { output, err := a.fetchAWSSEKSClusters(ctx) if err != nil { @@ -55,7 +55,7 @@ type fetchAWSEKSClustersOutput struct { } // fetchAWSSEKSClusters fetches eks instances from all regions. -func (a *awsFetcher) fetchAWSSEKSClusters(ctx context.Context) (fetchAWSEKSClustersOutput, error) { +func (a *Fetcher) fetchAWSSEKSClusters(ctx context.Context) (fetchAWSEKSClustersOutput, error) { var ( output fetchAWSEKSClustersOutput hostsMu sync.Mutex @@ -203,7 +203,7 @@ func awsEKSClusterToProtoCluster(cluster *eks.Cluster, region, accountID string) } // fetchAccessEntries fetches the access entries for the given cluster. -func (a *awsFetcher) fetchAccessEntries(ctx context.Context, eksClient eksiface.EKSAPI, cluster *accessgraphv1alpha.AWSEKSClusterV1) ([]*accessgraphv1alpha.AWSEKSClusterAccessEntryV1, error) { +func (a *Fetcher) fetchAccessEntries(ctx context.Context, eksClient eksiface.EKSAPI, cluster *accessgraphv1alpha.AWSEKSClusterV1) ([]*accessgraphv1alpha.AWSEKSClusterAccessEntryV1, error) { var accessEntries []string var errs []error @@ -277,7 +277,7 @@ func awsAccessEntryToProtoAccessEntry(accessEntry *eks.AccessEntry, cluster *acc } // fetchAccessEntries fetches the access entries for the given cluster. -func (a *awsFetcher) fetchAssociatedPolicies(ctx context.Context, eksClient eksiface.EKSAPI, cluster *accessgraphv1alpha.AWSEKSClusterV1, arns []string) ([]*accessgraphv1alpha.AWSEKSAssociatedAccessPolicyV1, error) { +func (a *Fetcher) fetchAssociatedPolicies(ctx context.Context, eksClient eksiface.EKSAPI, cluster *accessgraphv1alpha.AWSEKSClusterV1, arns []string) ([]*accessgraphv1alpha.AWSEKSAssociatedAccessPolicyV1, error) { var associatedPolicies []*accessgraphv1alpha.AWSEKSAssociatedAccessPolicyV1 var errs []error for _, arn := range arns { diff --git a/lib/srv/discovery/fetchers/aws-sync/eks_test.go b/lib/srv/discovery/fetchers/aws-sync/eks_test.go index 9c6c395018d95..f51e15a8ad078 100644 --- a/lib/srv/discovery/fetchers/aws-sync/eks_test.go +++ b/lib/srv/discovery/fetchers/aws-sync/eks_test.go @@ -134,7 +134,7 @@ func TestPollAWSEKSClusters(t *testing.T) { defer mu.Unlock() errs = append(errs, err) } - a := &awsFetcher{ + a := &Fetcher{ Config: Config{ AccountID: accountID, CloudClients: mockedClients, diff --git a/lib/srv/discovery/fetchers/aws-sync/groups.go b/lib/srv/discovery/fetchers/aws-sync/groups.go index cf8499794c1ac..78b643a4def17 100644 --- a/lib/srv/discovery/fetchers/aws-sync/groups.go +++ b/lib/srv/discovery/fetchers/aws-sync/groups.go @@ -33,7 +33,7 @@ import ( // pollAWSGroups is a function that returns a function that fetches // AWS groups and their inline and attached policies. -func (a *awsFetcher) pollAWSGroups(ctx context.Context, result *Resources, collectErr func(error)) func() error { +func (a *Fetcher) pollAWSGroups(ctx context.Context, result *Resources, collectErr func(error)) func() error { return func() error { var err error @@ -89,7 +89,7 @@ func (a *awsFetcher) pollAWSGroups(ctx context.Context, result *Resources, colle // fetchGroups fetches AWS groups and returns them as a slice of accessgraphv1alpha.AWSGroupV1. // It uses ListGroupsPagesWithContext to iterate over all groups. -func (a *awsFetcher) fetchGroups(ctx context.Context) ([]*accessgraphv1alpha.AWSGroupV1, error) { +func (a *Fetcher) fetchGroups(ctx context.Context) ([]*accessgraphv1alpha.AWSGroupV1, error) { var groups []*accessgraphv1alpha.AWSGroupV1 iamClient, err := a.CloudClients.GetAWSIAMClient( @@ -132,7 +132,7 @@ func awsGroupToProtoGroup(group *iam.Group, accountID string) *accessgraphv1alph // as a slice of accessgraphv1alpha.AWSGroupInlinePolicyV1. // It uses ListGroupPoliciesPagesWithContext to iterate over all inline policies // associated with the group. -func (a *awsFetcher) fetchGroupInlinePolicies(ctx context.Context, group *accessgraphv1alpha.AWSGroupV1) ([]*accessgraphv1alpha.AWSGroupInlinePolicyV1, error) { +func (a *Fetcher) fetchGroupInlinePolicies(ctx context.Context, group *accessgraphv1alpha.AWSGroupV1) ([]*accessgraphv1alpha.AWSGroupInlinePolicyV1, error) { var policies []*accessgraphv1alpha.AWSGroupInlinePolicyV1 var errs []error errCollect := func(err error) { @@ -183,7 +183,7 @@ func awsGroupPolicyToProtoGroupPolicy(policy *iam.GetGroupPolicyOutput, accountI } // fetchGroupAttachedPolicies fetches attached policies for a group. -func (a *awsFetcher) fetchGroupAttachedPolicies(ctx context.Context, group *accessgraphv1alpha.AWSGroupV1) (*accessgraphv1alpha.AWSGroupAttachedPolicies, error) { +func (a *Fetcher) fetchGroupAttachedPolicies(ctx context.Context, group *accessgraphv1alpha.AWSGroupV1) (*accessgraphv1alpha.AWSGroupAttachedPolicies, error) { rsp := &accessgraphv1alpha.AWSGroupAttachedPolicies{ Group: group, AccountId: a.AccountID, diff --git a/lib/srv/discovery/fetchers/aws-sync/iam_test.go b/lib/srv/discovery/fetchers/aws-sync/iam_test.go index a6af06ba26a8a..3e3f161633b8c 100644 --- a/lib/srv/discovery/fetchers/aws-sync/iam_test.go +++ b/lib/srv/discovery/fetchers/aws-sync/iam_test.go @@ -62,7 +62,7 @@ func TestAWSIAMPollSAMLProviders(t *testing.T) { defer mu.Unlock() errs = append(errs, err) } - a := &awsFetcher{ + a := &Fetcher{ Config: Config{ AccountID: accountID, CloudClients: mockedClients, @@ -203,7 +203,7 @@ func TestAWSIAMPollOIDCProviders(t *testing.T) { defer mu.Unlock() errs = append(errs, err) } - a := &awsFetcher{ + a := &Fetcher{ Config: Config{ AccountID: accountID, CloudClients: mockedClients, diff --git a/lib/srv/discovery/fetchers/aws-sync/idp.go b/lib/srv/discovery/fetchers/aws-sync/idp.go index 4ff3edef71149..5ead115526f1e 100644 --- a/lib/srv/discovery/fetchers/aws-sync/idp.go +++ b/lib/srv/discovery/fetchers/aws-sync/idp.go @@ -32,7 +32,7 @@ import ( accessgraphv1alpha "github.com/gravitational/teleport/gen/proto/go/accessgraph/v1alpha" ) -func (a *awsFetcher) pollAWSSAMLProviders(ctx context.Context, result *Resources, collectErr func(error)) func() error { +func (a *Fetcher) pollAWSSAMLProviders(ctx context.Context, result *Resources, collectErr func(error)) func() error { return func() error { var err error existing := a.lastResult @@ -74,7 +74,7 @@ func (a *awsFetcher) pollAWSSAMLProviders(ctx context.Context, result *Resources } // fetchAWSSAMLProvider fetches data about a single SAML identity provider. -func (a *awsFetcher) fetchAWSSAMLProvider(ctx context.Context, client iamiface.IAMAPI, arn string) (*accessgraphv1alpha.AWSSAMLProviderV1, error) { +func (a *Fetcher) fetchAWSSAMLProvider(ctx context.Context, client iamiface.IAMAPI, arn string) (*accessgraphv1alpha.AWSSAMLProviderV1, error) { providerResp, err := client.GetSAMLProviderWithContext(ctx, &iam.GetSAMLProviderInput{ SAMLProviderArn: aws.String(arn), }) @@ -132,7 +132,7 @@ func awsSAMLProviderOutputToProto(arn string, accountID string, provider *iam.Ge }, nil } -func (a *awsFetcher) pollAWSOIDCProviders(ctx context.Context, result *Resources, collectErr func(error)) func() error { +func (a *Fetcher) pollAWSOIDCProviders(ctx context.Context, result *Resources, collectErr func(error)) func() error { return func() error { var err error existing := a.lastResult @@ -174,7 +174,7 @@ func (a *awsFetcher) pollAWSOIDCProviders(ctx context.Context, result *Resources } // fetchAWSOIDCProvider fetches data about a single OIDC identity provider. -func (a *awsFetcher) fetchAWSOIDCProvider(ctx context.Context, client iamiface.IAMAPI, arn string) (*accessgraphv1alpha.AWSOIDCProviderV1, error) { +func (a *Fetcher) fetchAWSOIDCProvider(ctx context.Context, client iamiface.IAMAPI, arn string) (*accessgraphv1alpha.AWSOIDCProviderV1, error) { providerResp, err := client.GetOpenIDConnectProviderWithContext(ctx, &iam.GetOpenIDConnectProviderInput{ OpenIDConnectProviderArn: aws.String(arn), }) diff --git a/lib/srv/discovery/fetchers/aws-sync/policies.go b/lib/srv/discovery/fetchers/aws-sync/policies.go index 57bb981eef8e6..755b23ecdae49 100644 --- a/lib/srv/discovery/fetchers/aws-sync/policies.go +++ b/lib/srv/discovery/fetchers/aws-sync/policies.go @@ -33,7 +33,7 @@ import ( // pollAWSPolicies is a function that returns a function that fetches // AWS policies and returns an error if any. -func (a *awsFetcher) pollAWSPolicies(ctx context.Context, result *Resources, collectErr func(error)) func() error { +func (a *Fetcher) pollAWSPolicies(ctx context.Context, result *Resources, collectErr func(error)) func() error { return func() error { var err error result.Policies, err = a.fetchPolicies(ctx) @@ -48,7 +48,7 @@ func (a *awsFetcher) pollAWSPolicies(ctx context.Context, result *Resources, col // accessgraphv1alpha.AWSPolicyV1. // It uses iam.ListPoliciesPagesWithContext to iterate over all policies // and iam.GetPolicyVersionWithContext to fetch policy documents. -func (a *awsFetcher) fetchPolicies(ctx context.Context) ([]*accessgraphv1alpha.AWSPolicyV1, error) { +func (a *Fetcher) fetchPolicies(ctx context.Context) ([]*accessgraphv1alpha.AWSPolicyV1, error) { var policies []*accessgraphv1alpha.AWSPolicyV1 var errs []error var mu sync.Mutex diff --git a/lib/srv/discovery/fetchers/aws-sync/rds.go b/lib/srv/discovery/fetchers/aws-sync/rds.go index 08195e2132e82..7d39b5284be4d 100644 --- a/lib/srv/discovery/fetchers/aws-sync/rds.go +++ b/lib/srv/discovery/fetchers/aws-sync/rds.go @@ -33,7 +33,7 @@ import ( // pollAWSRDSDatabases is a function that returns a function that fetches // RDS instances and clusters. -func (a *awsFetcher) pollAWSRDSDatabases(ctx context.Context, result *Resources, collectErr func(error)) func() error { +func (a *Fetcher) pollAWSRDSDatabases(ctx context.Context, result *Resources, collectErr func(error)) func() error { return func() error { var err error result.RDSDatabases, err = a.fetchAWSRDSDatabases(ctx, a.lastResult) @@ -45,7 +45,7 @@ func (a *awsFetcher) pollAWSRDSDatabases(ctx context.Context, result *Resources, } // fetchAWSRDSDatabases fetches RDS databases from all regions. -func (a *awsFetcher) fetchAWSRDSDatabases(ctx context.Context, existing *Resources) ( +func (a *Fetcher) fetchAWSRDSDatabases(ctx context.Context, existing *Resources) ( []*accessgraphv1alpha.AWSRDSDatabaseV1, error, ) { diff --git a/lib/srv/discovery/fetchers/aws-sync/rds_test.go b/lib/srv/discovery/fetchers/aws-sync/rds_test.go index bed0811d88e1d..316e9e8d943d6 100644 --- a/lib/srv/discovery/fetchers/aws-sync/rds_test.go +++ b/lib/srv/discovery/fetchers/aws-sync/rds_test.go @@ -115,7 +115,7 @@ func TestPollAWSRDS(t *testing.T) { defer mu.Unlock() errs = append(errs, err) } - a := &awsFetcher{ + a := &Fetcher{ Config: Config{ AccountID: accountID, CloudClients: mockedClients, diff --git a/lib/srv/discovery/fetchers/aws-sync/roles.go b/lib/srv/discovery/fetchers/aws-sync/roles.go index 9bc007261ea31..99ab3ca2188fd 100644 --- a/lib/srv/discovery/fetchers/aws-sync/roles.go +++ b/lib/srv/discovery/fetchers/aws-sync/roles.go @@ -35,7 +35,7 @@ import ( // pollAWSRoles is a function that returns a function that fetches // AWS roles and their inline and attached policies. -func (a *awsFetcher) pollAWSRoles(ctx context.Context, result *Resources, collectErr func(error)) func() error { +func (a *Fetcher) pollAWSRoles(ctx context.Context, result *Resources, collectErr func(error)) func() error { return func() error { var err error existing := a.lastResult @@ -84,7 +84,7 @@ func (a *awsFetcher) pollAWSRoles(ctx context.Context, result *Resources, collec } // fetchRoles fetches AWS roles and returns them as a slice of accessgraphv1alpha.AWSRoleV1. -func (a *awsFetcher) fetchRoles(ctx context.Context) ([]*accessgraphv1alpha.AWSRoleV1, error) { +func (a *Fetcher) fetchRoles(ctx context.Context) ([]*accessgraphv1alpha.AWSRoleV1, error) { var roles []*accessgraphv1alpha.AWSRoleV1 iamClient, err := a.CloudClients.GetAWSIAMClient( @@ -114,7 +114,7 @@ func (a *awsFetcher) fetchRoles(ctx context.Context) ([]*accessgraphv1alpha.AWSR // them as a slice of accessgraphv1alpha.AWSRoleInlinePolicyV1. // It uses iam.ListRolePoliciesPagesWithContext to iterate over all inline policies // and iam.GetRolePolicyWithContext to fetch policy documents. -func (a *awsFetcher) fetchRoleInlinePolicies(ctx context.Context, role *accessgraphv1alpha.AWSRoleV1) ([]*accessgraphv1alpha.AWSRoleInlinePolicyV1, error) { +func (a *Fetcher) fetchRoleInlinePolicies(ctx context.Context, role *accessgraphv1alpha.AWSRoleV1) ([]*accessgraphv1alpha.AWSRoleInlinePolicyV1, error) { var policies []*accessgraphv1alpha.AWSRoleInlinePolicyV1 var errs []error errCollect := func(err error) { @@ -154,7 +154,7 @@ func (a *awsFetcher) fetchRoleInlinePolicies(ctx context.Context, role *accessgr } // fetchRoleAttachedPolicies fetches attached policies for an AWS role. -func (a *awsFetcher) fetchRoleAttachedPolicies(ctx context.Context, role *accessgraphv1alpha.AWSRoleV1) (*accessgraphv1alpha.AWSRoleAttachedPolicies, error) { +func (a *Fetcher) fetchRoleAttachedPolicies(ctx context.Context, role *accessgraphv1alpha.AWSRoleV1) (*accessgraphv1alpha.AWSRoleAttachedPolicies, error) { rsp := &accessgraphv1alpha.AWSRoleAttachedPolicies{ AwsRole: role, AccountId: a.AccountID, diff --git a/lib/srv/discovery/fetchers/aws-sync/s3.go b/lib/srv/discovery/fetchers/aws-sync/s3.go index a0c81e9d55436..ce3f0da9cf335 100644 --- a/lib/srv/discovery/fetchers/aws-sync/s3.go +++ b/lib/srv/discovery/fetchers/aws-sync/s3.go @@ -37,7 +37,7 @@ import ( // pollAWSS3Buckets is a function that returns a function that fetches // AWS s3 buckets and their inline and attached policies. -func (a *awsFetcher) pollAWSS3Buckets(ctx context.Context, result *Resources, collectErr func(error)) func() error { +func (a *Fetcher) pollAWSS3Buckets(ctx context.Context, result *Resources, collectErr func(error)) func() error { return func() error { var err error result.S3Buckets, err = a.fetchS3Buckets(ctx) @@ -50,7 +50,7 @@ func (a *awsFetcher) pollAWSS3Buckets(ctx context.Context, result *Resources, co // fetchS3Buckets fetches AWS s3 buckets and returns them as a slice of // accessgraphv1alpha.AWSS3BucketV1. -func (a *awsFetcher) fetchS3Buckets(ctx context.Context) ([]*accessgraphv1alpha.AWSS3BucketV1, error) { +func (a *Fetcher) fetchS3Buckets(ctx context.Context) ([]*accessgraphv1alpha.AWSS3BucketV1, error) { var s3s []*accessgraphv1alpha.AWSS3BucketV1 var errs []error var mu sync.Mutex @@ -201,7 +201,7 @@ type s3Details struct { tags *s3.GetBucketTaggingOutput } -func (a *awsFetcher) getS3BucketDetails(ctx context.Context, bucket *s3.Bucket, bucketRegion string) (s3Details, failedRequests, []error) { +func (a *Fetcher) getS3BucketDetails(ctx context.Context, bucket *s3.Bucket, bucketRegion string) (s3Details, failedRequests, []error) { var failedReqs failedRequests var errs []error var details s3Details @@ -278,7 +278,7 @@ func isS3BucketNoTagSet(err error) bool { return errors.As(err, &awsErr) && awsErr.Code() == "NoSuchTagSet" } -func (a *awsFetcher) listS3Buckets(ctx context.Context) ([]*s3.Bucket, func(*string) (string, error), error) { +func (a *Fetcher) listS3Buckets(ctx context.Context) ([]*s3.Bucket, func(*string) (string, error), error) { region := awsutil.GetKnownRegions()[0] if len(a.Regions) > 0 { region = a.Regions[0] diff --git a/lib/srv/discovery/fetchers/aws-sync/s3_test.go b/lib/srv/discovery/fetchers/aws-sync/s3_test.go index a10ad3bb6985d..318ad1c087dbb 100644 --- a/lib/srv/discovery/fetchers/aws-sync/s3_test.go +++ b/lib/srv/discovery/fetchers/aws-sync/s3_test.go @@ -166,7 +166,7 @@ func TestPollAWSS3(t *testing.T) { defer mu.Unlock() errs = append(errs, err) } - a := &awsFetcher{ + a := &Fetcher{ Config: Config{ AccountID: accountID, CloudClients: mockedClients, diff --git a/lib/srv/discovery/fetchers/aws-sync/users.go b/lib/srv/discovery/fetchers/aws-sync/users.go index a169e67a23308..b0963fde33545 100644 --- a/lib/srv/discovery/fetchers/aws-sync/users.go +++ b/lib/srv/discovery/fetchers/aws-sync/users.go @@ -33,7 +33,7 @@ import ( // pollAWSUsers is a function that returns a function that fetches // AWS users and their inline and attached policies, and groups. -func (a *awsFetcher) pollAWSUsers(ctx context.Context, result, existing *Resources, collectErr func(error)) func() error { +func (a *Fetcher) pollAWSUsers(ctx context.Context, result, existing *Resources, collectErr func(error)) func() error { return func() error { var err error @@ -103,7 +103,7 @@ func (a *awsFetcher) pollAWSUsers(ctx context.Context, result, existing *Resourc // fetchUsers fetches AWS users and returns them as a slice of accessgraphv1alpha.AWSUserV1. // It uses iam.ListUsersPagesWithContext to iterate over all users. -func (a *awsFetcher) fetchUsers(ctx context.Context) ([]*accessgraphv1alpha.AWSUserV1, error) { +func (a *Fetcher) fetchUsers(ctx context.Context) ([]*accessgraphv1alpha.AWSUserV1, error) { var users []*accessgraphv1alpha.AWSUserV1 iamClient, err := a.CloudClients.GetAWSIAMClient( @@ -162,7 +162,7 @@ func awsUserToProtoUser(user *iam.User, accountID string) *accessgraphv1alpha.AW } } -func (a *awsFetcher) fetchUserInlinePolicies(ctx context.Context, user *accessgraphv1alpha.AWSUserV1) ([]*accessgraphv1alpha.AWSUserInlinePolicyV1, error) { +func (a *Fetcher) fetchUserInlinePolicies(ctx context.Context, user *accessgraphv1alpha.AWSUserV1) ([]*accessgraphv1alpha.AWSUserInlinePolicyV1, error) { var policies []*accessgraphv1alpha.AWSUserInlinePolicyV1 var errs []error errCollect := func(err error) { @@ -211,7 +211,7 @@ func awsUserPolicyToProtoUserPolicy(policy *iam.GetUserPolicyOutput, user *acces } } -func (a *awsFetcher) fetchUserAttachedPolicies(ctx context.Context, user *accessgraphv1alpha.AWSUserV1) (*accessgraphv1alpha.AWSUserAttachedPolicies, error) { +func (a *Fetcher) fetchUserAttachedPolicies(ctx context.Context, user *accessgraphv1alpha.AWSUserV1) (*accessgraphv1alpha.AWSUserAttachedPolicies, error) { rsp := &accessgraphv1alpha.AWSUserAttachedPolicies{ User: user, AccountId: a.AccountID, @@ -250,7 +250,7 @@ func (a *awsFetcher) fetchUserAttachedPolicies(ctx context.Context, user *access return rsp, trace.Wrap(err) } -func (a *awsFetcher) fetchGroupsForUser(ctx context.Context, user *accessgraphv1alpha.AWSUserV1) (*accessgraphv1alpha.AWSUserGroupsV1, error) { +func (a *Fetcher) fetchGroupsForUser(ctx context.Context, user *accessgraphv1alpha.AWSUserV1) (*accessgraphv1alpha.AWSUserGroupsV1, error) { userGroups := &accessgraphv1alpha.AWSUserGroupsV1{ User: user, LastSyncTime: timestamppb.Now(), diff --git a/lib/srv/discovery/fetchers/azuresync/azure-sync.go b/lib/srv/discovery/fetchers/azuresync/azure-sync.go new file mode 100644 index 0000000000000..3f00071c9e679 --- /dev/null +++ b/lib/srv/discovery/fetchers/azuresync/azure-sync.go @@ -0,0 +1,275 @@ +/* + * Teleport + * Copyright (C) 2025 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 azuresync + +import ( + "context" + + "github.com/Azure/azure-sdk-for-go/sdk/azidentity" + "github.com/gravitational/trace" + "golang.org/x/sync/errgroup" + + "github.com/gravitational/teleport/api/types" + accessgraphv1alpha "github.com/gravitational/teleport/gen/proto/go/accessgraph/v1alpha" + "github.com/gravitational/teleport/lib/cloud/azure" + "github.com/gravitational/teleport/lib/msgraph" + "github.com/gravitational/teleport/lib/utils/slices" +) + +// fetcherConcurrency is an arbitrary per-resource type concurrency to ensure significant throughput. As we increase +// the number of resource types, we may increase this value or use some other approach to fetching concurrency. +const fetcherConcurrency = 4 + +type AzureOIDCCredentials interface { + GenerateAzureOIDCToken(ctx context.Context, integration string) (string, error) + GetIntegration(ctx context.Context, name string) (types.Integration, error) +} + +// Config defines parameters required for fetching resources from Azure +type Config struct { + // SubscriptionID is the Azure subscriptipn ID + SubscriptionID string + // Integration is the name of the associated Teleport integration + Integration string + // DiscoveryConfigName is the name of this Discovery configuration + DiscoveryConfigName string + // OIDCCredentials provides methods for fetching OIDC credentials + OIDCCredentials AzureOIDCCredentials +} + +// Resources represents the set of resources fetched from Azure +type Resources struct { + // Principals are Azure users, groups, and service principals + Principals []*accessgraphv1alpha.AzurePrincipal + // RoleDefinitions are Azure role definitions + RoleDefinitions []*accessgraphv1alpha.AzureRoleDefinition + // RoleAssignments are Azure role assignments + RoleAssignments []*accessgraphv1alpha.AzureRoleAssignment + // VirtualMachines are Azure virtual machines + VirtualMachines []*accessgraphv1alpha.AzureVirtualMachine +} + +// Fetcher provides the functionality for fetching resources from Azure +type Fetcher struct { + // Config is the configuration values for this fetcher + Config + // lastError is the last error returned from polling + lastError error + // lastDiscoveredResources is the number of resources last returned from polling + lastDiscoveredResources uint64 + // lastResult is the last set of resources returned from polling + lastResult *Resources + + // graphClient is the MS graph client for fetching principals + graphClient *msgraph.Client + // roleAssignClient is the Azure client for fetching role assignments + roleAssignClient RoleAssignmentsClient + // roleDefClient is the Azure client for fetching role definitions + roleDefClient RoleDefinitionsClient + // vmClient is the Azure client for fetching virtual machines + vmClient VirtualMachinesClient +} + +// NewFetcher returns a new fetcher based on configuration parameters +func NewFetcher(cfg Config, ctx context.Context) (*Fetcher, error) { + var cred msgraph.AzureTokenProvider + var err error + if cfg.Integration == "" { + // Establish the credential from the managed identity + cred, err = azidentity.NewDefaultAzureCredential(nil) + if err != nil { + return nil, trace.Wrap(err) + } + } else { + // Establish the credential from OIDC credential assertion + integration, err := cfg.OIDCCredentials.GetIntegration(ctx, cfg.Integration) + if err != nil { + return nil, trace.Wrap(err) + } + azureIntegration := integration.GetAzureOIDCIntegrationSpec() + cred, err = azidentity.NewClientAssertionCredential(azureIntegration.TenantID, azureIntegration.ClientID, func(ctx context.Context) (string, error) { + return cfg.OIDCCredentials.GenerateAzureOIDCToken(ctx, cfg.Integration) + }, nil) + if err != nil { + return nil, trace.Wrap(err) + } + } + + // Create the clients for the fetcher + graphClient, err := msgraph.NewClient(msgraph.Config{ + TokenProvider: cred, + }) + if err != nil { + return nil, trace.Wrap(err) + } + roleAssignClient, err := azure.NewRoleAssignmentsClient(cfg.SubscriptionID, cred, nil) + if err != nil { + return nil, trace.Wrap(err) + } + roleDefClient, err := azure.NewRoleDefinitionsClient(cfg.SubscriptionID, cred, nil) + if err != nil { + return nil, trace.Wrap(err) + } + vmClient, err := azure.NewVirtualMachinesClient(cfg.SubscriptionID, cred, nil) + if err != nil { + return nil, trace.Wrap(err) + } + + return &Fetcher{ + Config: cfg, + lastResult: &Resources{}, + graphClient: graphClient, + roleAssignClient: roleAssignClient, + roleDefClient: roleDefClient, + vmClient: vmClient, + }, nil +} + +const ( + featNamePrincipals = "azure/principals" + featNameRoleDefinitions = "azure/roledefinitions" + featNameRoleAssignments = "azure/roleassignments" + featNameVms = "azure/virtualmachines" +) + +// Features is a set of booleans that are received from the Access Graph to indicate which resources it can receive +type Features struct { + // Principals indicates Azure principals can be be fetched + Principals bool + // RoleDefinitions indicates Azure role definitions can be fetched + RoleDefinitions bool + // RoleAssignments indicates Azure role assignments can be fetched + RoleAssignments bool + // VirtualMachines indicates Azure virtual machines can be fetched + VirtualMachines bool +} + +// BuildFeatures builds the feature flags based on supported types returned by Access Graph Azure endpoints. +func BuildFeatures(values ...string) Features { + features := Features{} + for _, value := range values { + switch value { + case featNamePrincipals: + features.Principals = true + case featNameRoleAssignments: + features.RoleAssignments = true + case featNameRoleDefinitions: + features.RoleDefinitions = true + case featNameVms: + features.VirtualMachines = true + } + } + return features +} + +// Poll fetches and deduplicates Azure resources specified by the Access Graph +func (f *Fetcher) Poll(ctx context.Context, feats Features) (*Resources, error) { + res, err := f.fetch(ctx, feats) + if res == nil { + return nil, trace.Wrap(err) + } + res.Principals = slices.DeduplicateKey(res.Principals, azurePrincipalsKey) + res.RoleAssignments = slices.DeduplicateKey(res.RoleAssignments, azureRoleAssignKey) + res.RoleDefinitions = slices.DeduplicateKey(res.RoleDefinitions, azureRoleDefKey) + res.VirtualMachines = slices.DeduplicateKey(res.VirtualMachines, azureVmKey) + return res, trace.Wrap(err) +} + +// fetch returns the resources specified by the Access Graph +func (f *Fetcher) fetch(ctx context.Context, feats Features) (*Resources, error) { + // Accumulate Azure resources + eg, ctx := errgroup.WithContext(ctx) + eg.SetLimit(fetcherConcurrency) + var result = &Resources{} + // we use a larger value (50) here so there is always room for any returned error to be sent to errsCh without blocking. + errsCh := make(chan error, 50) + if feats.Principals { + eg.Go(func() error { + principals, err := fetchPrincipals(ctx, f.SubscriptionID, f.graphClient) + if err != nil { + errsCh <- err + return nil + } + result.Principals, err = expandMemberships(ctx, f.graphClient, principals) + if err != nil { + errsCh <- err + return err + } + return nil + }) + } + if feats.RoleAssignments { + eg.Go(func() error { + roleAssigns, err := fetchRoleAssignments(ctx, f.SubscriptionID, f.roleAssignClient) + if err != nil { + errsCh <- err + return nil + } + result.RoleAssignments = roleAssigns + return nil + }) + } + if feats.RoleDefinitions { + eg.Go(func() error { + roleDefs, err := fetchRoleDefinitions(ctx, f.SubscriptionID, f.roleDefClient) + if err != nil { + errsCh <- err + return nil + } + result.RoleDefinitions = roleDefs + return nil + }) + } + if feats.VirtualMachines { + eg.Go(func() error { + vms, err := fetchVirtualMachines(ctx, f.SubscriptionID, f.vmClient) + if err != nil { + errsCh <- err + return nil + } + result.VirtualMachines = vms + return nil + }) + } + + // Return the result along with any errors collected + _ = eg.Wait() + close(errsCh) + return result, trace.NewAggregateFromChannel(errsCh, context.WithoutCancel(ctx)) +} + +// Status returns the number of resources last fetched and/or the last fetching/reconciling error +func (f *Fetcher) Status() (uint64, error) { + return f.lastDiscoveredResources, f.lastError +} + +// DiscoveryConfigName returns the name of the configured discovery +func (f *Fetcher) DiscoveryConfigName() string { + return f.Config.DiscoveryConfigName +} + +// IsFromDiscoveryConfig returns whether the discovery is from configuration or dynamic +func (f *Fetcher) IsFromDiscoveryConfig() bool { + return f.Config.DiscoveryConfigName != "" +} + +// GetSubscriptionID returns the ID of the Azure subscription +func (f *Fetcher) GetSubscriptionID() string { + return f.Config.SubscriptionID +} diff --git a/lib/srv/discovery/fetchers/azuresync/azure-sync_test.go b/lib/srv/discovery/fetchers/azuresync/azure-sync_test.go new file mode 100644 index 0000000000000..3a2ebca3c6bca --- /dev/null +++ b/lib/srv/discovery/fetchers/azuresync/azure-sync_test.go @@ -0,0 +1,234 @@ +/* + * Teleport + * Copyright (C) 2025 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 azuresync + +import ( + "context" + "fmt" + "testing" + + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v3" + "github.com/stretchr/testify/require" +) + +type testRoleDefCli struct { + returnErr bool + roleDefs []*armauthorization.RoleDefinition +} + +func (t testRoleDefCli) ListRoleDefinitions(ctx context.Context, scope string) ([]*armauthorization.RoleDefinition, error) { + if t.returnErr { + return nil, fmt.Errorf("error") + } + return t.roleDefs, nil +} + +type testRoleAssignCli struct { + returnErr bool + roleAssigns []*armauthorization.RoleAssignment +} + +func (t testRoleAssignCli) ListRoleAssignments(ctx context.Context, scope string) ([]*armauthorization.RoleAssignment, error) { + if t.returnErr { + return nil, fmt.Errorf("error") + } + return t.roleAssigns, nil +} + +type testVmCli struct { + returnErr bool + vms []*armcompute.VirtualMachine +} + +func (t testVmCli) ListVirtualMachines(ctx context.Context, resourceGroup string) ([]*armcompute.VirtualMachine, error) { + if t.returnErr { + return nil, fmt.Errorf("error") + } + return t.vms, nil +} + +func newRoleDef(id string, name string) *armauthorization.RoleDefinition { + roleName := "test_role_name" + action1 := "Microsoft.Compute/virtualMachines/read" + action2 := "Microsoft.Compute/virtualMachines/*" + action3 := "Microsoft.Compute/*" + return &armauthorization.RoleDefinition{ + ID: &id, + Name: &name, + Properties: &armauthorization.RoleDefinitionProperties{ + Permissions: []*armauthorization.Permission{ + { + Actions: []*string{&action1, &action2}, + }, + { + Actions: []*string{&action3}, + }, + }, + RoleName: &roleName, + }, + } +} + +func newRoleAssign(id string, name string) *armauthorization.RoleAssignment { + scope := "test_scope" + principalId := "test_principal_id" + roleDefId := "test_role_def_id" + return &armauthorization.RoleAssignment{ + ID: &id, + Name: &name, + Properties: &armauthorization.RoleAssignmentProperties{ + PrincipalID: &principalId, + RoleDefinitionID: &roleDefId, + Scope: &scope, + }, + } +} + +func newVm(id string, name string) *armcompute.VirtualMachine { + return &armcompute.VirtualMachine{ + ID: &id, + Name: &name, + } +} + +func TestPoll(t *testing.T) { + roleDefs := []*armauthorization.RoleDefinition{ + newRoleDef("id1", "name1"), + } + roleAssigns := []*armauthorization.RoleAssignment{ + newRoleAssign("id1", "name1"), + } + vms := []*armcompute.VirtualMachine{ + newVm("id1", "name2"), + } + roleDefClient := testRoleDefCli{} + roleAssignClient := testRoleAssignCli{} + vmClient := testVmCli{} + fetcher := Fetcher{ + Config: Config{SubscriptionID: "1234567890"}, + lastResult: &Resources{}, + roleDefClient: &roleDefClient, + roleAssignClient: &roleAssignClient, + vmClient: &vmClient, + } + ctx := context.Background() + allFeats := Features{ + RoleDefinitions: true, + RoleAssignments: true, + VirtualMachines: true, + } + noVmsFeats := allFeats + noVmsFeats.VirtualMachines = false + + tests := []struct { + name string + returnErr bool + roleDefs []*armauthorization.RoleDefinition + roleAssigns []*armauthorization.RoleAssignment + vms []*armcompute.VirtualMachine + feats Features + }{ + // Process no results from clients + { + name: "WithoutResults", + returnErr: false, + roleDefs: []*armauthorization.RoleDefinition{}, + roleAssigns: []*armauthorization.RoleAssignment{}, + vms: []*armcompute.VirtualMachine{}, + feats: allFeats, + }, + // Process test results from clients + { + name: "WithResults", + returnErr: false, + roleDefs: roleDefs, + roleAssigns: roleAssigns, + vms: vms, + feats: allFeats, + }, + // Handle errors from clients + { + name: "PollErrors", + returnErr: true, + roleDefs: roleDefs, + roleAssigns: roleAssigns, + vms: vms, + feats: allFeats, + }, + // Handle VM features being disabled + { + name: "NoVmsFeats", + returnErr: false, + roleDefs: roleDefs, + roleAssigns: roleAssigns, + vms: vms, + feats: noVmsFeats, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Set the test data + roleDefClient.returnErr = tt.returnErr + roleDefClient.roleDefs = tt.roleDefs + roleAssignClient.returnErr = tt.returnErr + roleAssignClient.roleAssigns = tt.roleAssigns + vmClient.returnErr = tt.returnErr + vmClient.vms = tt.vms + + // Poll for resources + resources, err := fetcher.Poll(ctx, tt.feats) + + // Require no error unless otherwise specified + if tt.returnErr { + require.Error(t, err) + return + } + require.NoError(t, err) + + // Verify the results, based on the features set + require.NotNil(t, resources) + require.Equal(t, tt.feats.RoleDefinitions == false || len(tt.roleDefs) == 0, len(resources.RoleDefinitions) == 0) + for idx, resource := range resources.RoleDefinitions { + roleDef := tt.roleDefs[idx] + require.Equal(t, *roleDef.ID, resource.Id) + require.Equal(t, fetcher.SubscriptionID, resource.SubscriptionId) + require.Equal(t, *roleDef.Properties.RoleName, resource.Name) + require.Len(t, roleDef.Properties.Permissions, len(resource.Permissions)) + } + require.Equal(t, tt.feats.RoleAssignments == false || len(tt.roleAssigns) == 0, len(resources.RoleAssignments) == 0) + for idx, resource := range resources.RoleAssignments { + roleAssign := tt.roleAssigns[idx] + require.Equal(t, *roleAssign.ID, resource.Id) + require.Equal(t, fetcher.SubscriptionID, resource.SubscriptionId) + require.Equal(t, *roleAssign.Properties.PrincipalID, resource.PrincipalId) + require.Equal(t, *roleAssign.Properties.RoleDefinitionID, resource.RoleDefinitionId) + require.Equal(t, *roleAssign.Properties.Scope, resource.Scope) + } + require.Equal(t, tt.feats.VirtualMachines == false || len(tt.vms) == 0, len(resources.VirtualMachines) == 0) + for idx, resource := range resources.VirtualMachines { + vm := tt.vms[idx] + require.Equal(t, *vm.ID, resource.Id) + require.Equal(t, fetcher.SubscriptionID, resource.SubscriptionId) + require.Equal(t, *vm.Name, resource.Name) + } + }) + } +} diff --git a/lib/srv/discovery/fetchers/azuresync/memberships.go b/lib/srv/discovery/fetchers/azuresync/memberships.go new file mode 100644 index 0000000000000..f05be8f72567c --- /dev/null +++ b/lib/srv/discovery/fetchers/azuresync/memberships.go @@ -0,0 +1,65 @@ +/* + * Teleport + * Copyright (C) 2025 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 azuresync + +import ( + "context" + + "github.com/gravitational/trace" + "golang.org/x/sync/errgroup" + + accessgraphv1alpha "github.com/gravitational/teleport/gen/proto/go/accessgraph/v1alpha" + "github.com/gravitational/teleport/lib/msgraph" +) + +const parallelism = 10 //nolint:unused // invoked in a dependent PR + +// expandMemberships adds membership data to AzurePrincipal objects by querying the Graph API for group memberships +func expandMemberships(ctx context.Context, cli *msgraph.Client, principals []*accessgraphv1alpha.AzurePrincipal) ([]*accessgraphv1alpha.AzurePrincipal, error) { //nolint:unused // invoked in a dependent PR + // Map principals by ID + var principalsMap = make(map[string]*accessgraphv1alpha.AzurePrincipal) + for _, principal := range principals { + principalsMap[principal.Id] = principal + } + // Iterate through the Azure groups and add the group ID as a membership for its corresponding principal + eg, _ := errgroup.WithContext(ctx) + eg.SetLimit(parallelism) + errCh := make(chan error, len(principals)) + for _, principal := range principals { + if principal.ObjectType != "group" { + continue + } + group := principal + eg.Go(func() error { + err := cli.IterateGroupMembers(ctx, group.Id, func(member msgraph.GroupMember) bool { + if memberPrincipal, ok := principalsMap[*member.GetID()]; ok { + memberPrincipal.MemberOf = append(memberPrincipal.MemberOf, group.Id) + } + return true + }) + if err != nil { + errCh <- err + } + return nil + }) + } + _ = eg.Wait() + close(errCh) + return principals, trace.NewAggregateFromChannel(errCh, ctx) +} diff --git a/lib/srv/discovery/fetchers/azuresync/principals.go b/lib/srv/discovery/fetchers/azuresync/principals.go new file mode 100644 index 0000000000000..073d6c4713e0c --- /dev/null +++ b/lib/srv/discovery/fetchers/azuresync/principals.go @@ -0,0 +1,87 @@ +/* + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package azuresync + +import ( + "context" + + "github.com/gravitational/trace" + "google.golang.org/protobuf/types/known/timestamppb" + + accessgraphv1alpha "github.com/gravitational/teleport/gen/proto/go/accessgraph/v1alpha" + "github.com/gravitational/teleport/lib/msgraph" +) + +type dirObjMetadata struct { //nolint:unused // invoked in a dependent PR + objectType string +} + +type queryResult struct { //nolint:unused // invoked in a dependent PR + metadata dirObjMetadata + dirObj msgraph.DirectoryObject +} + +// fetchPrincipals fetches the Azure principals (users, groups, and service principals) using the Graph API +func fetchPrincipals(ctx context.Context, subscriptionID string, cli *msgraph.Client) ([]*accessgraphv1alpha.AzurePrincipal, error) { //nolint: unused // invoked in a dependent PR + // Fetch the users, groups, and service principals as directory objects + var queryResults []queryResult + err := cli.IterateUsers(ctx, func(user *msgraph.User) bool { + res := queryResult{metadata: dirObjMetadata{objectType: "user"}, dirObj: user.DirectoryObject} + queryResults = append(queryResults, res) + return true + }) + if err != nil { + return nil, trace.Wrap(err) + } + err = cli.IterateGroups(ctx, func(group *msgraph.Group) bool { + res := queryResult{metadata: dirObjMetadata{objectType: "group"}, dirObj: group.DirectoryObject} + queryResults = append(queryResults, res) + return true + }) + if err != nil { + return nil, trace.Wrap(err) + } + err = cli.IterateServicePrincipals(ctx, func(servicePrincipal *msgraph.ServicePrincipal) bool { + res := queryResult{metadata: dirObjMetadata{objectType: "servicePrincipal"}, dirObj: servicePrincipal.DirectoryObject} + queryResults = append(queryResults, res) + return true + }) + if err != nil { + return nil, trace.Wrap(err) + } + + // Return the users, groups, and service principals as protobuf messages + var fetchErrs []error + var pbPrincipals []*accessgraphv1alpha.AzurePrincipal + for _, res := range queryResults { + if res.dirObj.ID == nil || res.dirObj.DisplayName == nil { + fetchErrs = append(fetchErrs, + trace.BadParameter("nil values on msgraph directory object: %v", res.dirObj)) + continue + } + pbPrincipals = append(pbPrincipals, &accessgraphv1alpha.AzurePrincipal{ + Id: *res.dirObj.ID, + SubscriptionId: subscriptionID, + LastSyncTime: timestamppb.Now(), + DisplayName: *res.dirObj.DisplayName, + ObjectType: res.metadata.objectType, + }) + } + return pbPrincipals, trace.NewAggregate(fetchErrs...) +} diff --git a/lib/srv/discovery/fetchers/azuresync/reconcile.go b/lib/srv/discovery/fetchers/azuresync/reconcile.go new file mode 100644 index 0000000000000..a874f48215811 --- /dev/null +++ b/lib/srv/discovery/fetchers/azuresync/reconcile.go @@ -0,0 +1,165 @@ +/* + * Teleport + * Copyright (C) 2025 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 azuresync + +import ( + "fmt" + + "google.golang.org/protobuf/proto" + + accessgraphv1alpha "github.com/gravitational/teleport/gen/proto/go/accessgraph/v1alpha" + "github.com/gravitational/teleport/lib/utils/slices" +) + +// MergeResources merges Azure resources fetched from multiple configured Azure fetchers +func MergeResources(results ...*Resources) *Resources { + if len(results) == 0 { + return &Resources{} + } + if len(results) == 1 { + return results[0] + } + result := &Resources{} + for _, r := range results { + result.Principals = append(result.Principals, r.Principals...) + result.RoleAssignments = append(result.RoleAssignments, r.RoleAssignments...) + result.RoleDefinitions = append(result.RoleDefinitions, r.RoleDefinitions...) + result.VirtualMachines = append(result.VirtualMachines, r.VirtualMachines...) + } + result.Principals = slices.DeduplicateKey(result.Principals, azurePrincipalsKey) + result.RoleAssignments = slices.DeduplicateKey(result.RoleAssignments, azureRoleAssignKey) + result.RoleDefinitions = slices.DeduplicateKey(result.RoleDefinitions, azureRoleDefKey) + result.VirtualMachines = slices.DeduplicateKey(result.VirtualMachines, azureVmKey) + return result +} + +// newResourceList creates a new resource list message +func newResourceList() *accessgraphv1alpha.AzureResourceList { + return &accessgraphv1alpha.AzureResourceList{ + Resources: make([]*accessgraphv1alpha.AzureResource, 0), + } +} + +// ReconcileResults compares previously and currently fetched results and determines which resources to upsert and +// which to delete. +func ReconcileResults(old *Resources, new *Resources) (upsert, delete *accessgraphv1alpha.AzureResourceList) { + upsert, delete = newResourceList(), newResourceList() + reconciledResources := []*reconcilePair{ + reconcile(old.Principals, new.Principals, azurePrincipalsKey, azurePrincipalsWrap), + reconcile(old.RoleAssignments, new.RoleAssignments, azureRoleAssignKey, azureRoleAssignWrap), + reconcile(old.RoleDefinitions, new.RoleDefinitions, azureRoleDefKey, azureRoleDefWrap), + reconcile(old.VirtualMachines, new.VirtualMachines, azureVmKey, azureVmWrap), + } + for _, res := range reconciledResources { + upsert.Resources = append(upsert.Resources, res.upsert.Resources...) + delete.Resources = append(delete.Resources, res.delete.Resources...) + } + return upsert, delete +} + +// reconcilePair contains the Azure resources to upsert and delete +type reconcilePair struct { + upsert, delete *accessgraphv1alpha.AzureResourceList +} + +// reconcile compares old and new items to build a list of resources to upsert and delete in the Access Graph +func reconcile[T proto.Message]( + oldItems []T, + newItems []T, + keyFn func(T) string, + wrapFn func(T) *accessgraphv1alpha.AzureResource, +) *reconcilePair { + // Remove duplicates from the new items + newItems = slices.DeduplicateKey(newItems, keyFn) + upsertRes := newResourceList() + deleteRes := newResourceList() + + // Delete all old items if there are no new items + if len(newItems) == 0 { + for _, item := range oldItems { + deleteRes.Resources = append(deleteRes.Resources, wrapFn(item)) + } + return &reconcilePair{upsertRes, deleteRes} + } + + // Create all new items if there are no old items + if len(oldItems) == 0 { + for _, item := range newItems { + upsertRes.Resources = append(upsertRes.Resources, wrapFn(item)) + } + return &reconcilePair{upsertRes, deleteRes} + } + + // Map old and new items by their key + oldMap := make(map[string]T, len(oldItems)) + for _, item := range oldItems { + oldMap[keyFn(item)] = item + } + newMap := make(map[string]T, len(newItems)) + for _, item := range newItems { + newMap[keyFn(item)] = item + } + + // Append new or modified items to the upsert list + for _, item := range newItems { + if oldItem, ok := oldMap[keyFn(item)]; !ok || !proto.Equal(oldItem, item) { + upsertRes.Resources = append(upsertRes.Resources, wrapFn(item)) + } + } + + // Append removed items to the delete list + for _, item := range oldItems { + if _, ok := newMap[keyFn(item)]; !ok { + deleteRes.Resources = append(deleteRes.Resources, wrapFn(item)) + } + } + return &reconcilePair{upsertRes, deleteRes} +} + +func azurePrincipalsKey(user *accessgraphv1alpha.AzurePrincipal) string { + return fmt.Sprintf("%s:%s", user.SubscriptionId, user.Id) +} + +func azurePrincipalsWrap(principal *accessgraphv1alpha.AzurePrincipal) *accessgraphv1alpha.AzureResource { + return &accessgraphv1alpha.AzureResource{Resource: &accessgraphv1alpha.AzureResource_Principal{Principal: principal}} +} + +func azureRoleAssignKey(roleAssign *accessgraphv1alpha.AzureRoleAssignment) string { + return fmt.Sprintf("%s:%s", roleAssign.SubscriptionId, roleAssign.Id) +} + +func azureRoleAssignWrap(roleAssign *accessgraphv1alpha.AzureRoleAssignment) *accessgraphv1alpha.AzureResource { + return &accessgraphv1alpha.AzureResource{Resource: &accessgraphv1alpha.AzureResource_RoleAssignment{RoleAssignment: roleAssign}} +} + +func azureRoleDefKey(roleDef *accessgraphv1alpha.AzureRoleDefinition) string { + return fmt.Sprintf("%s:%s", roleDef.SubscriptionId, roleDef.Id) +} + +func azureRoleDefWrap(roleDef *accessgraphv1alpha.AzureRoleDefinition) *accessgraphv1alpha.AzureResource { + return &accessgraphv1alpha.AzureResource{Resource: &accessgraphv1alpha.AzureResource_RoleDefinition{RoleDefinition: roleDef}} +} + +func azureVmKey(vm *accessgraphv1alpha.AzureVirtualMachine) string { + return fmt.Sprintf("%s:%s", vm.SubscriptionId, vm.Id) +} + +func azureVmWrap(vm *accessgraphv1alpha.AzureVirtualMachine) *accessgraphv1alpha.AzureResource { + return &accessgraphv1alpha.AzureResource{Resource: &accessgraphv1alpha.AzureResource_VirtualMachine{VirtualMachine: vm}} +} diff --git a/lib/srv/discovery/fetchers/azuresync/reconcile_test.go b/lib/srv/discovery/fetchers/azuresync/reconcile_test.go new file mode 100644 index 0000000000000..3652c4963218c --- /dev/null +++ b/lib/srv/discovery/fetchers/azuresync/reconcile_test.go @@ -0,0 +1,197 @@ +/* + * Teleport + * Copyright (C) 2025 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 azuresync + +import ( + "testing" + + "github.com/stretchr/testify/require" + + accessgraphv1alpha "github.com/gravitational/teleport/gen/proto/go/accessgraph/v1alpha" +) + +func TestReconcileResults(t *testing.T) { + principals := generatePrincipals() + roleDefs := generateRoleDefs() + roleAssigns := generateRoleAssigns() + vms := generateVms() + + tests := []struct { + name string + oldResults *Resources + newResults *Resources + expectedUpserts *accessgraphv1alpha.AzureResourceList + expectedDeletes *accessgraphv1alpha.AzureResourceList + }{ + // Overlapping old and new results + { + name: "OverlapOldAndNewResults", + oldResults: &Resources{ + Principals: principals[0:2], + RoleDefinitions: roleDefs[0:2], + RoleAssignments: roleAssigns[0:2], + VirtualMachines: vms[0:2], + }, + newResults: &Resources{ + Principals: principals[1:3], + RoleDefinitions: roleDefs[1:3], + RoleAssignments: roleAssigns[1:3], + VirtualMachines: vms[1:3], + }, + expectedUpserts: generateExpected(principals[2:3], roleDefs[2:3], roleAssigns[2:3], vms[2:3]), + expectedDeletes: generateExpected(principals[0:1], roleDefs[0:1], roleAssigns[0:1], vms[0:1]), + }, + // Completely new results + { + name: "CompletelyNewResults", + oldResults: &Resources{ + Principals: nil, + RoleDefinitions: nil, + RoleAssignments: nil, + VirtualMachines: nil, + }, + newResults: &Resources{ + Principals: principals[1:3], + RoleDefinitions: roleDefs[1:3], + RoleAssignments: roleAssigns[1:3], + VirtualMachines: vms[1:3], + }, + expectedUpserts: generateExpected(principals[1:3], roleDefs[1:3], roleAssigns[1:3], vms[1:3]), + expectedDeletes: generateExpected(nil, nil, nil, nil), + }, + // No new results + { + name: "NoNewResults", + oldResults: &Resources{ + Principals: principals[1:3], + RoleDefinitions: roleDefs[1:3], + RoleAssignments: roleAssigns[1:3], + VirtualMachines: vms[1:3], + }, + newResults: &Resources{ + Principals: nil, + RoleDefinitions: nil, + RoleAssignments: nil, + VirtualMachines: nil, + }, + expectedUpserts: generateExpected(nil, nil, nil, nil), + expectedDeletes: generateExpected(principals[1:3], roleDefs[1:3], roleAssigns[1:3], vms[1:3]), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + upserts, deletes := ReconcileResults(tt.oldResults, tt.newResults) + require.ElementsMatch(t, upserts.Resources, tt.expectedUpserts.Resources) + require.ElementsMatch(t, deletes.Resources, tt.expectedDeletes.Resources) + }) + } + +} + +func generateExpected( + principals []*accessgraphv1alpha.AzurePrincipal, + roleDefs []*accessgraphv1alpha.AzureRoleDefinition, + roleAssigns []*accessgraphv1alpha.AzureRoleAssignment, + vms []*accessgraphv1alpha.AzureVirtualMachine, +) *accessgraphv1alpha.AzureResourceList { + resList := &accessgraphv1alpha.AzureResourceList{ + Resources: make([]*accessgraphv1alpha.AzureResource, 0), + } + for _, principal := range principals { + resList.Resources = append(resList.Resources, azurePrincipalsWrap(principal)) + } + for _, roleDef := range roleDefs { + resList.Resources = append(resList.Resources, azureRoleDefWrap(roleDef)) + } + for _, roleAssign := range roleAssigns { + resList.Resources = append(resList.Resources, azureRoleAssignWrap(roleAssign)) + } + for _, vm := range vms { + resList.Resources = append(resList.Resources, azureVmWrap(vm)) + } + return resList +} + +func generatePrincipals() []*accessgraphv1alpha.AzurePrincipal { + return []*accessgraphv1alpha.AzurePrincipal{ + { + Id: "/principals/foo", + DisplayName: "userFoo", + }, + { + Id: "/principals/bar", + DisplayName: "userBar", + }, + { + Id: "/principals/charles", + DisplayName: "userCharles", + }, + } +} + +func generateRoleDefs() []*accessgraphv1alpha.AzureRoleDefinition { + return []*accessgraphv1alpha.AzureRoleDefinition{ + { + Id: "/roledefinitions/foo", + Name: "roleFoo", + }, + { + Id: "/roledefinitions/bar", + Name: "roleBar", + }, + { + Id: "/roledefinitions/charles", + Name: "roleCharles", + }, + } +} + +func generateRoleAssigns() []*accessgraphv1alpha.AzureRoleAssignment { + return []*accessgraphv1alpha.AzureRoleAssignment{ + { + Id: "/roleassignments/foo", + PrincipalId: "userFoo", + }, + { + Id: "/roleassignments/bar", + PrincipalId: "userBar", + }, + { + Id: "/roleassignments/charles", + PrincipalId: "userCharles", + }, + } +} + +func generateVms() []*accessgraphv1alpha.AzureVirtualMachine { + return []*accessgraphv1alpha.AzureVirtualMachine{ + { + Id: "/vms/foo", + Name: "userFoo", + }, + { + Id: "/vms/bar", + Name: "userBar", + }, + { + Id: "/vms/charles", + Name: "userCharles", + }, + } +} diff --git a/lib/srv/discovery/fetchers/azuresync/roleassignments.go b/lib/srv/discovery/fetchers/azuresync/roleassignments.go new file mode 100644 index 0000000000000..a97fe69727ef8 --- /dev/null +++ b/lib/srv/discovery/fetchers/azuresync/roleassignments.go @@ -0,0 +1,68 @@ +/* + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package azuresync + +import ( + "context" + "fmt" + + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2" + "github.com/gravitational/trace" + "google.golang.org/protobuf/types/known/timestamppb" + + accessgraphv1alpha "github.com/gravitational/teleport/gen/proto/go/accessgraph/v1alpha" +) + +// RoleAssignmentsClient specifies the methods used to fetch role assignments from Azure +type RoleAssignmentsClient interface { + ListRoleAssignments(ctx context.Context, scope string) ([]*armauthorization.RoleAssignment, error) +} + +// fetchRoleAssignments fetches Azure role assignments using the Azure role assignments API +func fetchRoleAssignments(ctx context.Context, subscriptionID string, cli RoleAssignmentsClient) ([]*accessgraphv1alpha.AzureRoleAssignment, error) { //nolint:unused // invoked in a dependent PR + // List the role definitions + roleAssigns, err := cli.ListRoleAssignments(ctx, fmt.Sprintf("/subscriptions/%s", subscriptionID)) + if err != nil { + return nil, trace.Wrap(err) + } + + // Convert to protobuf format + pbRoleAssigns := make([]*accessgraphv1alpha.AzureRoleAssignment, 0, len(roleAssigns)) + var fetchErrs []error + for _, roleAssign := range roleAssigns { + if roleAssign.ID == nil || + roleAssign.Properties == nil || + roleAssign.Properties.PrincipalID == nil || + roleAssign.Properties.Scope == nil { + fetchErrs = append(fetchErrs, + trace.BadParameter("nil values on AzureRoleAssignment object: %v", roleAssign)) + continue + } + pbRoleAssign := &accessgraphv1alpha.AzureRoleAssignment{ + Id: *roleAssign.ID, + SubscriptionId: subscriptionID, + LastSyncTime: timestamppb.Now(), + PrincipalId: *roleAssign.Properties.PrincipalID, + RoleDefinitionId: *roleAssign.Properties.RoleDefinitionID, + Scope: *roleAssign.Properties.Scope, + } + pbRoleAssigns = append(pbRoleAssigns, pbRoleAssign) + } + return pbRoleAssigns, trace.NewAggregate(fetchErrs...) +} diff --git a/lib/srv/discovery/fetchers/azuresync/roledefinitions.go b/lib/srv/discovery/fetchers/azuresync/roledefinitions.go new file mode 100644 index 0000000000000..485117f898b81 --- /dev/null +++ b/lib/srv/discovery/fetchers/azuresync/roledefinitions.go @@ -0,0 +1,78 @@ +/* + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package azuresync + +import ( + "context" + "fmt" + + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2" + "github.com/gravitational/trace" + "google.golang.org/protobuf/types/known/timestamppb" + + accessgraphv1alpha "github.com/gravitational/teleport/gen/proto/go/accessgraph/v1alpha" + "github.com/gravitational/teleport/lib/utils/slices" +) + +// RoleDefinitionsClient specifies the methods used to fetch roles from Azure +type RoleDefinitionsClient interface { + ListRoleDefinitions(ctx context.Context, scope string) ([]*armauthorization.RoleDefinition, error) +} + +func fetchRoleDefinitions(ctx context.Context, subscriptionID string, cli RoleDefinitionsClient) ([]*accessgraphv1alpha.AzureRoleDefinition, error) { //nolint:unused // used in a dependent PR + // List the role definitions + roleDefs, err := cli.ListRoleDefinitions(ctx, fmt.Sprintf("/subscriptions/%s", subscriptionID)) + if err != nil { + return nil, trace.Wrap(err) + } + + // Convert to protobuf format + pbRoleDefs := make([]*accessgraphv1alpha.AzureRoleDefinition, 0, len(roleDefs)) + var fetchErrs []error + for _, roleDef := range roleDefs { + if roleDef.ID == nil || + roleDef.Properties == nil || + roleDef.Properties.Permissions == nil || + roleDef.Properties.RoleName == nil { + fetchErrs = append(fetchErrs, trace.BadParameter("nil values on AzureRoleDefinition object: %v", roleDef)) + continue + } + pbPerms := make([]*accessgraphv1alpha.AzureRBACPermission, 0, len(roleDef.Properties.Permissions)) + for _, perm := range roleDef.Properties.Permissions { + if perm.Actions == nil && perm.NotActions == nil { + fetchErrs = append(fetchErrs, trace.BadParameter("nil values on Permission object: %v", perm)) + continue + } + pbPerm := accessgraphv1alpha.AzureRBACPermission{ + Actions: slices.FromPointers(perm.Actions), + NotActions: slices.FromPointers(perm.NotActions), + } + pbPerms = append(pbPerms, &pbPerm) + } + pbRoleDef := &accessgraphv1alpha.AzureRoleDefinition{ + Id: *roleDef.ID, + Name: *roleDef.Properties.RoleName, + SubscriptionId: subscriptionID, + LastSyncTime: timestamppb.Now(), + Permissions: pbPerms, + } + pbRoleDefs = append(pbRoleDefs, pbRoleDef) + } + return pbRoleDefs, trace.NewAggregate(fetchErrs...) +} diff --git a/lib/srv/discovery/fetchers/azuresync/virtualmachines.go b/lib/srv/discovery/fetchers/azuresync/virtualmachines.go new file mode 100644 index 0000000000000..890c09e8f85db --- /dev/null +++ b/lib/srv/discovery/fetchers/azuresync/virtualmachines.go @@ -0,0 +1,61 @@ +/* + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package azuresync + +import ( + "context" + + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v3" + "github.com/gravitational/trace" + "google.golang.org/protobuf/types/known/timestamppb" + + accessgraphv1alpha "github.com/gravitational/teleport/gen/proto/go/accessgraph/v1alpha" +) + +const allResourceGroups = "*" //nolint:unused // invoked in a dependent PR + +// VirtualMachinesClient specifies the methods used to fetch virtual machines from Azure +type VirtualMachinesClient interface { + ListVirtualMachines(ctx context.Context, resourceGroup string) ([]*armcompute.VirtualMachine, error) +} + +func fetchVirtualMachines(ctx context.Context, subscriptionID string, cli VirtualMachinesClient) ([]*accessgraphv1alpha.AzureVirtualMachine, error) { //nolint:unused // invoked in a dependent PR + vms, err := cli.ListVirtualMachines(ctx, allResourceGroups) + if err != nil { + return nil, trace.Wrap(err) + } + + // Return the VMs as protobuf messages + pbVms := make([]*accessgraphv1alpha.AzureVirtualMachine, 0, len(vms)) + var fetchErrs []error + for _, vm := range vms { + if vm.ID == nil || vm.Name == nil { + fetchErrs = append(fetchErrs, trace.BadParameter("nil values on AzureVirtualMachine object: %v", vm)) + continue + } + pbVm := accessgraphv1alpha.AzureVirtualMachine{ + Id: *vm.ID, + SubscriptionId: subscriptionID, + LastSyncTime: timestamppb.Now(), + Name: *vm.Name, + } + pbVms = append(pbVms, &pbVm) + } + return pbVms, trace.NewAggregate(fetchErrs...) +} diff --git a/lib/srv/discovery/kube_integration_watcher_test.go b/lib/srv/discovery/kube_integration_watcher_test.go index 566d587635ff6..3c4e65e34a0e4 100644 --- a/lib/srv/discovery/kube_integration_watcher_test.go +++ b/lib/srv/discovery/kube_integration_watcher_test.go @@ -503,6 +503,11 @@ func (m *mockIntegrationsTokenGenerator) GenerateAWSOIDCToken(ctx context.Contex return uuid.NewString(), nil } +// GenerateAzureOIDCToken generates a token to be used to execute an Azure OIDC Integration action. +func (m *mockIntegrationsTokenGenerator) GenerateAzureOIDCToken(ctx context.Context, integration string) (string, error) { + return uuid.NewString(), nil +} + type mockEnrollEKSClusterClient struct { createAccessEntry func(context.Context, *eks.CreateAccessEntryInput, ...func(*eks.Options)) (*eks.CreateAccessEntryOutput, error) associateAccessPolicy func(context.Context, *eks.AssociateAccessPolicyInput, ...func(*eks.Options)) (*eks.AssociateAccessPolicyOutput, error) diff --git a/lib/srv/discovery/status.go b/lib/srv/discovery/status.go index 93b88fb762d16..642deb7244c85 100644 --- a/lib/srv/discovery/status.go +++ b/lib/srv/discovery/status.go @@ -35,10 +35,19 @@ import ( "github.com/gravitational/teleport/api/utils/retryutils" libevents "github.com/gravitational/teleport/lib/events" "github.com/gravitational/teleport/lib/services" - aws_sync "github.com/gravitational/teleport/lib/srv/discovery/fetchers/aws-sync" "github.com/gravitational/teleport/lib/srv/server" ) +// FetcherStatus defines an interface for fetchers to report status +type FetcherStatus interface { + // Status reports the last known status of the fetcher. + Status() (uint64, error) + // DiscoveryConfigName returns the name of the Discovery Config. + DiscoveryConfigName() string + // IsFromDiscoveryConfig returns true if the fetcher is associated with a Discovery Config. + IsFromDiscoveryConfig() bool +} + // updateDiscoveryConfigStatus updates the DiscoveryConfig Status field with the current in-memory status. // The status will be updated with the following matchers: // - AWS Sync (TAG) status @@ -59,8 +68,8 @@ func (s *Server) updateDiscoveryConfigStatus(discoveryConfigNames ...string) { IntegrationDiscoveredResources: make(map[string]*discoveryconfigv1.IntegrationDiscoveredSummary), } - // Merge AWS Sync (TAG) status - discoveryConfigStatus = s.awsSyncStatus.mergeIntoGlobalStatus(discoveryConfigName, discoveryConfigStatus) + // Merge AWS or Azure Sync (TAG) status + discoveryConfigStatus = s.tagSyncStatus.mergeIntoGlobalStatus(discoveryConfigName, discoveryConfigStatus) // Merge AWS EC2 Instances (auto discovery) status discoveryConfigStatus = s.awsEC2ResourcesStatus.mergeIntoGlobalStatus(discoveryConfigName, discoveryConfigStatus) @@ -84,16 +93,23 @@ func (s *Server) updateDiscoveryConfigStatus(discoveryConfigNames ...string) { } } -// awsSyncStatus contains all the status for aws_sync Fetchers grouped by DiscoveryConfig. -type awsSyncStatus struct { +// tagSyncStatus contains all the status for both AWS and Azure fetchers grouped by DiscoveryConfig. +type tagSyncStatus struct { mu sync.RWMutex - // awsSyncResults maps the DiscoveryConfig name to a aws_sync result. - // Each DiscoveryConfig might have multiple `aws_sync` matchers. - awsSyncResults map[string][]awsSyncResult + // syncResults maps the DiscoveryConfig name to a AWS or Azure fetcher result. + // Each DiscoveryConfig might have multiple AWS or Azure matchers. + syncResults map[string][]tagSyncResult +} + +// newTagSyncStatus creates a new sync status object for storing results from the last fetch +func newTagSyncStatus() *tagSyncStatus { + return &tagSyncStatus{ + syncResults: make(map[string][]tagSyncResult), + } } -// awsSyncResult stores the result of the aws_sync Matchers for a given DiscoveryConfig. -type awsSyncResult struct { +// tagSyncResult stores the result of the aws_sync Matchers for a given DiscoveryConfig. +type tagSyncResult struct { // state is the State for the DiscoveryConfigStatus. // Allowed values are: // - DISCOVERY_CONFIG_STATE_SYNCING @@ -105,72 +121,65 @@ type awsSyncResult struct { discoveredResources uint64 } -func (d *awsSyncStatus) iterationFinished(fetchers []aws_sync.AWSSync, pushErr error, lastUpdate time.Time) { +func (d *tagSyncStatus) syncFinished(fetcher FetcherStatus, pushErr error, lastUpdate time.Time) { d.mu.Lock() defer d.mu.Unlock() - d.awsSyncResults = make(map[string][]awsSyncResult) - for _, fetcher := range fetchers { - // Only update the status for fetchers that are from the discovery config. - if !fetcher.IsFromDiscoveryConfig() { - continue - } - - count, statusErr := fetcher.Status() - statusAndPushErr := trace.NewAggregate(statusErr, pushErr) + // Only update the status for fetchers that are from the discovery config. + if !fetcher.IsFromDiscoveryConfig() { + return + } - fetcherResult := awsSyncResult{ - state: discoveryconfigv1.DiscoveryConfigState_DISCOVERY_CONFIG_STATE_RUNNING.String(), - lastSyncTime: lastUpdate, - discoveredResources: count, - } + count, statusErr := fetcher.Status() + statusAndPushErr := trace.NewAggregate(statusErr, pushErr) - if statusAndPushErr != nil { - errorMessage := statusAndPushErr.Error() - fetcherResult.errorMessage = &errorMessage - fetcherResult.state = discoveryconfigv1.DiscoveryConfigState_DISCOVERY_CONFIG_STATE_ERROR.String() - } + fetcherResult := tagSyncResult{ + state: discoveryconfigv1.DiscoveryConfigState_DISCOVERY_CONFIG_STATE_RUNNING.String(), + lastSyncTime: lastUpdate, + discoveredResources: count, + } - d.awsSyncResults[fetcher.DiscoveryConfigName()] = append(d.awsSyncResults[fetcher.DiscoveryConfigName()], fetcherResult) + if statusAndPushErr != nil { + errorMessage := statusAndPushErr.Error() + fetcherResult.errorMessage = &errorMessage + fetcherResult.state = discoveryconfigv1.DiscoveryConfigState_DISCOVERY_CONFIG_STATE_ERROR.String() } + + d.syncResults[fetcher.DiscoveryConfigName()] = append(d.syncResults[fetcher.DiscoveryConfigName()], fetcherResult) } -func (d *awsSyncStatus) discoveryConfigs() []string { +func (d *tagSyncStatus) discoveryConfigs() []string { d.mu.RLock() defer d.mu.RUnlock() - ret := make([]string, 0, len(d.awsSyncResults)) - for k := range d.awsSyncResults { + ret := make([]string, 0, len(d.syncResults)) + for k := range d.syncResults { ret = append(ret, k) } return ret } -func (d *awsSyncStatus) iterationStarted(fetchers []aws_sync.AWSSync, lastUpdate time.Time) { +func (d *tagSyncStatus) syncStarted(fetcher FetcherStatus, lastUpdate time.Time) { d.mu.Lock() defer d.mu.Unlock() + // Only update the status for fetchers that are from the discovery config. + if !fetcher.IsFromDiscoveryConfig() { + return + } - d.awsSyncResults = make(map[string][]awsSyncResult) - for _, fetcher := range fetchers { - // Only update the status for fetchers that are from the discovery config. - if !fetcher.IsFromDiscoveryConfig() { - continue - } - - fetcherResult := awsSyncResult{ - state: discoveryconfigv1.DiscoveryConfigState_DISCOVERY_CONFIG_STATE_SYNCING.String(), - lastSyncTime: lastUpdate, - } - - d.awsSyncResults[fetcher.DiscoveryConfigName()] = append(d.awsSyncResults[fetcher.DiscoveryConfigName()], fetcherResult) + fetcherResult := tagSyncResult{ + state: discoveryconfigv1.DiscoveryConfigState_DISCOVERY_CONFIG_STATE_SYNCING.String(), + lastSyncTime: lastUpdate, } + + d.syncResults[fetcher.DiscoveryConfigName()] = append(d.syncResults[fetcher.DiscoveryConfigName()], fetcherResult) } -func (d *awsSyncStatus) mergeIntoGlobalStatus(discoveryConfigName string, existingStatus discoveryconfig.Status) discoveryconfig.Status { +func (d *tagSyncStatus) mergeIntoGlobalStatus(discoveryConfigName string, existingStatus discoveryconfig.Status) discoveryconfig.Status { d.mu.RLock() defer d.mu.RUnlock() - awsStatusFetchers, found := d.awsSyncResults[discoveryConfigName] + awsStatusFetchers, found := d.syncResults[discoveryConfigName] if !found { return existingStatus } diff --git a/lib/utils/slices/slices.go b/lib/utils/slices/slices.go index d0ce95010748f..077911c8738cf 100644 --- a/lib/utils/slices/slices.go +++ b/lib/utils/slices/slices.go @@ -35,3 +35,39 @@ func FilterMapUnique[T any, S comparable](ts []T, fn func(T) (s S, include bool) return ss } + +// ToPointers converts a slice of values to a slice of pointers to those values +func ToPointers[T any](in []T) []*T { + out := make([]*T, len(in)) + for i := range in { + out[i] = &in[i] + } + return out +} + +// FromPointers converts a slice of pointers to values to a slice of values. +// Nil pointers are converted to zero-values. +func FromPointers[T any](in []*T) []T { + out := make([]T, len(in)) + for i := range in { + if in[i] == nil { + continue + } + out[i] = *in[i] + } + return out +} + +// DeduplicateKey returns a deduplicated slice by comparing key values from the key function +func DeduplicateKey[T any](s []T, key func(T) string) []T { + out := make([]T, 0, len(s)) + seen := make(map[string]struct{}) + for _, v := range s { + if _, ok := seen[key(v)]; ok { + continue + } + seen[key(v)] = struct{}{} + out = append(out, v) + } + return out +} diff --git a/lib/utils/slices/slices_test.go b/lib/utils/slices/slices_test.go index 1f031d21eca49..b0fe86a1bfd2e 100644 --- a/lib/utils/slices/slices_test.go +++ b/lib/utils/slices/slices_test.go @@ -19,6 +19,7 @@ package slices import ( + "fmt" "strings" "testing" @@ -92,3 +93,92 @@ func TestFilterMapUnique(t *testing.T) { require.Equal(t, expected, got) }) } + +// TestDuplicateKey tests slice deduplication via key function +func TestDeduplicateKey(t *testing.T) { + t.Parallel() + + stringTests := []struct { + name string + slice []string + keyFn func(string) string + expected []string + }{ + { + name: "EmptyStringSlice", + slice: []string{}, + keyFn: func(s string) string { return s }, + expected: []string{}, + }, + { + name: "NoStringDuplicates", + slice: []string{"foo", "bar", "baz"}, + keyFn: func(s string) string { return s }, + expected: []string{"foo", "bar", "baz"}, + }, + { + name: "StringDuplicates", + slice: []string{"foo", "bar", "bar", "bar", "baz", "baz"}, + keyFn: func(s string) string { return s }, + expected: []string{"foo", "bar", "baz"}, + }, + { + name: "StringDuplicatesWeirdKeyFn", + slice: []string{"foo", "bar", "bar", "bar", "baz", "baz"}, + keyFn: func(s string) string { return "huh" }, + expected: []string{"foo"}, + }, + } + for _, tt := range stringTests { + t.Run(tt.name, func(t *testing.T) { + res := DeduplicateKey(tt.slice, tt.keyFn) + require.Equal(t, tt.expected, res) + }) + } + + type dedupeStruct struct { + a string + b int + c bool + } + dedupeStructKeyFn := func(d dedupeStruct) string { return fmt.Sprintf("%s:%d:%v", d.a, d.b, d.c) } + structTests := []struct { + name string + slice []dedupeStruct + keyFn func(d dedupeStruct) string + expected []dedupeStruct + }{ + { + name: "EmptySlice", + slice: []dedupeStruct{}, + keyFn: dedupeStructKeyFn, + expected: []dedupeStruct{}, + }, + { + name: "NoStructDuplicates", + slice: []dedupeStruct{ + {a: "foo", b: 1, c: true}, + {a: "foo", b: 1, c: false}, + {a: "foo", b: 2, c: true}, + {a: "bar", b: 1, c: true}, + {a: "bar", b: 1, c: false}, + {a: "bar", b: 2, c: true}, + }, + keyFn: dedupeStructKeyFn, + expected: []dedupeStruct{ + {a: "foo", b: 1, c: true}, + {a: "foo", b: 1, c: false}, + {a: "foo", b: 2, c: true}, + {a: "bar", b: 1, c: true}, + {a: "bar", b: 1, c: false}, + {a: "bar", b: 2, c: true}, + }, + }, + } + for _, tt := range structTests { + t.Run(tt.name, func(t *testing.T) { + res := DeduplicateKey(tt.slice, tt.keyFn) + require.Equal(t, tt.expected, res) + }) + } +} diff --git a/proto/accessgraph/v1alpha/access_graph_service.proto b/proto/accessgraph/v1alpha/access_graph_service.proto index f032b2397ec02..3ce1effe5f922 100644 --- a/proto/accessgraph/v1alpha/access_graph_service.proto +++ b/proto/accessgraph/v1alpha/access_graph_service.proto @@ -21,6 +21,7 @@ syntax = "proto3"; package accessgraph.v1alpha; import "accessgraph/v1alpha/aws.proto"; +import "accessgraph/v1alpha/azure.proto"; import "accessgraph/v1alpha/entra.proto"; import "accessgraph/v1alpha/events.proto"; import "accessgraph/v1alpha/gitlab.proto"; @@ -90,6 +91,9 @@ service AccessGraphService { // NetIQEventsStream is a stream of commands to the NetIQ importer. rpc NetIQEventsStream(stream NetIQEventsStreamRequest) returns (stream NetIQEventsStreamResponse); + + // AzureEventsStream is a stream of commands to the Azure importer + rpc AzureEventsStream(stream AzureEventsStreamRequest) returns (stream AzureEventsStreamResponse); } // QueryRequest is a request to query the access graph. @@ -288,3 +292,23 @@ message NetIQSyncOperation {} // NetIQEventsStreamResponse is a response from NetIQEventsStream message NetIQEventsStreamResponse {} + +// AzureEventsStreamRequest is a request to send commands to the Azure importer +message AzureEventsStreamRequest { + oneof operation { + // sync is a command to sync the access graph with the Teleport database state. + // it's issued once Teleport finishes syncing all resources with the database. + AzureSyncOperation sync = 1; + // upsert is a command to put a resource into the access graph or update it. + AzureResourceList upsert = 2; + // delete is a command to delete a resource from the access graph when it's deleted from Teleport. + AzureResourceList delete = 3; + } +} + +// AzureSyncOperation is a command that Teleport sends to the access graph service +// at the end of the sync process. +message AzureSyncOperation {} + +// AzureEventsStreamResponse is a response from AzureEventsStream +message AzureEventsStreamResponse {} diff --git a/proto/accessgraph/v1alpha/azure.proto b/proto/accessgraph/v1alpha/azure.proto new file mode 100644 index 0000000000000..58bef9b36e97b --- /dev/null +++ b/proto/accessgraph/v1alpha/azure.proto @@ -0,0 +1,140 @@ +/* + * 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 . + */ +syntax = "proto3"; +package accessgraph.v1alpha; + +import "google/protobuf/timestamp.proto"; + +option go_package = "github.com/gravitational/teleport/gen/proto/go/accessgraph/v1alpha;accessgraphv1alpha"; + +// AzureResourceList is a list of Azure resources +message AzureResourceList { + repeated AzureResource resources = 1; +} + +// AzureResource is a list of Azure resources supported by the access graph. +message AzureResource { + oneof resource { + // principal is an Azure principal + AzurePrincipal principal = 1; + // role_definition is an Azure role definition + AzureRoleDefinition role_definition = 2; + // role_assignment is an Azure role assignment, which assigns a role definition to a principal + AzureRoleAssignment role_assignment = 3; + // virtual_machine is an Azure virtual machine, an instance of a compute resource + AzureVirtualMachine virtual_machine = 4; + } +} + +// AzureVirtualMachine is an Azure virtual machine +message AzureVirtualMachine { + // id is the ID of the virtual machine + string id = 1; + // subscription_id is the ID of the subscription to which the virtual machine belongs + string subscription_id = 2; + // last_sync_time is when the virtual machine was last fetched from Azure + google.protobuf.Timestamp last_sync_time = 3; + // name is the given name of the virtual machine + string name = 4; + // resource_group is the name of the resource group to which the virtual machine belongs + string resource_group = 5; + // tags are a collection of arbitrary key-values applied to the virtual machine + map tags = 6; + // location is the geographical location of the Virtual Machine + string location = 7; +} + +// AzureIdentity is a Graph API object identity +message AzureIdentity { + // sign_in_type is the type of identity used when signing in, e.g. "emailAddress" or "userName" + string sign_in_type = 1; + // issuer is the issuer of the identity, such as a domain name like "goteleport.com" + string issuer = 2; + // issuer_assigned_id unique identifier assigned to the user by the issuer + string issuer_assigned_id = 3; +} + +// AzurePrincipal is a Graph API principal (user, group, service principal) +message AzurePrincipal { + // id is the ID of the principal + string id = 1; + // subscription_id is the ID of the subscription to which the principal belongs + string subscription_id = 2; + // last_sync_time is when the principal was last fetched from Azure + google.protobuf.Timestamp last_sync_time = 3; + // display_name is the given name for the principal, e.g. a user's first+last name + string display_name = 4; + // member_of lists the groups and directories the principal is assigned to + repeated string member_of = 5; + // identities lists the identities that can be used to sign in to the account + repeated AzureIdentity identities = 6; + // object_type defines the type of principal, e.g. "user" or "group" + string object_type = 7; +} + +// AzureRoleAssignment links an Azure principal to a role definition with a scope +message AzureRoleAssignment { + // id is the ID of the role assignment + string id = 1; + // subscription_id is the ID of the subscription to which the role assignment belongs + string subscription_id = 2; + // last_sync_time is when the role assignment was last fetched from Azure + google.protobuf.Timestamp last_sync_time = 3; + // principal_id is the ID of the principal being assigned a role + string principal_id = 4; + // role_definition_id is the ID of the role definition assigned to the principal + string role_definition_id = 5; + // scope constrains which resources the assignment applies to + string scope = 6; + // condition further which resources the assignment applies to + string condition = 7; +} + +// AzureRoleDefinition defines a role by its permissions +message AzureRoleDefinition { + // id is the ID of the role definition + string id = 1; + // subscription_id is the ID of the subscription to which the role definition belongs + string subscription_id = 2; + // last_sync_time is when the role definition was last fetched from Azure + google.protobuf.Timestamp last_sync_time = 3; + // name is the given name for the role definition + string name = 4; + // description provides additional detail about the role definition + string description = 5; + // assignable_scopes limits the scopes defined in corresponding role assignments + repeated string assignable_scopes = 6; + // permissions define the actions and not (disallowed) actions + repeated AzureRBACPermission permissions = 7; + // role_name is the given name for the role itself + string role_name = 8; + // type defines the type of role + string type = 9; +} + +// AzureRBACPermission defines the actions and not (disallowed) actions for a role definition +message AzureRBACPermission { + // actions define the resources and verbs allowed on the resources + repeated string actions = 1; + // not_actions define the resources and verbs disallowed on the resources + repeated string not_actions = 2; + // data_actions define fine-grained resources and verbs allowed within the resource + repeated string data_actions = 3; + // not_data_actions define fine-grained resources and verbs disallowed within the resource + repeated string not_data_actions = 4; +} diff --git a/tool/teleport/common/integration_configure.go b/tool/teleport/common/integration_configure.go index 97f531910e45e..26f8d93896853 100644 --- a/tool/teleport/common/integration_configure.go +++ b/tool/teleport/common/integration_configure.go @@ -241,6 +241,22 @@ func onIntegrationConfAccessGraphAWSSync(ctx context.Context, params config.Inte return trace.Wrap(awsoidc.ConfigureAccessGraphSyncIAM(ctx, clt, confReq)) } +func onIntegrationConfAccessGraphAzureSync(ctx context.Context, params config.IntegrationConfAccessGraphAzureSync) error { + // Ensure we print output to the user. LogLevel at this point was set to Error. + utils.InitLogger(utils.LoggingForDaemon, slog.LevelInfo) + confReq := azureoidc.AccessGraphAzureConfigureRequest{ + ManagedIdentity: params.ManagedIdentity, + RoleName: params.RoleName, + SubscriptionID: params.SubscriptionID, + AutoConfirm: params.AutoConfirm, + } + clt, err := azureoidc.NewAzureConfigClient(params.SubscriptionID) + if err != nil { + return trace.Wrap(err) + } + return trace.Wrap(azureoidc.ConfigureAccessGraphSyncAzure(ctx, clt, confReq)) +} + func onIntegrationConfAzureOIDCCmd(ctx context.Context, params config.IntegrationConfAzureOIDC) 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 8318fcf68a45f..18a3981bca56a 100644 --- a/tool/teleport/common/teleport.go +++ b/tool/teleport/common/teleport.go @@ -508,10 +508,16 @@ func Run(options Options) (app *kingpin.Application, executedCommand string, con integrationConfEKSCmd.Flag("confirm", "Apply changes without confirmation prompt.").BoolVar(&ccf.IntegrationConfEKSIAMArguments.AutoConfirm) integrationConfAccessGraphCmd := integrationConfigureCmd.Command("access-graph", "Manages Access Graph configuration.") - integrationConfTAGSyncCmd := integrationConfAccessGraphCmd.Command("aws-iam", "Adds required IAM permissions for syncing data into Access Graph service.") - integrationConfTAGSyncCmd.Flag("role", "The AWS Role used by the AWS OIDC Integration.").Required().StringVar(&ccf.IntegrationConfAccessGraphAWSSyncArguments.Role) - integrationConfTAGSyncCmd.Flag("aws-account-id", "The AWS account ID.").StringVar(&ccf.IntegrationConfAccessGraphAWSSyncArguments.AccountID) - integrationConfTAGSyncCmd.Flag("confirm", "Apply changes without confirmation prompt.").BoolVar(&ccf.IntegrationConfAccessGraphAWSSyncArguments.AutoConfirm) + integrationConfAccessGraphAWSSyncCmd := integrationConfAccessGraphCmd.Command("aws-iam", "Adds required AWS IAM permissions for syncing AWS resources into Access Graph service.") + integrationConfAccessGraphAWSSyncCmd.Flag("role", "The AWS Role used by the AWS OIDC Integration.").Required().StringVar(&ccf.IntegrationConfAccessGraphAWSSyncArguments.Role) + integrationConfAccessGraphAWSSyncCmd.Flag("aws-account-id", "The AWS account ID.").StringVar(&ccf.IntegrationConfAccessGraphAWSSyncArguments.AccountID) + integrationConfAccessGraphAWSSyncCmd.Flag("confirm", "Apply changes without confirmation prompt.").BoolVar(&ccf.IntegrationConfAccessGraphAWSSyncArguments.AutoConfirm) + + integrationConfAccessGraphAzureSyncCmd := integrationConfAccessGraphCmd.Command("azure", "Adds required Azure permissions for syncing Azure resources into Access Graph service.") + integrationConfAccessGraphAzureSyncCmd.Flag("managed-identity", "The ID of the managed identity to run the Discovery service.").Required().StringVar(&ccf.IntegrationConfAccessGraphAzureSyncArguments.ManagedIdentity) + integrationConfAccessGraphAzureSyncCmd.Flag("role-name", "The name of the Azure Role to create and assign to the managed identity").Required().StringVar(&ccf.IntegrationConfAccessGraphAzureSyncArguments.RoleName) + integrationConfAccessGraphAzureSyncCmd.Flag("subscription-id", "The subscription ID in which to discovery resources.").StringVar(&ccf.IntegrationConfAccessGraphAzureSyncArguments.SubscriptionID) + integrationConfAccessGraphAzureSyncCmd.Flag("confirm", "Apply changes without confirmation prompt.").BoolVar(&ccf.IntegrationConfAccessGraphAzureSyncArguments.AutoConfirm) integrationConfAWSOIDCIdPCmd := integrationConfigureCmd.Command("awsoidc-idp", "Creates an IAM IdP (OIDC) in your AWS account to allow the AWS OIDC Integration to access AWS APIs.") integrationConfAWSOIDCIdPCmd.Flag("cluster", "Teleport Cluster name.").Required().StringVar(&ccf. @@ -721,8 +727,10 @@ Examples: err = onIntegrationConfListDatabasesIAM(ctx, ccf.IntegrationConfListDatabasesIAMArguments) case integrationConfExternalAuditCmd.FullCommand(): err = onIntegrationConfExternalAuditCmd(ctx, ccf.IntegrationConfExternalAuditStorageArguments) - case integrationConfTAGSyncCmd.FullCommand(): + case integrationConfAccessGraphAWSSyncCmd.FullCommand(): err = onIntegrationConfAccessGraphAWSSync(ctx, ccf.IntegrationConfAccessGraphAWSSyncArguments) + case integrationConfAccessGraphAzureSyncCmd.FullCommand(): + err = onIntegrationConfAccessGraphAzureSync(ctx, ccf.IntegrationConfAccessGraphAzureSyncArguments) case integrationConfAzureOIDCCmd.FullCommand(): err = onIntegrationConfAzureOIDCCmd(ctx, ccf.IntegrationConfAzureOIDCArguments) case integrationSAMLIdPGCPWorkforce.FullCommand():