diff --git a/api/client/accessmonitoringrules/access_monitoring_rules_client.go b/api/client/accessmonitoringrules/access_monitoring_rules_client.go index ee641bf9c2ead..fff91ceaf2f48 100644 --- a/api/client/accessmonitoringrules/access_monitoring_rules_client.go +++ b/api/client/accessmonitoringrules/access_monitoring_rules_client.go @@ -109,3 +109,17 @@ func (c *Client) ListAccessMonitoringRules(ctx context.Context, pageSize int, pa } return resp.Rules, resp.GetNextPageToken(), nil } + +// ListAccessMonitoringRulesWithFilter lists current access monitoring rules. +func (c *Client) ListAccessMonitoringRulesWithFilter(ctx context.Context, pageSize int, pageToken string, subjects []string, notificationName string) ([]*accessmonitoringrulesv1.AccessMonitoringRule, string, error) { + resp, err := c.grpcClient.ListAccessMonitoringRulesWithFilter(ctx, &accessmonitoringrulesv1.ListAccessMonitoringRulesWithFilterRequest{ + PageSize: int64(pageSize), + PageToken: pageToken, + Subjects: subjects, + NotificationName: notificationName, + }) + if err != nil { + return nil, "", trace.Wrap(err) + } + return resp.Rules, resp.GetNextPageToken(), nil +} diff --git a/api/gen/proto/go/teleport/accessmonitoringrules/v1/access_monitoring_rules.pb.go b/api/gen/proto/go/teleport/accessmonitoringrules/v1/access_monitoring_rules.pb.go index 66af7ada863ea..52e4d59e32fe2 100644 --- a/api/gen/proto/go/teleport/accessmonitoringrules/v1/access_monitoring_rules.pb.go +++ b/api/gen/proto/go/teleport/accessmonitoringrules/v1/access_monitoring_rules.pb.go @@ -500,7 +500,7 @@ func (x *DeleteAccessMonitoringRuleRequest) GetName() string { return "" } -// ListAccessMonitoringRulesResponse is the request for ListAccessMonitoringRules. +// ListAccessMonitoringRulesRequest is the request for ListAccessMonitoringRules. type ListAccessMonitoringRulesRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -559,6 +559,83 @@ func (x *ListAccessMonitoringRulesRequest) GetPageToken() string { return "" } +// ListAccessMonitoringRulesWithFilterRequest is the request for ListAccessMonitoringRulesWithFilter. +type ListAccessMonitoringRulesWithFilterRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // page_size is the maximum number of items to return. + // The server may impose a different page size at its discretion. + PageSize int64 `protobuf:"varint,1,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` + // page_token is the next_page_token value returned from a previous List request, if any. + PageToken string `protobuf:"bytes,2,opt,name=page_token,json=pageToken,proto3" json:"page_token,omitempty"` + // subjects are the subjects the access monitoring rules must have. This field is optional. + Subjects []string `protobuf:"bytes,3,rep,name=subjects,proto3" json:"subjects,omitempty"` + // notification_name is the value of the notification name field the rule must have. This field is optional. + NotificationName string `protobuf:"bytes,4,opt,name=notification_name,json=notificationName,proto3" json:"notification_name,omitempty"` +} + +func (x *ListAccessMonitoringRulesWithFilterRequest) Reset() { + *x = ListAccessMonitoringRulesWithFilterRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_teleport_accessmonitoringrules_v1_access_monitoring_rules_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListAccessMonitoringRulesWithFilterRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListAccessMonitoringRulesWithFilterRequest) ProtoMessage() {} + +func (x *ListAccessMonitoringRulesWithFilterRequest) ProtoReflect() protoreflect.Message { + mi := &file_teleport_accessmonitoringrules_v1_access_monitoring_rules_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListAccessMonitoringRulesWithFilterRequest.ProtoReflect.Descriptor instead. +func (*ListAccessMonitoringRulesWithFilterRequest) Descriptor() ([]byte, []int) { + return file_teleport_accessmonitoringrules_v1_access_monitoring_rules_proto_rawDescGZIP(), []int{9} +} + +func (x *ListAccessMonitoringRulesWithFilterRequest) GetPageSize() int64 { + if x != nil { + return x.PageSize + } + return 0 +} + +func (x *ListAccessMonitoringRulesWithFilterRequest) GetPageToken() string { + if x != nil { + return x.PageToken + } + return "" +} + +func (x *ListAccessMonitoringRulesWithFilterRequest) GetSubjects() []string { + if x != nil { + return x.Subjects + } + return nil +} + +func (x *ListAccessMonitoringRulesWithFilterRequest) GetNotificationName() string { + if x != nil { + return x.NotificationName + } + return "" +} + // ListAccessMonitoringRulesResponse is the response from ListAccessMonitoringRules. type ListAccessMonitoringRulesResponse struct { state protoimpl.MessageState @@ -575,7 +652,7 @@ type ListAccessMonitoringRulesResponse struct { func (x *ListAccessMonitoringRulesResponse) Reset() { *x = ListAccessMonitoringRulesResponse{} if protoimpl.UnsafeEnabled { - mi := &file_teleport_accessmonitoringrules_v1_access_monitoring_rules_proto_msgTypes[9] + mi := &file_teleport_accessmonitoringrules_v1_access_monitoring_rules_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -588,7 +665,7 @@ func (x *ListAccessMonitoringRulesResponse) String() string { func (*ListAccessMonitoringRulesResponse) ProtoMessage() {} func (x *ListAccessMonitoringRulesResponse) ProtoReflect() protoreflect.Message { - mi := &file_teleport_accessmonitoringrules_v1_access_monitoring_rules_proto_msgTypes[9] + mi := &file_teleport_accessmonitoringrules_v1_access_monitoring_rules_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -601,7 +678,7 @@ func (x *ListAccessMonitoringRulesResponse) ProtoReflect() protoreflect.Message // Deprecated: Use ListAccessMonitoringRulesResponse.ProtoReflect.Descriptor instead. func (*ListAccessMonitoringRulesResponse) Descriptor() ([]byte, []int) { - return file_teleport_accessmonitoringrules_v1_access_monitoring_rules_proto_rawDescGZIP(), []int{9} + return file_teleport_accessmonitoringrules_v1_access_monitoring_rules_proto_rawDescGZIP(), []int{10} } func (x *ListAccessMonitoringRulesResponse) GetRules() []*AccessMonitoringRule { @@ -618,6 +695,65 @@ func (x *ListAccessMonitoringRulesResponse) GetNextPageToken() string { return "" } +// ListAccessMonitoringRulesWithFilterResponse is the response from ListAccessMonitoringRulesWithFilter. +type ListAccessMonitoringRulesWithFilterResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The page of AccessMonitoringRule that matched the request. + Rules []*AccessMonitoringRule `protobuf:"bytes,1,rep,name=rules,proto3" json:"rules,omitempty"` + // Token to retrieve the next page of results, or empty if there are no + // more results in the list. + NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"` +} + +func (x *ListAccessMonitoringRulesWithFilterResponse) Reset() { + *x = ListAccessMonitoringRulesWithFilterResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_teleport_accessmonitoringrules_v1_access_monitoring_rules_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListAccessMonitoringRulesWithFilterResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListAccessMonitoringRulesWithFilterResponse) ProtoMessage() {} + +func (x *ListAccessMonitoringRulesWithFilterResponse) ProtoReflect() protoreflect.Message { + mi := &file_teleport_accessmonitoringrules_v1_access_monitoring_rules_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListAccessMonitoringRulesWithFilterResponse.ProtoReflect.Descriptor instead. +func (*ListAccessMonitoringRulesWithFilterResponse) Descriptor() ([]byte, []int) { + return file_teleport_accessmonitoringrules_v1_access_monitoring_rules_proto_rawDescGZIP(), []int{11} +} + +func (x *ListAccessMonitoringRulesWithFilterResponse) GetRules() []*AccessMonitoringRule { + if x != nil { + return x.Rules + } + return nil +} + +func (x *ListAccessMonitoringRulesWithFilterResponse) GetNextPageToken() string { + if x != nil { + return x.NextPageToken + } + return "" +} + var File_teleport_accessmonitoringrules_v1_access_monitoring_rules_proto protoreflect.FileDescriptor var file_teleport_accessmonitoringrules_v1_access_monitoring_rules_proto_rawDesc = []byte{ @@ -695,24 +831,46 @@ var file_teleport_accessmonitoringrules_v1_access_monitoring_rules_proto_rawDesc 0x7a, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, - 0x6e, 0x22, 0x9a, 0x01, 0x0a, 0x21, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, - 0x74, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, - 0x6e, 0x67, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x52, - 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, - 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x6e, - 0x5a, 0x6c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, - 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, - 0x6f, 0x72, 0x74, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x61, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x72, 0x75, - 0x6c, 0x65, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6d, 0x6f, 0x6e, - 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x76, 0x31, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6e, 0x22, 0xb1, 0x01, 0x0a, 0x2a, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x57, + 0x69, 0x74, 0x68, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1d, 0x0a, + 0x0a, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x70, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1a, 0x0a, 0x08, + 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, + 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x6e, 0x6f, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x10, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x9a, 0x01, 0x0a, 0x21, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x75, + 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x05, 0x72, + 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x74, 0x65, 0x6c, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6d, 0x6f, 0x6e, 0x69, + 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x52, + 0x75, 0x6c, 0x65, 0x52, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, + 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x22, 0xa4, 0x01, 0x0a, 0x2b, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x73, + 0x57, 0x69, 0x74, 0x68, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x37, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x72, 0x75, 0x6c, + 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4d, 0x6f, 0x6e, 0x69, + 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x05, 0x72, 0x75, 0x6c, 0x65, + 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, + 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, + 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x6e, 0x5a, 0x6c, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x61, + 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, + 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6d, + 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x2f, 0x76, + 0x31, 0x3b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, + 0x6e, 0x67, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( @@ -727,33 +885,36 @@ func file_teleport_accessmonitoringrules_v1_access_monitoring_rules_proto_rawDes return file_teleport_accessmonitoringrules_v1_access_monitoring_rules_proto_rawDescData } -var file_teleport_accessmonitoringrules_v1_access_monitoring_rules_proto_msgTypes = make([]protoimpl.MessageInfo, 10) +var file_teleport_accessmonitoringrules_v1_access_monitoring_rules_proto_msgTypes = make([]protoimpl.MessageInfo, 12) var file_teleport_accessmonitoringrules_v1_access_monitoring_rules_proto_goTypes = []interface{}{ - (*AccessMonitoringRule)(nil), // 0: teleport.accessmonitoringrules.v1.AccessMonitoringRule - (*AccessMonitoringRuleSpec)(nil), // 1: teleport.accessmonitoringrules.v1.AccessMonitoringRuleSpec - (*Notification)(nil), // 2: teleport.accessmonitoringrules.v1.Notification - (*CreateAccessMonitoringRuleRequest)(nil), // 3: teleport.accessmonitoringrules.v1.CreateAccessMonitoringRuleRequest - (*UpdateAccessMonitoringRuleRequest)(nil), // 4: teleport.accessmonitoringrules.v1.UpdateAccessMonitoringRuleRequest - (*UpsertAccessMonitoringRuleRequest)(nil), // 5: teleport.accessmonitoringrules.v1.UpsertAccessMonitoringRuleRequest - (*GetAccessMonitoringRuleRequest)(nil), // 6: teleport.accessmonitoringrules.v1.GetAccessMonitoringRuleRequest - (*DeleteAccessMonitoringRuleRequest)(nil), // 7: teleport.accessmonitoringrules.v1.DeleteAccessMonitoringRuleRequest - (*ListAccessMonitoringRulesRequest)(nil), // 8: teleport.accessmonitoringrules.v1.ListAccessMonitoringRulesRequest - (*ListAccessMonitoringRulesResponse)(nil), // 9: teleport.accessmonitoringrules.v1.ListAccessMonitoringRulesResponse - (*v1.Metadata)(nil), // 10: teleport.header.v1.Metadata + (*AccessMonitoringRule)(nil), // 0: teleport.accessmonitoringrules.v1.AccessMonitoringRule + (*AccessMonitoringRuleSpec)(nil), // 1: teleport.accessmonitoringrules.v1.AccessMonitoringRuleSpec + (*Notification)(nil), // 2: teleport.accessmonitoringrules.v1.Notification + (*CreateAccessMonitoringRuleRequest)(nil), // 3: teleport.accessmonitoringrules.v1.CreateAccessMonitoringRuleRequest + (*UpdateAccessMonitoringRuleRequest)(nil), // 4: teleport.accessmonitoringrules.v1.UpdateAccessMonitoringRuleRequest + (*UpsertAccessMonitoringRuleRequest)(nil), // 5: teleport.accessmonitoringrules.v1.UpsertAccessMonitoringRuleRequest + (*GetAccessMonitoringRuleRequest)(nil), // 6: teleport.accessmonitoringrules.v1.GetAccessMonitoringRuleRequest + (*DeleteAccessMonitoringRuleRequest)(nil), // 7: teleport.accessmonitoringrules.v1.DeleteAccessMonitoringRuleRequest + (*ListAccessMonitoringRulesRequest)(nil), // 8: teleport.accessmonitoringrules.v1.ListAccessMonitoringRulesRequest + (*ListAccessMonitoringRulesWithFilterRequest)(nil), // 9: teleport.accessmonitoringrules.v1.ListAccessMonitoringRulesWithFilterRequest + (*ListAccessMonitoringRulesResponse)(nil), // 10: teleport.accessmonitoringrules.v1.ListAccessMonitoringRulesResponse + (*ListAccessMonitoringRulesWithFilterResponse)(nil), // 11: teleport.accessmonitoringrules.v1.ListAccessMonitoringRulesWithFilterResponse + (*v1.Metadata)(nil), // 12: teleport.header.v1.Metadata } var file_teleport_accessmonitoringrules_v1_access_monitoring_rules_proto_depIdxs = []int32{ - 10, // 0: teleport.accessmonitoringrules.v1.AccessMonitoringRule.metadata:type_name -> teleport.header.v1.Metadata + 12, // 0: teleport.accessmonitoringrules.v1.AccessMonitoringRule.metadata:type_name -> teleport.header.v1.Metadata 1, // 1: teleport.accessmonitoringrules.v1.AccessMonitoringRule.spec:type_name -> teleport.accessmonitoringrules.v1.AccessMonitoringRuleSpec 2, // 2: teleport.accessmonitoringrules.v1.AccessMonitoringRuleSpec.notification:type_name -> teleport.accessmonitoringrules.v1.Notification 0, // 3: teleport.accessmonitoringrules.v1.CreateAccessMonitoringRuleRequest.rule:type_name -> teleport.accessmonitoringrules.v1.AccessMonitoringRule 0, // 4: teleport.accessmonitoringrules.v1.UpdateAccessMonitoringRuleRequest.rule:type_name -> teleport.accessmonitoringrules.v1.AccessMonitoringRule 0, // 5: teleport.accessmonitoringrules.v1.UpsertAccessMonitoringRuleRequest.rule:type_name -> teleport.accessmonitoringrules.v1.AccessMonitoringRule 0, // 6: teleport.accessmonitoringrules.v1.ListAccessMonitoringRulesResponse.rules:type_name -> teleport.accessmonitoringrules.v1.AccessMonitoringRule - 7, // [7:7] is the sub-list for method output_type - 7, // [7:7] is the sub-list for method input_type - 7, // [7:7] is the sub-list for extension type_name - 7, // [7:7] is the sub-list for extension extendee - 0, // [0:7] is the sub-list for field type_name + 0, // 7: teleport.accessmonitoringrules.v1.ListAccessMonitoringRulesWithFilterResponse.rules:type_name -> teleport.accessmonitoringrules.v1.AccessMonitoringRule + 8, // [8:8] is the sub-list for method output_type + 8, // [8:8] is the sub-list for method input_type + 8, // [8:8] is the sub-list for extension type_name + 8, // [8:8] is the sub-list for extension extendee + 0, // [0:8] is the sub-list for field type_name } func init() { file_teleport_accessmonitoringrules_v1_access_monitoring_rules_proto_init() } @@ -871,6 +1032,18 @@ func file_teleport_accessmonitoringrules_v1_access_monitoring_rules_proto_init() } } file_teleport_accessmonitoringrules_v1_access_monitoring_rules_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListAccessMonitoringRulesWithFilterRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_teleport_accessmonitoringrules_v1_access_monitoring_rules_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ListAccessMonitoringRulesResponse); i { case 0: return &v.state @@ -882,6 +1055,18 @@ func file_teleport_accessmonitoringrules_v1_access_monitoring_rules_proto_init() return nil } } + file_teleport_accessmonitoringrules_v1_access_monitoring_rules_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListAccessMonitoringRulesWithFilterResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -889,7 +1074,7 @@ func file_teleport_accessmonitoringrules_v1_access_monitoring_rules_proto_init() GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_teleport_accessmonitoringrules_v1_access_monitoring_rules_proto_rawDesc, NumEnums: 0, - NumMessages: 10, + NumMessages: 12, NumExtensions: 0, NumServices: 0, }, diff --git a/api/gen/proto/go/teleport/accessmonitoringrules/v1/access_monitoring_rules_service.pb.go b/api/gen/proto/go/teleport/accessmonitoringrules/v1/access_monitoring_rules_service.pb.go index 07442dcb492a3..636b1cf7059e0 100644 --- a/api/gen/proto/go/teleport/accessmonitoringrules/v1/access_monitoring_rules_service.pb.go +++ b/api/gen/proto/go/teleport/accessmonitoringrules/v1/access_monitoring_rules_service.pb.go @@ -49,7 +49,7 @@ var file_teleport_accessmonitoringrules_v1_access_monitoring_rules_service_proto 0x6f, 0x72, 0x74, 0x2f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x72, - 0x75, 0x6c, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0xb5, 0x07, 0x0a, 0x1c, 0x41, + 0x75, 0x6c, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0xfc, 0x08, 0x0a, 0x1c, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x9b, 0x01, 0x0a, 0x1a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4d, 0x6f, 0x6e, 0x69, @@ -109,45 +109,62 @@ var file_teleport_accessmonitoringrules_v1_access_monitoring_rules_service_proto 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x42, 0x6e, 0x5a, 0x6c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, - 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, - 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, - 0x74, 0x2f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, - 0x6e, 0x67, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x61, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x72, 0x75, 0x6c, 0x65, 0x73, - 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x65, 0x12, 0xc4, 0x01, 0x0a, 0x23, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x73, + 0x57, 0x69, 0x74, 0x68, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x4d, 0x2e, 0x74, 0x65, 0x6c, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6d, 0x6f, 0x6e, 0x69, + 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, + 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x57, 0x69, 0x74, 0x68, 0x46, 0x69, 0x6c, 0x74, + 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x4e, 0x2e, 0x74, 0x65, 0x6c, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6d, 0x6f, 0x6e, 0x69, 0x74, + 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, + 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x57, 0x69, 0x74, 0x68, 0x46, 0x69, 0x6c, 0x74, 0x65, + 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x6e, 0x5a, 0x6c, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x61, + 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, + 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6d, + 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x2f, 0x76, + 0x31, 0x3b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, + 0x6e, 0x67, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var file_teleport_accessmonitoringrules_v1_access_monitoring_rules_service_proto_goTypes = []interface{}{ - (*CreateAccessMonitoringRuleRequest)(nil), // 0: teleport.accessmonitoringrules.v1.CreateAccessMonitoringRuleRequest - (*UpdateAccessMonitoringRuleRequest)(nil), // 1: teleport.accessmonitoringrules.v1.UpdateAccessMonitoringRuleRequest - (*UpsertAccessMonitoringRuleRequest)(nil), // 2: teleport.accessmonitoringrules.v1.UpsertAccessMonitoringRuleRequest - (*GetAccessMonitoringRuleRequest)(nil), // 3: teleport.accessmonitoringrules.v1.GetAccessMonitoringRuleRequest - (*DeleteAccessMonitoringRuleRequest)(nil), // 4: teleport.accessmonitoringrules.v1.DeleteAccessMonitoringRuleRequest - (*ListAccessMonitoringRulesRequest)(nil), // 5: teleport.accessmonitoringrules.v1.ListAccessMonitoringRulesRequest - (*AccessMonitoringRule)(nil), // 6: teleport.accessmonitoringrules.v1.AccessMonitoringRule - (*emptypb.Empty)(nil), // 7: google.protobuf.Empty - (*ListAccessMonitoringRulesResponse)(nil), // 8: teleport.accessmonitoringrules.v1.ListAccessMonitoringRulesResponse + (*CreateAccessMonitoringRuleRequest)(nil), // 0: teleport.accessmonitoringrules.v1.CreateAccessMonitoringRuleRequest + (*UpdateAccessMonitoringRuleRequest)(nil), // 1: teleport.accessmonitoringrules.v1.UpdateAccessMonitoringRuleRequest + (*UpsertAccessMonitoringRuleRequest)(nil), // 2: teleport.accessmonitoringrules.v1.UpsertAccessMonitoringRuleRequest + (*GetAccessMonitoringRuleRequest)(nil), // 3: teleport.accessmonitoringrules.v1.GetAccessMonitoringRuleRequest + (*DeleteAccessMonitoringRuleRequest)(nil), // 4: teleport.accessmonitoringrules.v1.DeleteAccessMonitoringRuleRequest + (*ListAccessMonitoringRulesRequest)(nil), // 5: teleport.accessmonitoringrules.v1.ListAccessMonitoringRulesRequest + (*ListAccessMonitoringRulesWithFilterRequest)(nil), // 6: teleport.accessmonitoringrules.v1.ListAccessMonitoringRulesWithFilterRequest + (*AccessMonitoringRule)(nil), // 7: teleport.accessmonitoringrules.v1.AccessMonitoringRule + (*emptypb.Empty)(nil), // 8: google.protobuf.Empty + (*ListAccessMonitoringRulesResponse)(nil), // 9: teleport.accessmonitoringrules.v1.ListAccessMonitoringRulesResponse + (*ListAccessMonitoringRulesWithFilterResponse)(nil), // 10: teleport.accessmonitoringrules.v1.ListAccessMonitoringRulesWithFilterResponse } var file_teleport_accessmonitoringrules_v1_access_monitoring_rules_service_proto_depIdxs = []int32{ - 0, // 0: teleport.accessmonitoringrules.v1.AccessMonitoringRulesService.CreateAccessMonitoringRule:input_type -> teleport.accessmonitoringrules.v1.CreateAccessMonitoringRuleRequest - 1, // 1: teleport.accessmonitoringrules.v1.AccessMonitoringRulesService.UpdateAccessMonitoringRule:input_type -> teleport.accessmonitoringrules.v1.UpdateAccessMonitoringRuleRequest - 2, // 2: teleport.accessmonitoringrules.v1.AccessMonitoringRulesService.UpsertAccessMonitoringRule:input_type -> teleport.accessmonitoringrules.v1.UpsertAccessMonitoringRuleRequest - 3, // 3: teleport.accessmonitoringrules.v1.AccessMonitoringRulesService.GetAccessMonitoringRule:input_type -> teleport.accessmonitoringrules.v1.GetAccessMonitoringRuleRequest - 4, // 4: teleport.accessmonitoringrules.v1.AccessMonitoringRulesService.DeleteAccessMonitoringRule:input_type -> teleport.accessmonitoringrules.v1.DeleteAccessMonitoringRuleRequest - 5, // 5: teleport.accessmonitoringrules.v1.AccessMonitoringRulesService.ListAccessMonitoringRules:input_type -> teleport.accessmonitoringrules.v1.ListAccessMonitoringRulesRequest - 6, // 6: teleport.accessmonitoringrules.v1.AccessMonitoringRulesService.CreateAccessMonitoringRule:output_type -> teleport.accessmonitoringrules.v1.AccessMonitoringRule - 6, // 7: teleport.accessmonitoringrules.v1.AccessMonitoringRulesService.UpdateAccessMonitoringRule:output_type -> teleport.accessmonitoringrules.v1.AccessMonitoringRule - 6, // 8: teleport.accessmonitoringrules.v1.AccessMonitoringRulesService.UpsertAccessMonitoringRule:output_type -> teleport.accessmonitoringrules.v1.AccessMonitoringRule - 6, // 9: teleport.accessmonitoringrules.v1.AccessMonitoringRulesService.GetAccessMonitoringRule:output_type -> teleport.accessmonitoringrules.v1.AccessMonitoringRule - 7, // 10: teleport.accessmonitoringrules.v1.AccessMonitoringRulesService.DeleteAccessMonitoringRule:output_type -> google.protobuf.Empty - 8, // 11: teleport.accessmonitoringrules.v1.AccessMonitoringRulesService.ListAccessMonitoringRules:output_type -> teleport.accessmonitoringrules.v1.ListAccessMonitoringRulesResponse - 6, // [6:12] is the sub-list for method output_type - 0, // [0:6] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name + 0, // 0: teleport.accessmonitoringrules.v1.AccessMonitoringRulesService.CreateAccessMonitoringRule:input_type -> teleport.accessmonitoringrules.v1.CreateAccessMonitoringRuleRequest + 1, // 1: teleport.accessmonitoringrules.v1.AccessMonitoringRulesService.UpdateAccessMonitoringRule:input_type -> teleport.accessmonitoringrules.v1.UpdateAccessMonitoringRuleRequest + 2, // 2: teleport.accessmonitoringrules.v1.AccessMonitoringRulesService.UpsertAccessMonitoringRule:input_type -> teleport.accessmonitoringrules.v1.UpsertAccessMonitoringRuleRequest + 3, // 3: teleport.accessmonitoringrules.v1.AccessMonitoringRulesService.GetAccessMonitoringRule:input_type -> teleport.accessmonitoringrules.v1.GetAccessMonitoringRuleRequest + 4, // 4: teleport.accessmonitoringrules.v1.AccessMonitoringRulesService.DeleteAccessMonitoringRule:input_type -> teleport.accessmonitoringrules.v1.DeleteAccessMonitoringRuleRequest + 5, // 5: teleport.accessmonitoringrules.v1.AccessMonitoringRulesService.ListAccessMonitoringRules:input_type -> teleport.accessmonitoringrules.v1.ListAccessMonitoringRulesRequest + 6, // 6: teleport.accessmonitoringrules.v1.AccessMonitoringRulesService.ListAccessMonitoringRulesWithFilter:input_type -> teleport.accessmonitoringrules.v1.ListAccessMonitoringRulesWithFilterRequest + 7, // 7: teleport.accessmonitoringrules.v1.AccessMonitoringRulesService.CreateAccessMonitoringRule:output_type -> teleport.accessmonitoringrules.v1.AccessMonitoringRule + 7, // 8: teleport.accessmonitoringrules.v1.AccessMonitoringRulesService.UpdateAccessMonitoringRule:output_type -> teleport.accessmonitoringrules.v1.AccessMonitoringRule + 7, // 9: teleport.accessmonitoringrules.v1.AccessMonitoringRulesService.UpsertAccessMonitoringRule:output_type -> teleport.accessmonitoringrules.v1.AccessMonitoringRule + 7, // 10: teleport.accessmonitoringrules.v1.AccessMonitoringRulesService.GetAccessMonitoringRule:output_type -> teleport.accessmonitoringrules.v1.AccessMonitoringRule + 8, // 11: teleport.accessmonitoringrules.v1.AccessMonitoringRulesService.DeleteAccessMonitoringRule:output_type -> google.protobuf.Empty + 9, // 12: teleport.accessmonitoringrules.v1.AccessMonitoringRulesService.ListAccessMonitoringRules:output_type -> teleport.accessmonitoringrules.v1.ListAccessMonitoringRulesResponse + 10, // 13: teleport.accessmonitoringrules.v1.AccessMonitoringRulesService.ListAccessMonitoringRulesWithFilter:output_type -> teleport.accessmonitoringrules.v1.ListAccessMonitoringRulesWithFilterResponse + 7, // [7:14] is the sub-list for method output_type + 0, // [0:7] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name } func init() { file_teleport_accessmonitoringrules_v1_access_monitoring_rules_service_proto_init() } diff --git a/api/gen/proto/go/teleport/accessmonitoringrules/v1/access_monitoring_rules_service_grpc.pb.go b/api/gen/proto/go/teleport/accessmonitoringrules/v1/access_monitoring_rules_service_grpc.pb.go index 3c3216510001b..896483a6e85b1 100644 --- a/api/gen/proto/go/teleport/accessmonitoringrules/v1/access_monitoring_rules_service_grpc.pb.go +++ b/api/gen/proto/go/teleport/accessmonitoringrules/v1/access_monitoring_rules_service_grpc.pb.go @@ -34,12 +34,13 @@ import ( const _ = grpc.SupportPackageIsVersion7 const ( - AccessMonitoringRulesService_CreateAccessMonitoringRule_FullMethodName = "/teleport.accessmonitoringrules.v1.AccessMonitoringRulesService/CreateAccessMonitoringRule" - AccessMonitoringRulesService_UpdateAccessMonitoringRule_FullMethodName = "/teleport.accessmonitoringrules.v1.AccessMonitoringRulesService/UpdateAccessMonitoringRule" - AccessMonitoringRulesService_UpsertAccessMonitoringRule_FullMethodName = "/teleport.accessmonitoringrules.v1.AccessMonitoringRulesService/UpsertAccessMonitoringRule" - AccessMonitoringRulesService_GetAccessMonitoringRule_FullMethodName = "/teleport.accessmonitoringrules.v1.AccessMonitoringRulesService/GetAccessMonitoringRule" - AccessMonitoringRulesService_DeleteAccessMonitoringRule_FullMethodName = "/teleport.accessmonitoringrules.v1.AccessMonitoringRulesService/DeleteAccessMonitoringRule" - AccessMonitoringRulesService_ListAccessMonitoringRules_FullMethodName = "/teleport.accessmonitoringrules.v1.AccessMonitoringRulesService/ListAccessMonitoringRules" + AccessMonitoringRulesService_CreateAccessMonitoringRule_FullMethodName = "/teleport.accessmonitoringrules.v1.AccessMonitoringRulesService/CreateAccessMonitoringRule" + AccessMonitoringRulesService_UpdateAccessMonitoringRule_FullMethodName = "/teleport.accessmonitoringrules.v1.AccessMonitoringRulesService/UpdateAccessMonitoringRule" + AccessMonitoringRulesService_UpsertAccessMonitoringRule_FullMethodName = "/teleport.accessmonitoringrules.v1.AccessMonitoringRulesService/UpsertAccessMonitoringRule" + AccessMonitoringRulesService_GetAccessMonitoringRule_FullMethodName = "/teleport.accessmonitoringrules.v1.AccessMonitoringRulesService/GetAccessMonitoringRule" + AccessMonitoringRulesService_DeleteAccessMonitoringRule_FullMethodName = "/teleport.accessmonitoringrules.v1.AccessMonitoringRulesService/DeleteAccessMonitoringRule" + AccessMonitoringRulesService_ListAccessMonitoringRules_FullMethodName = "/teleport.accessmonitoringrules.v1.AccessMonitoringRulesService/ListAccessMonitoringRules" + AccessMonitoringRulesService_ListAccessMonitoringRulesWithFilter_FullMethodName = "/teleport.accessmonitoringrules.v1.AccessMonitoringRulesService/ListAccessMonitoringRulesWithFilter" ) // AccessMonitoringRulesServiceClient is the client API for AccessMonitoringRulesService service. @@ -58,6 +59,8 @@ type AccessMonitoringRulesServiceClient interface { DeleteAccessMonitoringRule(ctx context.Context, in *DeleteAccessMonitoringRuleRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) // ListAccessMonitoringRules lists current access monitoring rules. ListAccessMonitoringRules(ctx context.Context, in *ListAccessMonitoringRulesRequest, opts ...grpc.CallOption) (*ListAccessMonitoringRulesResponse, error) + // ListAccessMonitoringRulesWithFilter lists current access monitoring rules that match the provided filter. + ListAccessMonitoringRulesWithFilter(ctx context.Context, in *ListAccessMonitoringRulesWithFilterRequest, opts ...grpc.CallOption) (*ListAccessMonitoringRulesWithFilterResponse, error) } type accessMonitoringRulesServiceClient struct { @@ -122,6 +125,15 @@ func (c *accessMonitoringRulesServiceClient) ListAccessMonitoringRules(ctx conte return out, nil } +func (c *accessMonitoringRulesServiceClient) ListAccessMonitoringRulesWithFilter(ctx context.Context, in *ListAccessMonitoringRulesWithFilterRequest, opts ...grpc.CallOption) (*ListAccessMonitoringRulesWithFilterResponse, error) { + out := new(ListAccessMonitoringRulesWithFilterResponse) + err := c.cc.Invoke(ctx, AccessMonitoringRulesService_ListAccessMonitoringRulesWithFilter_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // AccessMonitoringRulesServiceServer is the server API for AccessMonitoringRulesService service. // All implementations must embed UnimplementedAccessMonitoringRulesServiceServer // for forward compatibility @@ -138,6 +150,8 @@ type AccessMonitoringRulesServiceServer interface { DeleteAccessMonitoringRule(context.Context, *DeleteAccessMonitoringRuleRequest) (*emptypb.Empty, error) // ListAccessMonitoringRules lists current access monitoring rules. ListAccessMonitoringRules(context.Context, *ListAccessMonitoringRulesRequest) (*ListAccessMonitoringRulesResponse, error) + // ListAccessMonitoringRulesWithFilter lists current access monitoring rules that match the provided filter. + ListAccessMonitoringRulesWithFilter(context.Context, *ListAccessMonitoringRulesWithFilterRequest) (*ListAccessMonitoringRulesWithFilterResponse, error) mustEmbedUnimplementedAccessMonitoringRulesServiceServer() } @@ -163,6 +177,9 @@ func (UnimplementedAccessMonitoringRulesServiceServer) DeleteAccessMonitoringRul func (UnimplementedAccessMonitoringRulesServiceServer) ListAccessMonitoringRules(context.Context, *ListAccessMonitoringRulesRequest) (*ListAccessMonitoringRulesResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ListAccessMonitoringRules not implemented") } +func (UnimplementedAccessMonitoringRulesServiceServer) ListAccessMonitoringRulesWithFilter(context.Context, *ListAccessMonitoringRulesWithFilterRequest) (*ListAccessMonitoringRulesWithFilterResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListAccessMonitoringRulesWithFilter not implemented") +} func (UnimplementedAccessMonitoringRulesServiceServer) mustEmbedUnimplementedAccessMonitoringRulesServiceServer() { } @@ -285,6 +302,24 @@ func _AccessMonitoringRulesService_ListAccessMonitoringRules_Handler(srv interfa return interceptor(ctx, in, info, handler) } +func _AccessMonitoringRulesService_ListAccessMonitoringRulesWithFilter_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListAccessMonitoringRulesWithFilterRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AccessMonitoringRulesServiceServer).ListAccessMonitoringRulesWithFilter(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AccessMonitoringRulesService_ListAccessMonitoringRulesWithFilter_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AccessMonitoringRulesServiceServer).ListAccessMonitoringRulesWithFilter(ctx, req.(*ListAccessMonitoringRulesWithFilterRequest)) + } + return interceptor(ctx, in, info, handler) +} + // AccessMonitoringRulesService_ServiceDesc is the grpc.ServiceDesc for AccessMonitoringRulesService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -316,6 +351,10 @@ var AccessMonitoringRulesService_ServiceDesc = grpc.ServiceDesc{ MethodName: "ListAccessMonitoringRules", Handler: _AccessMonitoringRulesService_ListAccessMonitoringRules_Handler, }, + { + MethodName: "ListAccessMonitoringRulesWithFilter", + Handler: _AccessMonitoringRulesService_ListAccessMonitoringRulesWithFilter_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "teleport/accessmonitoringrules/v1/access_monitoring_rules_service.proto", diff --git a/api/proto/teleport/accessmonitoringrules/v1/access_monitoring_rules.proto b/api/proto/teleport/accessmonitoringrules/v1/access_monitoring_rules.proto index 1b4e101ce849c..6b385a9f42eaf 100644 --- a/api/proto/teleport/accessmonitoringrules/v1/access_monitoring_rules.proto +++ b/api/proto/teleport/accessmonitoringrules/v1/access_monitoring_rules.proto @@ -85,7 +85,7 @@ message DeleteAccessMonitoringRuleRequest { string name = 1; } -// ListAccessMonitoringRulesResponse is the request for ListAccessMonitoringRules. +// ListAccessMonitoringRulesRequest is the request for ListAccessMonitoringRules. message ListAccessMonitoringRulesRequest { // page_size is the maximum number of items to return. // The server may impose a different page size at its discretion. @@ -94,6 +94,19 @@ message ListAccessMonitoringRulesRequest { string page_token = 2; } +// ListAccessMonitoringRulesWithFilterRequest is the request for ListAccessMonitoringRulesWithFilter. +message ListAccessMonitoringRulesWithFilterRequest { + // page_size is the maximum number of items to return. + // The server may impose a different page size at its discretion. + int64 page_size = 1; + // page_token is the next_page_token value returned from a previous List request, if any. + string page_token = 2; + // subjects are the subjects the access monitoring rules must have. This field is optional. + repeated string subjects = 3; + // notification_name is the value of the notification name field the rule must have. This field is optional. + string notification_name = 4; +} + // ListAccessMonitoringRulesResponse is the response from ListAccessMonitoringRules. message ListAccessMonitoringRulesResponse { // The page of AccessMonitoringRule that matched the request. @@ -102,3 +115,12 @@ message ListAccessMonitoringRulesResponse { // more results in the list. string next_page_token = 2; } + +// ListAccessMonitoringRulesWithFilterResponse is the response from ListAccessMonitoringRulesWithFilter. +message ListAccessMonitoringRulesWithFilterResponse { + // The page of AccessMonitoringRule that matched the request. + repeated AccessMonitoringRule rules = 1; + // Token to retrieve the next page of results, or empty if there are no + // more results in the list. + string next_page_token = 2; +} diff --git a/api/proto/teleport/accessmonitoringrules/v1/access_monitoring_rules_service.proto b/api/proto/teleport/accessmonitoringrules/v1/access_monitoring_rules_service.proto index 55ee27692cadf..6025d31796ccb 100644 --- a/api/proto/teleport/accessmonitoringrules/v1/access_monitoring_rules_service.proto +++ b/api/proto/teleport/accessmonitoringrules/v1/access_monitoring_rules_service.proto @@ -40,4 +40,7 @@ service AccessMonitoringRulesService { // ListAccessMonitoringRules lists current access monitoring rules. rpc ListAccessMonitoringRules(ListAccessMonitoringRulesRequest) returns (ListAccessMonitoringRulesResponse); + + // ListAccessMonitoringRulesWithFilter lists current access monitoring rules that match the provided filter. + rpc ListAccessMonitoringRulesWithFilter(ListAccessMonitoringRulesWithFilterRequest) returns (ListAccessMonitoringRulesWithFilterResponse); } diff --git a/integrations/access/accessrequest/app.go b/integrations/access/accessrequest/app.go index cca57b2d12423..d6b430279384c 100644 --- a/integrations/access/accessrequest/app.go +++ b/integrations/access/accessrequest/app.go @@ -21,11 +21,15 @@ package accessrequest import ( "context" "fmt" + "maps" + "slices" + "sync" "time" "github.com/gravitational/trace" "github.com/gravitational/teleport/api/accessrequest" + accessmonitoringrulesv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/accessmonitoringrules/v1" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/integrations/access/common" "github.com/gravitational/teleport/integrations/access/common/teleport" @@ -38,6 +42,8 @@ import ( const ( // handlerTimeout is used to bound the execution time of watcher event handler. handlerTimeout = time.Second * 5 + // defaultAccessMonitoringRulePageSize is the default number of rules to retrieve per request + defaultAccessMonitoringRulePageSize = 10 ) // App is the access request application for plugins. This will notify when access requests @@ -50,11 +56,20 @@ type App struct { pluginData *pd.CompareAndSwap[PluginData] bot MessagingBot job lib.ServiceJob + + accessMonitoringRules amrMap +} + +type amrMap struct { + sync.RWMutex + rules map[string]*accessmonitoringrulesv1.AccessMonitoringRule } // NewApp will create a new access request application. func NewApp(bot MessagingBot) common.App { - app := &App{} + app := &App{accessMonitoringRules: amrMap{ + rules: make(map[string]*accessmonitoringrulesv1.AccessMonitoringRule), + }} app.job = lib.NewServiceJob(app.run) return app } @@ -111,7 +126,10 @@ func (a *App) run(ctx context.Context) error { job, err := watcherjob.NewJob( a.apiClient, watcherjob.Config{ - Watch: types.Watch{Kinds: []types.WatchKind{{Kind: types.KindAccessRequest}}}, + Watch: types.Watch{Kinds: []types.WatchKind{ + {Kind: types.KindAccessRequest}, + {Kind: types.KindAccessMonitoringRule}, + }}, EventFuncTimeout: handlerTimeout, }, a.onWatcherEvent, @@ -127,6 +145,10 @@ func (a *App) run(ctx context.Context) error { return trace.Wrap(err) } + if err := a.initAccessMonitoringRulesCache(ctx); err != nil { + return trace.Wrap(err) + } + a.job.SetReady(ok) if !ok { return trace.BadParameter("job not ready") @@ -136,12 +158,28 @@ func (a *App) run(ctx context.Context) error { return nil } +func (a *App) amrAppliesToThisPlugin(amr *accessmonitoringrulesv1.AccessMonitoringRule) bool { + if amr.Spec.Notification.Name != a.pluginName { + return false + } + return slices.ContainsFunc(amr.Spec.Subjects, func(subject string) bool { + return subject == types.KindAccessRequest + }) +} + // onWatcherEvent is called for every cluster Event. It will filter out non-access-request events and // call onPendingRequest, onResolvedRequest and on DeletedRequest depending on the event. func (a *App) onWatcherEvent(ctx context.Context, event types.Event) error { - if kind := event.Resource.GetKind(); kind != types.KindAccessRequest { - return trace.Errorf("unexpected kind %s", kind) + switch event.Resource.GetKind() { + case types.KindAccessMonitoringRule: + return trace.Wrap(a.handleAccessMonitoringRule(ctx, event)) + case types.KindAccessRequest: + return trace.Wrap(a.handleAcessRequest(ctx, event)) } + return trace.BadParameter("unexpected kind %s", event.Resource.GetKind()) +} + +func (a *App) handleAcessRequest(ctx context.Context, event types.Event) error { op := event.Type reqID := event.Resource.GetName() ctx, _ = logger.WithField(ctx, "request_id", reqID) @@ -151,7 +189,7 @@ func (a *App) onWatcherEvent(ctx context.Context, event types.Event) error { ctx, _ = logger.WithField(ctx, "request_op", "put") req, ok := event.Resource.(types.AccessRequest) if !ok { - return trace.Errorf("unexpected resource type %T", event.Resource) + return trace.BadParameter("unexpected resource type %T", event.Resource) } ctx, log := logger.WithField(ctx, "request_state", req.GetState().String()) @@ -185,6 +223,36 @@ func (a *App) onWatcherEvent(ctx context.Context, event types.Event) error { } } +func (a *App) handleAccessMonitoringRule(ctx context.Context, event types.Event) error { + if kind := event.Resource.GetKind(); kind != types.KindAccessMonitoringRule { + return trace.BadParameter("expected %s resource kind, got %s", types.KindAccessMonitoringRule, kind) + } + + a.accessMonitoringRules.Lock() + defer a.accessMonitoringRules.Unlock() + switch op := event.Type; op { + case types.OpPut: + e, ok := event.Resource.(types.Resource153Unwrapper) + if !ok { + return trace.BadParameter("expected Resource153Unwrapper resource type, got %T", event.Resource) + } + req, ok := e.Unwrap().(*accessmonitoringrulesv1.AccessMonitoringRule) + if !ok { + return trace.BadParameter("expected AccessMonitoringRule resource type, got %T", event.Resource) + } + if !a.amrAppliesToThisPlugin(req) { + return nil + } + a.accessMonitoringRules.rules[req.Metadata.Name] = req + return nil + case types.OpDelete: + delete(a.accessMonitoringRules.rules, event.Resource.GetName()) + return nil + default: + return trace.BadParameter("unexpected event operation %s", op) + } +} + func (a *App) onPendingRequest(ctx context.Context, req types.AccessRequest) error { log := logger.Get(ctx) @@ -345,6 +413,14 @@ func (a *App) getMessageRecipients(ctx context.Context, req types.AccessRequest) // This can happen if this set contains the channel `C` and the email for channel `C`. recipientSet := common.NewRecipientSet() + recipients := a.recipientsFromAccessMonitoringRules(ctx, req) + recipients.ForEach(func(r common.Recipient) { + recipientSet.Add(r) + }) + if recipientSet.Len() != 0 { + return recipientSet.ToSlice() + } + switch a.pluginType { case types.PluginTypeServiceNow: // The ServiceNow plugin does not use recipients currently and create incidents in the incident table directly. @@ -389,6 +465,40 @@ func (a *App) getMessageRecipients(ctx context.Context, req types.AccessRequest) return recipientSet.ToSlice() } +func (a *App) recipientsFromAccessMonitoringRules(ctx context.Context, req types.AccessRequest) *common.RecipientSet { + log := logger.Get(ctx) + recipientSet := common.NewRecipientSet() + + // This switch is used to determine which plugins we are enabling access monitoring notification rules for. + switch a.pluginType { + // Enabled plugins are added to this case. + case types.PluginTypeSlack: + log.Debug("Applying access monitoring rules to request") + default: + return &recipientSet + } + + for _, rule := range a.getAccessMonitoringRules() { + match, err := matchAccessRequest(rule.Spec.Condition, req) + if err != nil { + log.WithError(err).WithField("rule", rule.Metadata.Name). + Warn("Failed to parse access monitoring notification rule") + } + if !match { + continue + } + for _, recipient := range rule.Spec.Notification.Recipients { + rec, err := a.bot.FetchRecipient(ctx, recipient) + if err != nil { + log.WithError(err).Warn("Failed to fetch plugin recipients based on Access moniotring rule recipients") + continue + } + recipientSet.Add(*rec) + } + } + return &recipientSet +} + // updateMessages updates the messages status and adds the resolve reason. func (a *App) updateMessages(ctx context.Context, reqID string, tag pd.ResolutionTag, reason string, reviews []types.AccessReview) error { log := logger.Get(ctx) @@ -461,3 +571,45 @@ func (a *App) getResourceNames(ctx context.Context, req types.AccessRequest) ([] } return resourceNames, nil } + +func (a *App) initAccessMonitoringRulesCache(ctx context.Context) error { + accessMonitoringRules, err := a.getAllAccessMonitoringRules(ctx) + if err != nil { + return trace.Wrap(err) + } + a.accessMonitoringRules.Lock() + defer a.accessMonitoringRules.Unlock() + for _, amr := range accessMonitoringRules { + if !a.amrAppliesToThisPlugin(amr) { + continue + } + a.accessMonitoringRules.rules[amr.GetMetadata().Name] = amr + } + return nil +} + +func (a *App) getAllAccessMonitoringRules(ctx context.Context) ([]*accessmonitoringrulesv1.AccessMonitoringRule, error) { + var resources []*accessmonitoringrulesv1.AccessMonitoringRule + var nextToken string + for { + var page []*accessmonitoringrulesv1.AccessMonitoringRule + var err error + page, nextToken, err = a.apiClient.ListAccessMonitoringRulesWithFilter(ctx, defaultAccessMonitoringRulePageSize, nextToken, []string{types.KindAccessRequest}, a.pluginName) + if err != nil { + return nil, trace.Wrap(err) + } + + resources = append(resources, page...) + + if nextToken == "" { + break + } + } + return resources, nil +} + +func (a *App) getAccessMonitoringRules() map[string]*accessmonitoringrulesv1.AccessMonitoringRule { + a.accessMonitoringRules.RLock() + defer a.accessMonitoringRules.RUnlock() + return maps.Clone(a.accessMonitoringRules.rules) +} diff --git a/integrations/access/accessrequest/request_mapping.go b/integrations/access/accessrequest/request_mapping.go new file mode 100644 index 0000000000000..7bc46121d0c0e --- /dev/null +++ b/integrations/access/accessrequest/request_mapping.go @@ -0,0 +1,113 @@ +/* +Copyright 2024 Gravitational, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package accessrequest + +import ( + "time" + + "github.com/gravitational/trace" + + "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/lib/expression" + "github.com/gravitational/teleport/lib/utils/typical" +) + +// accessRequestExpressionEnv holds user details that can be mapped in an +// access request condition assertion. +type accessRequestExpressionEnv struct { + Roles []string + SuggestedReviewers []string + Annotations map[string][]string + User string + RequestReason string + CreationTime time.Time + Expiry time.Time +} + +type accessRequestExpression typical.Expression[accessRequestExpressionEnv, any] + +func parseAccessRequestExpression(expr string) (accessRequestExpression, error) { + parser, err := newRequestConditionParser() + if err != nil { + return nil, trace.Wrap(err) + } + parsedExpr, err := parser.Parse(expr) + if err != nil { + return nil, trace.Wrap(err, "parsing access monitoring rule condition expression") + } + return parsedExpr, nil +} + +func newRequestConditionParser() (*typical.Parser[accessRequestExpressionEnv, any], error) { + typicalEnvVar := map[string]typical.Variable{ + "true": true, + "false": false, + "access_request.spec.roles": typical.DynamicVariable[accessRequestExpressionEnv](func(env accessRequestExpressionEnv) (expression.Set, error) { + return expression.NewSet(env.Roles...), nil + }), + "access_request.spec.suggested_reviewers": typical.DynamicVariable[accessRequestExpressionEnv](func(env accessRequestExpressionEnv) (expression.Set, error) { + return expression.NewSet(env.SuggestedReviewers...), nil + }), + "access_request.spec.system_annotations": typical.DynamicMap[accessRequestExpressionEnv, expression.Set](func(env accessRequestExpressionEnv) (expression.Dict, error) { + return expression.DictFromStringSliceMap(env.Annotations), nil + }), + "access_request.spec.user": typical.DynamicVariable[accessRequestExpressionEnv](func(env accessRequestExpressionEnv) (string, error) { + return env.User, nil + }), + "access_request.spec.request_reason": typical.DynamicVariable[accessRequestExpressionEnv](func(env accessRequestExpressionEnv) (string, error) { + return env.RequestReason, nil + }), + "access_request.spec.creation_time": typical.DynamicVariable[accessRequestExpressionEnv](func(env accessRequestExpressionEnv) (time.Time, error) { + return env.CreationTime, nil + }), + "access_request.spec.expiry": typical.DynamicVariable[accessRequestExpressionEnv](func(env accessRequestExpressionEnv) (time.Time, error) { + return env.Expiry, nil + }), + } + defParserSpec := expression.DefaultParserSpec[accessRequestExpressionEnv]() + defParserSpec.Variables = typicalEnvVar + + requestConditionParser, err := typical.NewParser[accessRequestExpressionEnv, any](defParserSpec) + if err != nil { + return nil, trace.Wrap(err) + } + return requestConditionParser, nil +} + +func matchAccessRequest(expr string, req types.AccessRequest) (bool, error) { + parsedExpr, err := parseAccessRequestExpression(expr) + if err != nil { + return false, trace.Wrap(err) + } + + match, err := parsedExpr.Evaluate(accessRequestExpressionEnv{ + Roles: req.GetRoles(), + SuggestedReviewers: req.GetSuggestedReviewers(), + Annotations: req.GetSystemAnnotations(), + User: req.GetUser(), + RequestReason: req.GetRequestReason(), + CreationTime: req.GetCreationTime(), + Expiry: req.Expiry(), + }) + if err != nil { + return false, trace.Wrap(err, "evaluating access monitoring rule condition expression %q", expr) + } + if matched, ok := match.(bool); ok && matched { + return true, nil + } + return false, nil +} diff --git a/integrations/access/common/config.go b/integrations/access/common/config.go index e664373eae6b7..0a3dd48ba5465 100644 --- a/integrations/access/common/config.go +++ b/integrations/access/common/config.go @@ -58,9 +58,9 @@ func (w *wrappedClient) ListAccessLists(ctx context.Context, pageSize int, pageT return w.Client.AccessListClient().ListAccessLists(ctx, pageSize, pageToken) } -// ListAccessMonitoringRules lists current access monitoring rules. -func (w *wrappedClient) ListAccessMonitoringRules(ctx context.Context, limit int, startKey string) ([]*accessmonitoringrulesv1.AccessMonitoringRule, string, error) { - return w.Client.AccessMonitoringRulesClient().ListAccessMonitoringRules(ctx, limit, startKey) +// ListAccessMonitoringRulesWithFilter lists current access monitoring rules. +func (w *wrappedClient) ListAccessMonitoringRulesWithFilter(ctx context.Context, pageSize int, pageToken string, subjects []string, notificationName string) ([]*accessmonitoringrulesv1.AccessMonitoringRule, string, error) { + return w.Client.AccessMonitoringRulesClient().ListAccessMonitoringRulesWithFilter(ctx, pageSize, pageToken, subjects, notificationName) } // wrapAPIClient will wrap the API client such that it conforms to the Teleport plugin client interface. diff --git a/integrations/access/common/recipient.go b/integrations/access/common/recipient.go index f352cd579812c..67273cefa4b5b 100644 --- a/integrations/access/common/recipient.go +++ b/integrations/access/common/recipient.go @@ -145,3 +145,15 @@ func (s *RecipientSet) ToSlice() []Recipient { } return recipientSlice } + +// ForEach applies run the given func with each recipient in the set as the argument. +func (s *RecipientSet) ForEach(f func(r Recipient)) { + for _, v := range s.recipients { + f(v) + } +} + +// Len returns number of recipients +func (s *RecipientSet) Len() int { + return len(s.recipients) +} diff --git a/integrations/access/common/teleport/client.go b/integrations/access/common/teleport/client.go index 8e61120314f55..675c9578d939e 100644 --- a/integrations/access/common/teleport/client.go +++ b/integrations/access/common/teleport/client.go @@ -40,5 +40,5 @@ type Client interface { SetAccessRequestState(ctx context.Context, params types.AccessRequestUpdate) error ListResources(ctx context.Context, req proto.ListResourcesRequest) (*types.ListResourcesResponse, error) ListAccessLists(context.Context, int, string) ([]*accesslist.AccessList, string, error) - ListAccessMonitoringRules(ctx context.Context, limit int, startKey string) ([]*accessmonitoringrulesv1.AccessMonitoringRule, string, error) + ListAccessMonitoringRulesWithFilter(ctx context.Context, pageSize int, pageToken string, subjects []string, notificationName string) ([]*accessmonitoringrulesv1.AccessMonitoringRule, string, error) } diff --git a/integrations/access/slack/testlib/suite.go b/integrations/access/slack/testlib/suite.go index f8f8840559c5a..f7e810b4a4b88 100644 --- a/integrations/access/slack/testlib/suite.go +++ b/integrations/access/slack/testlib/suite.go @@ -35,6 +35,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + accessmonitoringrulesv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/accessmonitoringrules/v1" + v1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/types/accesslist" "github.com/gravitational/teleport/api/types/header" @@ -88,6 +90,7 @@ func (s *SlackBaseSuite) SetupTest() { conf.Slack.APIURL = s.fakeSlack.URL() + "/" conf.AccessTokenProvider = auth.NewStaticAccessTokenProvider(conf.Slack.Token) conf.StatusSink = s.fakeStatusSink + conf.PluginType = types.PluginTypeSlack s.appConfig = &conf } @@ -241,6 +244,75 @@ func (s *SlackSuiteOSS) TestRecipientsConfig() { assert.Equal(t, s.reviewer2SlackUser.ID, messages[2].Channel) } +func (s *SlackSuiteOSS) TestRecipientsFromAccessMonitoringRule() { + t := s.T() + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) + t.Cleanup(cancel) + + // Setup base config to ensure access monitoring rule recipient take precidence + s.appConfig.Recipients = common.RawRecipientsMap{ + types.Wildcard: []string{ + s.reviewer2SlackUser.Profile.Email, + }, + } + + s.startApp() + const numMessages = 3 + + _, err := s.ClientByName(integration.RulerUserName). + AccessMonitoringRulesClient(). + CreateAccessMonitoringRule(ctx, &accessmonitoringrulesv1.AccessMonitoringRule{ + Kind: types.KindAccessMonitoringRule, + Version: types.V1, + Metadata: &v1.Metadata{ + Name: "test-slack-amr", + }, + Spec: &accessmonitoringrulesv1.AccessMonitoringRuleSpec{ + Subjects: []string{types.KindAccessRequest}, + Condition: "!is_empty(access_request.spec.roles)", + Notification: &accessmonitoringrulesv1.Notification{ + Name: "slack", + Recipients: []string{ + s.reviewer1SlackUser.ID, + s.reviewer2SlackUser.Profile.Email, + }, + }, + }, + }) + assert.NoError(t, err) + + // Test execution: we create an access request + userName := integration.RequesterOSSUserName + request := s.CreateAccessRequest(ctx, userName, nil) + pluginData := s.checkPluginData(ctx, request.GetName(), func(data accessrequest.PluginData) bool { + return len(data.SentMessages) > 0 + }) + assert.Len(t, pluginData.SentMessages, numMessages) + + var messages []slack.Message + + messageSet := make(SlackDataMessageSet) + + // Validate we got 3 messages: one for each recipient and one for the requester. + for i := 0; i < numMessages; i++ { + msg, err := s.fakeSlack.CheckNewMessage(ctx) + require.NoError(t, err) + messageSet.Add(accessrequest.MessageData{ChannelID: msg.Channel, MessageID: msg.Timestamp}) + messages = append(messages, msg) + } + + assert.Len(t, messageSet, numMessages) + for i := 0; i < numMessages; i++ { + assert.Contains(t, messageSet, pluginData.SentMessages[i]) + } + + // Validate the message recipients + sort.Sort(SlackMessageSlice(messages)) + assert.Equal(t, s.requesterOSSSlackUser.ID, messages[0].Channel) + assert.Equal(t, s.reviewer1SlackUser.ID, messages[1].Channel) + assert.Equal(t, s.reviewer2SlackUser.ID, messages[2].Channel) +} + // TestApproval tests that when a request is approved, its corresponding message // is updated to reflect the new request state. func (s *SlackSuiteOSS) TestApproval() { diff --git a/integrations/lib/testing/integration/accessrequestsuite.go b/integrations/lib/testing/integration/accessrequestsuite.go index a257e80b04907..3be8578f23088 100644 --- a/integrations/lib/testing/integration/accessrequestsuite.go +++ b/integrations/lib/testing/integration/accessrequestsuite.go @@ -205,6 +205,7 @@ func (s *AccessRequestSuite) SetupSuite() { // submit positive reviews. types.NewRule("access_request", []string{"list", "read", "update"}), types.NewRule("access_plugin_data", []string{"update"}), + types.NewRule(types.KindAccessMonitoringRule, []string{"update", "read", "list"}), }, }, }) diff --git a/lib/accessmonitoringrules/accessmonitoringrulesv1/service.go b/lib/accessmonitoringrules/accessmonitoringrulesv1/service.go index c7db512ab2c7a..eb53f499c3452 100644 --- a/lib/accessmonitoringrules/accessmonitoringrulesv1/service.go +++ b/lib/accessmonitoringrules/accessmonitoringrulesv1/service.go @@ -40,6 +40,7 @@ type ServiceConfig struct { // Cache is the subset of the cached resources that the service queries. type Cache interface { ListAccessMonitoringRules(ctx context.Context, limit int, startKey string) ([]*accessmonitoringrulesv1.AccessMonitoringRule, string, error) + ListAccessMonitoringRulesWithFilter(ctx context.Context, pageSize int, pageToken string, subjects []string, notificationName string) ([]*accessmonitoringrulesv1.AccessMonitoringRule, string, error) GetAccessMonitoringRule(ctx context.Context, name string) (*accessmonitoringrulesv1.AccessMonitoringRule, error) } @@ -168,3 +169,22 @@ func (s *Service) ListAccessMonitoringRules(ctx context.Context, req *accessmoni NextPageToken: nextToken, }, nil } + +// ListAccessMonitoringRulesWithFilter lists current access monitoring rules. +func (s *Service) ListAccessMonitoringRulesWithFilter(ctx context.Context, req *accessmonitoringrulesv1.ListAccessMonitoringRulesWithFilterRequest) (*accessmonitoringrulesv1.ListAccessMonitoringRulesWithFilterResponse, error) { + authCtx, err := s.authorizer.Authorize(ctx) + if err != nil { + return nil, trace.Wrap(err) + } + if err := authCtx.CheckAccessToKind(types.KindAccessMonitoringRule, types.VerbRead, types.VerbList); err != nil { + return nil, trace.Wrap(err) + } + results, nextToken, err := s.cache.ListAccessMonitoringRulesWithFilter(ctx, int(req.PageSize), req.PageToken, req.Subjects, req.NotificationName) + if err != nil { + return nil, trace.Wrap(err) + } + return &accessmonitoringrulesv1.ListAccessMonitoringRulesWithFilterResponse{ + Rules: results, + NextPageToken: nextToken, + }, nil +} diff --git a/lib/accessmonitoringrules/accessmonitoringrulesv1/service_test.go b/lib/accessmonitoringrules/accessmonitoringrulesv1/service_test.go index 446c5ebdc2a1a..6a2f28c109661 100644 --- a/lib/accessmonitoringrules/accessmonitoringrulesv1/service_test.go +++ b/lib/accessmonitoringrules/accessmonitoringrulesv1/service_test.go @@ -48,9 +48,10 @@ func TestAccessMonitoringRuleCRUD(t *testing.T) { ctx, localClient, resourceSvc := initSvc(t, clusterName) - sampleAccessMonitoringRuleFn := func(t *testing.T, name string) *accessmonitoringrulev1.AccessMonitoringRule { + sampleAccessMonitoringRuleFn := func(name string) *accessmonitoringrulev1.AccessMonitoringRule { return &accessmonitoringrulev1.AccessMonitoringRule{ Kind: types.KindAccessMonitoringRule, + Version: types.V1, Metadata: &v1.Metadata{Name: name}, Spec: &accessmonitoringrulev1.AccessMonitoringRuleSpec{ Subjects: []string{"someSubject"}, @@ -76,7 +77,7 @@ func TestAccessMonitoringRuleCRUD(t *testing.T) { }}}, }, Setup: func(t *testing.T, amrName string) { - _, err := localClient.CreateAccessMonitoringRule(ctx, sampleAccessMonitoringRuleFn(t, amrName)) + _, err := localClient.CreateAccessMonitoringRule(ctx, sampleAccessMonitoringRuleFn(amrName)) require.NoError(t, err) }, Test: func(ctx context.Context, resourceSvc *Service, amrName string) error { @@ -126,7 +127,7 @@ func TestAccessMonitoringRuleCRUD(t *testing.T) { }, Setup: func(t *testing.T, _ string) { for i := 0; i < 10; i++ { - _, err := localClient.CreateAccessMonitoringRule(ctx, sampleAccessMonitoringRuleFn(t, uuid.NewString())) + _, err := localClient.CreateAccessMonitoringRule(ctx, sampleAccessMonitoringRuleFn(uuid.NewString())) require.NoError(t, err) } }, @@ -162,7 +163,7 @@ func TestAccessMonitoringRuleCRUD(t *testing.T) { Name: "no access to create AccessMonitoringRules", Role: types.RoleSpecV6{}, Test: func(ctx context.Context, resourceSvc *Service, amrName string) error { - amr := sampleAccessMonitoringRuleFn(t, amrName) + amr := sampleAccessMonitoringRuleFn(amrName) _, err := resourceSvc.CreateAccessMonitoringRule(ctx, &accessmonitoringrulev1.CreateAccessMonitoringRuleRequest{ Rule: amr, }) @@ -179,7 +180,7 @@ func TestAccessMonitoringRuleCRUD(t *testing.T) { }}}, }, Test: func(ctx context.Context, resourceSvc *Service, amrName string) error { - amr := sampleAccessMonitoringRuleFn(t, amrName) + amr := sampleAccessMonitoringRuleFn(amrName) _, err := resourceSvc.CreateAccessMonitoringRule(ctx, &accessmonitoringrulev1.CreateAccessMonitoringRuleRequest{ Rule: amr, }) @@ -193,7 +194,7 @@ func TestAccessMonitoringRuleCRUD(t *testing.T) { Name: "no access to update AccessMonitoringRule", Role: types.RoleSpecV6{}, Test: func(ctx context.Context, resourceSvc *Service, amrName string) error { - amr := sampleAccessMonitoringRuleFn(t, amrName) + amr := sampleAccessMonitoringRuleFn(amrName) _, err := resourceSvc.UpdateAccessMonitoringRule(ctx, &accessmonitoringrulev1.UpdateAccessMonitoringRuleRequest{ Rule: amr, }) @@ -210,11 +211,11 @@ func TestAccessMonitoringRuleCRUD(t *testing.T) { }}}, }, Setup: func(t *testing.T, amrName string) { - _, err := localClient.CreateAccessMonitoringRule(ctx, sampleAccessMonitoringRuleFn(t, amrName)) + _, err := localClient.CreateAccessMonitoringRule(ctx, sampleAccessMonitoringRuleFn(amrName)) require.NoError(t, err) }, Test: func(ctx context.Context, resourceSvc *Service, amrName string) error { - amr := sampleAccessMonitoringRuleFn(t, amrName) + amr := sampleAccessMonitoringRuleFn(amrName) _, err := resourceSvc.UpdateAccessMonitoringRule(ctx, &accessmonitoringrulev1.UpdateAccessMonitoringRuleRequest{ Rule: amr, }) @@ -233,7 +234,7 @@ func TestAccessMonitoringRuleCRUD(t *testing.T) { }}}, }, Test: func(ctx context.Context, resourceSvc *Service, amrName string) error { - amr := sampleAccessMonitoringRuleFn(t, amrName) + amr := sampleAccessMonitoringRuleFn(amrName) _, err := resourceSvc.UpsertAccessMonitoringRule(ctx, &accessmonitoringrulev1.UpsertAccessMonitoringRuleRequest{ Rule: amr, }) @@ -251,7 +252,7 @@ func TestAccessMonitoringRuleCRUD(t *testing.T) { }, Setup: func(t *testing.T, amrName string) {}, Test: func(ctx context.Context, resourceSvc *Service, amrName string) error { - amr := sampleAccessMonitoringRuleFn(t, amrName) + amr := sampleAccessMonitoringRuleFn(amrName) _, err := resourceSvc.UpsertAccessMonitoringRule(ctx, &accessmonitoringrulev1.UpsertAccessMonitoringRuleRequest{ Rule: amr, }) @@ -279,7 +280,7 @@ func TestAccessMonitoringRuleCRUD(t *testing.T) { }}}, }, Setup: func(t *testing.T, amrName string) { - _, err := localClient.CreateAccessMonitoringRule(ctx, sampleAccessMonitoringRuleFn(t, amrName)) + _, err := localClient.CreateAccessMonitoringRule(ctx, sampleAccessMonitoringRuleFn(amrName)) require.NoError(t, err) }, Test: func(ctx context.Context, resourceSvc *Service, amrName string) error { diff --git a/lib/auth/authclient/api.go b/lib/auth/authclient/api.go index b724de9d3cdd8..87482c7e84d6c 100644 --- a/lib/auth/authclient/api.go +++ b/lib/auth/authclient/api.go @@ -1167,6 +1167,8 @@ type Cache interface { ListAccessMonitoringRules(ctx context.Context, limit int, startKey string) ([]*accessmonitoringrules.AccessMonitoringRule, string, error) // GetAccessMonitoringRule returns the specified access monitoring rule. GetAccessMonitoringRule(ctx context.Context, name string) (*accessmonitoringrules.AccessMonitoringRule, error) + // ListAccessMonitoringRulesWithFilter returns a paginated list of access monitoring rules. + ListAccessMonitoringRulesWithFilter(ctx context.Context, pageSize int, nextToken string, subjects []string, notificationName string) ([]*accessmonitoringrules.AccessMonitoringRule, string, error) } type NodeWrapper struct { diff --git a/lib/cache/cache.go b/lib/cache/cache.go index a74bf553b0405..2bab09f0d5643 100644 --- a/lib/cache/cache.go +++ b/lib/cache/cache.go @@ -3125,6 +3125,21 @@ func (c *Cache) ListAccessMonitoringRules(ctx context.Context, pageSize int, nex return out, nextKey, trace.Wrap(err) } +// ListAccessMonitoringRulesWithFilter returns a paginated list of access monitoring rules. +func (c *Cache) ListAccessMonitoringRulesWithFilter(ctx context.Context, pageSize int, nextToken string, subjects []string, notificationName string) ([]*accessmonitoringrulesv1.AccessMonitoringRule, string, error) { + ctx, span := c.Tracer.Start(ctx, "cache/ListAccessMonitoringRules") + defer span.End() + + rg, err := readCollectionCache(c, c.collections.accessMonitoringRules) + + if err != nil { + return nil, "", trace.Wrap(err) + } + defer rg.Release() + out, nextKey, err := rg.reader.ListAccessMonitoringRulesWithFilter(ctx, pageSize, nextToken, subjects, notificationName) + return out, nextKey, trace.Wrap(err) +} + // GetAccessMonitoringRule returns the specified AccessMonitoringRule resources. func (c *Cache) GetAccessMonitoringRule(ctx context.Context, name string) (*accessmonitoringrulesv1.AccessMonitoringRule, error) { ctx, span := c.Tracer.Start(ctx, "cache/GetAccessMonitoringRule") diff --git a/lib/cache/collections.go b/lib/cache/collections.go index 339a014cdf4fe..289fca897723c 100644 --- a/lib/cache/collections.go +++ b/lib/cache/collections.go @@ -3170,4 +3170,5 @@ func (accessMonitoringRulesExecutor) getReader(cache *Cache, cacheOK bool) acces type accessMonitoringRuleGetter interface { GetAccessMonitoringRule(ctx context.Context, name string) (*accessmonitoringrulesv1.AccessMonitoringRule, error) ListAccessMonitoringRules(ctx context.Context, limit int, startKey string) ([]*accessmonitoringrulesv1.AccessMonitoringRule, string, error) + ListAccessMonitoringRulesWithFilter(ctx context.Context, pageSize int, nextToken string, subjects []string, notificationName string) ([]*accessmonitoringrulesv1.AccessMonitoringRule, string, error) } diff --git a/lib/expression/parser.go b/lib/expression/parser.go index 3678d4c84d469..7055d065bc837 100644 --- a/lib/expression/parser.go +++ b/lib/expression/parser.go @@ -20,6 +20,7 @@ package expression import ( "strings" + "time" "github.com/gravitational/trace" @@ -104,6 +105,42 @@ func DefaultParserSpec[evaluationEnv any]() typical.ParserSpec[evaluationEnv] { } return NewSet(outputs...), nil }), + "time.RFC3339": typical.UnaryFunction[evaluationEnv]( + func(input string) (time.Time, error) { + return time.Parse(time.RFC3339, input) + }), + "before": typical.BinaryFunction[evaluationEnv]( + func(t time.Time, other time.Time) (bool, error) { + return t.Before(other), nil + }), + "after": typical.BinaryFunction[evaluationEnv]( + func(t time.Time, other time.Time) (bool, error) { + return t.After(other), nil + }), + "between": typical.BinaryVariadicFunction[evaluationEnv]( + func(t time.Time, interval ...time.Time) (bool, error) { + if len(interval) != 2 { + return false, trace.BadParameter("between expected 2 parameters: got %v", len(interval)) + } + first, second := interval[0], interval[1] + if first.After(second) { + first, second = second, first + } + return t.After(first) && t.Before(second), nil + }), + "contains_any": typical.BinaryFunction[evaluationEnv]( + func(s1, s2 Set) (bool, error) { + for _, v := range s2.items() { + if s1.contains(v) { + return true, nil + } + } + return false, nil + }), + "is_empty": typical.UnaryFunction[evaluationEnv]( + func(s Set) (bool, error) { + return len(s) == 0, nil + }), }, Methods: map[string]typical.Function{ "add": typical.BinaryVariadicFunction[evaluationEnv]( @@ -126,6 +163,38 @@ func DefaultParserSpec[evaluationEnv any]() typical.ParserSpec[evaluationEnv] { func(r remover, items ...string) (any, error) { return r.remove(items...), nil }), + "before": typical.BinaryFunction[evaluationEnv]( + func(t time.Time, other time.Time) (bool, error) { + return t.Before(other), nil + }), + "after": typical.BinaryFunction[evaluationEnv]( + func(t time.Time, other time.Time) (bool, error) { + return t.After(other), nil + }), + "between": typical.BinaryVariadicFunction[evaluationEnv]( + func(t time.Time, interval ...time.Time) (bool, error) { + if len(interval) != 2 { + return false, trace.BadParameter("between expected 2 parameters: got %v", len(interval)) + } + first, second := interval[0], interval[1] + if first.After(second) { + first, second = second, first + } + return t.After(first) && t.Before(second), nil + }), + "contains_any": typical.BinaryFunction[evaluationEnv]( + func(s1, s2 Set) (bool, error) { + for _, v := range s2.items() { + if s1.contains(v) { + return true, nil + } + } + return false, nil + }), + "isempty": typical.UnaryFunction[evaluationEnv]( + func(s Set) (bool, error) { + return len(s) == 0, nil + }), }, } } diff --git a/lib/services/access_monitoring_rules.go b/lib/services/access_monitoring_rules.go index b459389f6b08a..e091353d1dfa8 100644 --- a/lib/services/access_monitoring_rules.go +++ b/lib/services/access_monitoring_rules.go @@ -39,6 +39,7 @@ type AccessMonitoringRules interface { DeleteAccessMonitoringRule(ctx context.Context, name string) error DeleteAllAccessMonitoringRules(ctx context.Context) error ListAccessMonitoringRules(ctx context.Context, limit int, startKey string) ([]*accessmonitoringrulesv1.AccessMonitoringRule, string, error) + ListAccessMonitoringRulesWithFilter(ctx context.Context, pageSize int, nextToken string, subjects []string, notificationName string) ([]*accessmonitoringrulesv1.AccessMonitoringRule, string, error) } // NewAccessMonitoringRuleWithLabels creates a new AccessMonitoringRule with the given spec and labels. @@ -69,6 +70,9 @@ func ValidateAccessMonitoringRule(accessMonitoringRule *accessmonitoringrulesv1. if accessMonitoringRule.Metadata == nil { return trace.BadParameter("accessMonitoringRule metadata is missing") } + if accessMonitoringRule.Version != types.V1 { + return trace.BadParameter("accessMonitoringRule %q is not supported", accessMonitoringRule.Version) + } if accessMonitoringRule.Spec == nil { return trace.BadParameter("accessMonitoringRule spec is missing") } diff --git a/lib/services/local/access_monitoring_rules.go b/lib/services/local/access_monitoring_rules.go index deeafcead11ce..5b1e059b49517 100644 --- a/lib/services/local/access_monitoring_rules.go +++ b/lib/services/local/access_monitoring_rules.go @@ -20,6 +20,7 @@ package local import ( "context" + "slices" "github.com/gravitational/trace" @@ -110,3 +111,31 @@ func (s *AccessMonitoringRulesService) DeleteAccessMonitoringRule(ctx context.Co func (s *AccessMonitoringRulesService) DeleteAllAccessMonitoringRules(ctx context.Context) error { return trace.Wrap(s.svc.DeleteAllResources(ctx)) } + +// ListAccessMonitoringRulesWithFilter returns a paginated list of access monitoring rules that match the given filter. +func (s *AccessMonitoringRulesService) ListAccessMonitoringRulesWithFilter(ctx context.Context, pageSize int, pageToken string, subjects []string, notificationName string) ([]*accessmonitoringrulesv1.AccessMonitoringRule, string, error) { + resources, nextKey, err := s.svc.ListResourcesWithFilter(ctx, pageSize, pageToken, + func(resource *accessmonitoringrulesv1.AccessMonitoringRule) bool { + return match(resource, subjects, notificationName) + }) + if err != nil { + return nil, "", trace.Wrap(err) + } + return resources, nextKey, nil +} + +func match(rule *accessmonitoringrulesv1.AccessMonitoringRule, subjects []string, notificationName string) bool { + if notificationName != "" { + if rule.Spec.Notification == nil || rule.Spec.Notification.Name != notificationName { + return false + } + } + for _, subject := range subjects { + if ok := slices.ContainsFunc(rule.Spec.Subjects, func(s string) bool { + return s == subject + }); !ok { + return false + } + } + return true +} diff --git a/lib/services/local/access_monitoring_rules_test.go b/lib/services/local/access_monitoring_rules_test.go index 2cee8530b3cfc..b3ce35e878152 100644 --- a/lib/services/local/access_monitoring_rules_test.go +++ b/lib/services/local/access_monitoring_rules_test.go @@ -49,7 +49,8 @@ func TestAccessMonitoringRulesCRUD(t *testing.T) { require.NoError(t, err) AccessMonitoringRule1 := &accessmonitoringrulesv1.AccessMonitoringRule{ - Kind: types.KindAccessMonitoringRule, + Kind: types.KindAccessMonitoringRule, + Version: types.V1, Metadata: &v1.Metadata{ Name: "p1", }, @@ -60,7 +61,8 @@ func TestAccessMonitoringRulesCRUD(t *testing.T) { } AccessMonitoringRule2 := &accessmonitoringrulesv1.AccessMonitoringRule{ - Kind: types.KindAccessMonitoringRule, + Kind: types.KindAccessMonitoringRule, + Version: types.V1, Metadata: &v1.Metadata{ Name: "p2", }, @@ -129,7 +131,8 @@ func TestListAccessMonitoringRules(t *testing.T) { var insertedAccessMonitoringRules []*accessmonitoringrulesv1.AccessMonitoringRule for i := 0; i < numAccessMonitoringRules; i++ { AccessMonitoringRule := &accessmonitoringrulesv1.AccessMonitoringRule{ - Kind: types.KindAccessMonitoringRule, + Kind: types.KindAccessMonitoringRule, + Version: types.V1, Metadata: &v1.Metadata{ Name: fmt.Sprintf("p%02d", i+1), }, diff --git a/lib/services/local/generic/generic.go b/lib/services/local/generic/generic.go index 5ba550aec092e..02a7648d67f9e 100644 --- a/lib/services/local/generic/generic.go +++ b/lib/services/local/generic/generic.go @@ -213,6 +213,54 @@ func (s *Service[T]) ListResourcesReturnNextResource(ctx context.Context, pageSi return out, next, nil } +// ListResourcesWithFilter returns a paginated list of resources that match the given filter. +func (s *Service[T]) ListResourcesWithFilter(ctx context.Context, pageSize int, pageToken string, matcher func(T) bool) ([]T, string, error) { + rangeStart := backend.Key(s.backendPrefix, pageToken) + rangeEnd := backend.RangeEnd(backend.ExactKey(s.backendPrefix)) + + // Adjust page size, so it can't be too large. + if pageSize <= 0 || pageSize > int(s.pageLimit) { + pageSize = int(s.pageLimit) + } + + limit := pageSize + 1 + + var resources []T + if err := backend.IterateRange( + ctx, + s.backend, + rangeStart, + rangeEnd, + limit, + func(items []backend.Item) (stop bool, err error) { + for _, item := range items { + resource, err := s.unmarshalFunc(item.Value, services.WithRevision(item.Revision), services.WithRevision(item.Revision)) + if err != nil { + return false, trace.Wrap(err) + } + if matcher(resource) { + resources = append(resources, resource) + } + if len(resources) == pageSize { + break + } + } + return limit == len(resources), nil + }); err != nil { + return nil, "", trace.Wrap(err) + } + + var nextKey string + if len(resources) > pageSize { + nextKey = backend.GetPaginationKey(resources[pageSize]) + // Truncate the last item that was used to determine next row existence. + resources = resources[:pageSize] + } + + return resources, nextKey, nil + +} + // GetResource returns the specified resource. func (s *Service[T]) GetResource(ctx context.Context, name string) (resource T, err error) { item, err := s.backend.Get(ctx, s.MakeKey(name)) diff --git a/lib/services/local/generic/generic_test.go b/lib/services/local/generic/generic_test.go index 3bc0c63e19613..7dd43710ba98d 100644 --- a/lib/services/local/generic/generic_test.go +++ b/lib/services/local/generic/generic_test.go @@ -329,3 +329,50 @@ func TestGenericListResourcesReturnNextResource(t *testing.T) { )) require.Nil(t, next) } + +func TestGenericListResourcesWithFilter(t *testing.T) { + ctx := context.Background() + + memBackend, err := memory.New(memory.Config{ + Context: ctx, + Clock: clockwork.NewFakeClock(), + }) + require.NoError(t, err) + + service, err := NewService(&ServiceConfig[*testResource]{ + Backend: memBackend, + ResourceKind: "generic resource", + PageLimit: 200, + BackendPrefix: "generic_prefix", + UnmarshalFunc: unmarshalResource, + MarshalFunc: marshalResource, + }) + require.NoError(t, err) + + // Create a couple test resources. + r1 := newTestResource("r1") + r2 := newTestResource("r2") + + _, err = service.WithPrefix("a-unique-prefix").UpsertResource(ctx, r1) + require.NoError(t, err) + _, err = service.WithPrefix("another-unique-prefix").UpsertResource(ctx, r2) + require.NoError(t, err) + + page, nextKey, err := service.ListResourcesWithFilter(ctx, 1, "", func(r *testResource) bool { + return r.Metadata.Name == "r1" + }) + require.NoError(t, err) + require.Empty(t, cmp.Diff([]*testResource{r1}, page, + cmpopts.IgnoreFields(types.Metadata{}, "Revision"), + )) + require.Equal(t, "", nextKey) + + page, nextKey, err = service.ListResourcesWithFilter(ctx, 1, "", func(r *testResource) bool { + return r.Metadata.Name == "r2" + }) + require.NoError(t, err) + require.Empty(t, cmp.Diff([]*testResource{r2}, page, + cmpopts.IgnoreFields(types.Metadata{}, "Revision"), + )) + require.Equal(t, "", nextKey) +} diff --git a/lib/services/local/generic/generic_wrapper.go b/lib/services/local/generic/generic_wrapper.go index 25f2f910cf54a..3fa6fc1c1c418 100644 --- a/lib/services/local/generic/generic_wrapper.go +++ b/lib/services/local/generic/generic_wrapper.go @@ -132,3 +132,20 @@ func (s ServiceWrapper[T]) ListResources(ctx context.Context, pageSize int, page } return out, nextToken, trace.Wrap(err) } + +// ListResourcesWithFilter returns a paginated list of resources that match the provided filter. +func (s ServiceWrapper[T]) ListResourcesWithFilter(ctx context.Context, pageSize int, pageToken string, matcher func(T) bool) ([]T, string, error) { + adapters, nextToken, err := s.service.ListResourcesWithFilter( + ctx, + pageSize, + pageToken, + func(rma resourceMetadataAdapter[T]) bool { + return matcher(rma.resource) + }) + + out := make([]T, 0, len(adapters)) + for _, adapter := range adapters { + out = append(out, adapter.resource) + } + return out, nextToken, trace.Wrap(err) +}