mirror of
https://github.com/paralus/paralus.git
synced 2026-05-07 00:46:52 +00:00
428 lines
13 KiB
Go
428 lines
13 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/RafayLabs/rcloud-base/internal/dao"
|
|
"github.com/RafayLabs/rcloud-base/internal/models"
|
|
"github.com/RafayLabs/rcloud-base/pkg/audit"
|
|
"github.com/RafayLabs/rcloud-base/pkg/utils"
|
|
systemv3 "github.com/RafayLabs/rcloud-base/proto/types/systempb/v3"
|
|
"github.com/google/uuid"
|
|
"github.com/uptrace/bun"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
const (
|
|
AuditActionCreate = "create"
|
|
AuditActionDelete = "delete"
|
|
AuditActionUpdate = "update"
|
|
)
|
|
|
|
func CreateUserAuditEvent(ctx context.Context, al *zap.Logger, db bun.IDB, action string, name string, id uuid.UUID, rolesBefore, rolesAfter, groupsBefore, groupsAfter []uuid.UUID) {
|
|
sd, ok := GetSessionDataFromContext(ctx)
|
|
if !ok {
|
|
_log.Warn("unable to create audit event: could not fetch info from context")
|
|
return
|
|
}
|
|
|
|
detail := &audit.EventDetail{
|
|
Message: fmt.Sprintf("User %s %sd", name, action),
|
|
Meta: map[string]string{
|
|
"username": name,
|
|
},
|
|
}
|
|
if err := audit.CreateV1Event(al, sd, detail, fmt.Sprintf("user.%s.success", action), ""); err != nil {
|
|
_log.Warn("unable to create audit event", err)
|
|
}
|
|
|
|
cr, _, dr := utils.DiffU(rolesBefore, rolesAfter)
|
|
ncr, err := dao.GetNamesByIds(ctx, db, cr, &models.Role{})
|
|
if err != nil {
|
|
_log.Warn("unable to create audit event", err)
|
|
}
|
|
ndr, err := dao.GetNamesByIds(ctx, db, dr, &models.Role{})
|
|
if err != nil {
|
|
_log.Warn("unable to create audit event", err)
|
|
}
|
|
for _, r := range ncr {
|
|
detail := &audit.EventDetail{
|
|
Message: fmt.Sprintf("Role %s added to user %s", r, name),
|
|
Meta: map[string]string{
|
|
"username": name,
|
|
"roles_name": r, // TODO: add info like namespace and project
|
|
},
|
|
}
|
|
// user.role.created is user.project.created in rcloud
|
|
if err := audit.CreateV1Event(al, sd, detail, "user.role.created", ""); err != nil {
|
|
_log.Warn("unable to create audit event", err)
|
|
}
|
|
}
|
|
|
|
for _, r := range ndr {
|
|
detail := &audit.EventDetail{
|
|
Message: fmt.Sprintf("Role %s deleted from user %s", r, name),
|
|
Meta: map[string]string{
|
|
"username": name,
|
|
"role_name": r,
|
|
},
|
|
}
|
|
if err := audit.CreateV1Event(al, sd, detail, "user.role.deleted", ""); err != nil {
|
|
_log.Warn("unable to create audit event", err)
|
|
}
|
|
}
|
|
|
|
cg, _, dg := utils.DiffU(groupsBefore, rolesAfter)
|
|
ncg, err := dao.GetNamesByIds(ctx, db, cg, &models.Group{})
|
|
if err != nil {
|
|
_log.Warn("unable to create audit event", err)
|
|
}
|
|
ndg, err := dao.GetNamesByIds(ctx, db, dg, &models.Group{})
|
|
if err != nil {
|
|
_log.Warn("unable to create audit event", err)
|
|
}
|
|
for _, g := range ncg {
|
|
detail := &audit.EventDetail{
|
|
Message: fmt.Sprintf("User %s added to group %s", name, g),
|
|
Meta: map[string]string{
|
|
"username": name,
|
|
"group_name": g,
|
|
},
|
|
}
|
|
// user.role.created is user.project.created in rcloud
|
|
if err := audit.CreateV1Event(al, sd, detail, "user.group.created", ""); err != nil {
|
|
_log.Warn("unable to create audit event", err)
|
|
}
|
|
}
|
|
|
|
for _, g := range ndg {
|
|
detail := &audit.EventDetail{
|
|
Message: fmt.Sprintf("User %s added to group %s", name, g),
|
|
Meta: map[string]string{
|
|
"username": name,
|
|
"group_name": g,
|
|
},
|
|
}
|
|
if err := audit.CreateV1Event(al, sd, detail, "user.group.deleted", ""); err != nil {
|
|
_log.Warn("unable to create audit event", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func CreateGroupAuditEvent(ctx context.Context, al *zap.Logger, db bun.IDB, action string, name string, id uuid.UUID, usersBefore, usersAfter, rolesBefore, rolesAfter []uuid.UUID) {
|
|
sd, ok := GetSessionDataFromContext(ctx)
|
|
if !ok {
|
|
_log.Warn("unable to create audit event: could not fetch info from context")
|
|
return
|
|
}
|
|
|
|
detail := &audit.EventDetail{
|
|
Message: fmt.Sprintf("Group %s %sd", name, action),
|
|
Meta: map[string]string{
|
|
"group_name": name,
|
|
},
|
|
}
|
|
if err := audit.CreateV1Event(al, sd, detail, fmt.Sprintf("group.%s.success", action), ""); err != nil {
|
|
_log.Warn("unable to create audit event", err)
|
|
}
|
|
|
|
cu, _, du := utils.DiffU(usersBefore, usersAfter)
|
|
|
|
cun, err := dao.GetUserNamesByIds(ctx, db, cu, &models.KratosIdentities{})
|
|
if err != nil {
|
|
_log.Warn("unable to create audit event", err)
|
|
}
|
|
dun, err := dao.GetUserNamesByIds(ctx, db, du, &models.KratosIdentities{})
|
|
if err != nil {
|
|
_log.Warn("unable to create audit event", err)
|
|
}
|
|
|
|
for _, u := range cun {
|
|
detail := &audit.EventDetail{
|
|
Message: fmt.Sprintf("User %s added to group %s", u, name),
|
|
Meta: map[string]string{
|
|
"group_name": name,
|
|
"username": u,
|
|
},
|
|
}
|
|
if err := audit.CreateV1Event(al, sd, detail, "group.user.created", ""); err != nil {
|
|
_log.Warn("unable to create audit event", err)
|
|
}
|
|
}
|
|
|
|
for _, u := range dun {
|
|
detail := &audit.EventDetail{
|
|
Message: fmt.Sprintf("User %s deleted from group %s", u, name),
|
|
Meta: map[string]string{
|
|
"group_name": name,
|
|
"username": u,
|
|
},
|
|
}
|
|
if err := audit.CreateV1Event(al, sd, detail, "group.user.deleted", ""); err != nil {
|
|
_log.Warn("unable to create audit event", err)
|
|
}
|
|
}
|
|
|
|
cr, _, dr := utils.DiffU(rolesBefore, rolesAfter)
|
|
ncr, err := dao.GetNamesByIds(ctx, db, cr, &models.Role{})
|
|
if err != nil {
|
|
_log.Warn("unable to create audit event", err)
|
|
}
|
|
ndr, err := dao.GetNamesByIds(ctx, db, dr, &models.Role{})
|
|
if err != nil {
|
|
_log.Warn("unable to create audit event", err)
|
|
}
|
|
for _, r := range ncr {
|
|
detail := &audit.EventDetail{
|
|
Message: fmt.Sprintf("Role %s added to group %s", r, name),
|
|
Meta: map[string]string{
|
|
"group_name": name,
|
|
"roles_name": r, // TODO: add info like namespace and project
|
|
},
|
|
}
|
|
// group.role.created is group.project.created in rcloud
|
|
if err := audit.CreateV1Event(al, sd, detail, "group.role.created", ""); err != nil {
|
|
_log.Warn("unable to create audit event", err)
|
|
}
|
|
}
|
|
|
|
for _, r := range ndr {
|
|
detail := &audit.EventDetail{
|
|
Message: fmt.Sprintf("Role %s deleted from group %s", r, name),
|
|
Meta: map[string]string{
|
|
"group_name": name,
|
|
"role_name": r,
|
|
},
|
|
}
|
|
if err := audit.CreateV1Event(al, sd, detail, "group.role.deleted", ""); err != nil {
|
|
_log.Warn("unable to create audit event", err)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
func CreateRoleAuditEvent(ctx context.Context, al *zap.Logger, action string, name string, id uuid.UUID, permissions []string) {
|
|
sd, ok := GetSessionDataFromContext(ctx)
|
|
if !ok {
|
|
_log.Warn("unable to create audit event: could not fetch info from context")
|
|
return
|
|
}
|
|
|
|
detail := &audit.EventDetail{
|
|
Message: fmt.Sprintf("Role %s %sd", name, action),
|
|
Meta: map[string]string{
|
|
"role_name": name,
|
|
"permissions": strings.Join(permissions, ","), // TODO: Should we split it into individual ones?
|
|
},
|
|
}
|
|
if err := audit.CreateV1Event(al, sd, detail, fmt.Sprintf("role.%s.success", action), ""); err != nil {
|
|
_log.Warn("unable to create audit event", err)
|
|
}
|
|
}
|
|
|
|
func CreateProjectAuditEvent(ctx context.Context, al *zap.Logger, action string, name string, id uuid.UUID) {
|
|
sd, ok := GetSessionDataFromContext(ctx)
|
|
if !ok {
|
|
_log.Warn("unable to create audit event: could not fetch info from context")
|
|
return
|
|
}
|
|
|
|
detail := &audit.EventDetail{
|
|
Message: fmt.Sprintf("Project %s %sd", name, action),
|
|
Meta: map[string]string{
|
|
"project_name": name,
|
|
},
|
|
}
|
|
if err := audit.CreateV1Event(al, sd, detail, fmt.Sprintf("project.%s.success", action), id.String()); err != nil {
|
|
_log.Warn("unable to create audit event", err)
|
|
}
|
|
}
|
|
|
|
func CreatePartnerAuditEvent(ctx context.Context, al *zap.Logger, action string, name string, id uuid.UUID) {
|
|
sd, ok := GetSessionDataFromContext(ctx)
|
|
if !ok {
|
|
_log.Warn("unable to create audit event: could not fetch info from context")
|
|
return
|
|
}
|
|
|
|
detail := &audit.EventDetail{
|
|
Message: fmt.Sprintf("Partner %s %sd", name, action),
|
|
Meta: map[string]string{
|
|
"partner_name": name,
|
|
},
|
|
}
|
|
if err := audit.CreateV1Event(al, sd, detail, fmt.Sprintf("partner.%s.success", action), id.String()); err != nil {
|
|
_log.Warn("unable to create audit event", err)
|
|
}
|
|
}
|
|
|
|
func CreateOrganizationAuditEvent(ctx context.Context, al *zap.Logger, action string, name string, id uuid.UUID, settingsBefore, settingsAfter *systemv3.OrganizationSettings) {
|
|
sd, ok := GetSessionDataFromContext(ctx)
|
|
if !ok {
|
|
_log.Warn("unable to create audit event: could not fetch info from context")
|
|
return
|
|
}
|
|
|
|
detail := &audit.EventDetail{
|
|
Message: fmt.Sprintf("Organization %s %sd", name, action),
|
|
Meta: map[string]string{
|
|
"organization_name": name,
|
|
},
|
|
}
|
|
if err := audit.CreateV1Event(al, sd, detail, fmt.Sprintf("organization.%s.success", action), ""); err != nil {
|
|
_log.Warn("unable to create audit event", err)
|
|
}
|
|
|
|
if settingsBefore == nil && settingsAfter == nil {
|
|
return
|
|
}
|
|
|
|
bavail := settingsBefore != nil && settingsAfter != nil
|
|
if !bavail || settingsBefore.IdleLogoutMin != settingsAfter.IdleLogoutMin {
|
|
detail := &audit.EventDetail{
|
|
Message: fmt.Sprintf("Idel logout settings updated for organization %s", name),
|
|
Meta: map[string]string{
|
|
"organization_name": name,
|
|
},
|
|
}
|
|
|
|
if settingsAfter != nil {
|
|
detail.Meta = map[string]string{
|
|
"organization_name": name,
|
|
"idle_logout_min": string(settingsAfter.IdleLogoutMin),
|
|
}
|
|
}
|
|
|
|
if err := audit.CreateV1Event(al, sd, detail, "organization.idle.timeout.settings.updated", ""); err != nil {
|
|
_log.Warn("unable to create audit event", err)
|
|
}
|
|
}
|
|
|
|
bavail = bavail && settingsBefore.Lockout != nil && settingsAfter.Lockout != nil
|
|
|
|
if !bavail ||
|
|
settingsBefore.Lockout.Enabled != settingsAfter.Lockout.Enabled ||
|
|
settingsBefore.Lockout.PeriodMin != settingsAfter.Lockout.PeriodMin ||
|
|
settingsBefore.Lockout.Attempts != settingsAfter.Lockout.Attempts {
|
|
|
|
enabled := "false"
|
|
detail := &audit.EventDetail{
|
|
Message: fmt.Sprintf("Lockout settings updated for organization %s", name),
|
|
Meta: map[string]string{
|
|
"organization_name": name,
|
|
},
|
|
}
|
|
|
|
if settingsAfter != nil && settingsAfter.Lockout != nil {
|
|
if settingsAfter.Lockout.Enabled {
|
|
enabled = "true"
|
|
}
|
|
detail.Meta = map[string]string{
|
|
"organization_name": name,
|
|
"lockout_enabled": enabled,
|
|
"lockout_period_min": string(settingsAfter.Lockout.PeriodMin),
|
|
"lockout_attempts": string(settingsAfter.Lockout.Attempts),
|
|
}
|
|
}
|
|
|
|
if err := audit.CreateV1Event(al, sd, detail, "organization.lockout.settings.updated", ""); err != nil {
|
|
_log.Warn("unable to create audit event", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func CreateIdpAuditEvent(ctx context.Context, al *zap.Logger, action string, name string, id uuid.UUID) {
|
|
sd, ok := GetSessionDataFromContext(ctx)
|
|
if !ok {
|
|
_log.Warn("unable to create audit event: could not fetch info from context")
|
|
return
|
|
}
|
|
|
|
detail := &audit.EventDetail{
|
|
Message: fmt.Sprintf("Idp %s %sd", name, action),
|
|
Meta: map[string]string{
|
|
"idp_name": name,
|
|
},
|
|
}
|
|
// idp.create.success is idp.config.created in rcloud
|
|
if err := audit.CreateV1Event(al, sd, detail, fmt.Sprintf("idp.%s.success", action), ""); err != nil {
|
|
_log.Warn("unable to create audit event", err)
|
|
}
|
|
}
|
|
|
|
func CreateOidcAuditEvent(ctx context.Context, al *zap.Logger, action string, name string, id uuid.UUID) {
|
|
sd, ok := GetSessionDataFromContext(ctx)
|
|
if !ok {
|
|
_log.Warn("unable to create audit event: could not fetch info from context")
|
|
return
|
|
}
|
|
|
|
detail := &audit.EventDetail{
|
|
Message: fmt.Sprintf("Oidc %s %sd", name, action),
|
|
Meta: map[string]string{
|
|
"oidc_name": name,
|
|
},
|
|
}
|
|
|
|
if err := audit.CreateV1Event(al, sd, detail, fmt.Sprintf("oidc.%s.success", action), ""); err != nil {
|
|
_log.Warn("unable to create audit event", err)
|
|
}
|
|
}
|
|
|
|
func CreateApiKeyAuditEvent(ctx context.Context, al *zap.Logger, action string, id string) {
|
|
sd, ok := GetSessionDataFromContext(ctx)
|
|
if !ok {
|
|
_log.Warn("unable to create audit event: could not fetch info from context")
|
|
return
|
|
}
|
|
|
|
detail := &audit.EventDetail{
|
|
Message: fmt.Sprintf("ApiKey %s %sd", id, action),
|
|
Meta: map[string]string{
|
|
"apikey": id,
|
|
},
|
|
}
|
|
if err := audit.CreateV1Event(al, sd, detail, fmt.Sprintf("apikey.%s.success", action), ""); err != nil {
|
|
_log.Warn("unable to create audit event", err)
|
|
}
|
|
}
|
|
|
|
func CreateClusterAuditEvent(ctx context.Context, al *zap.Logger, action string, name string, id uuid.UUID) {
|
|
sd, ok := GetSessionDataFromContext(ctx)
|
|
if !ok {
|
|
_log.Warn("unable to create audit event: could not fetch info from context")
|
|
return
|
|
}
|
|
|
|
detail := &audit.EventDetail{
|
|
Message: fmt.Sprintf("Cluster %s %sd", name, action),
|
|
Meta: map[string]string{
|
|
"cluster_name": name,
|
|
},
|
|
}
|
|
if err := audit.CreateV1Event(al, sd, detail, fmt.Sprintf("cluster.%s.success", action), ""); err != nil {
|
|
_log.Warn("unable to create audit event", err)
|
|
}
|
|
}
|
|
|
|
// TODO: figure out how this is to be added
|
|
func CreateLocationAuditEvent(ctx context.Context, al *zap.Logger, action string, name string, id uuid.UUID) {
|
|
sd, ok := GetSessionDataFromContext(ctx)
|
|
if !ok {
|
|
_log.Warn("unable to create audit event: could not fetch info from context")
|
|
return
|
|
}
|
|
|
|
detail := &audit.EventDetail{
|
|
Message: fmt.Sprintf("Location %s %sd", name, action),
|
|
Meta: map[string]string{
|
|
"location_name": name,
|
|
},
|
|
}
|
|
if err := audit.CreateV1Event(al, sd, detail, fmt.Sprintf("location.%s.success", action), ""); err != nil {
|
|
_log.Warn("unable to create audit event", err)
|
|
}
|
|
}
|