From ed3237a58c64208dcb2ae37f0ffeaa9b889fce0c Mon Sep 17 00:00:00 2001 From: Abin Simon Date: Wed, 8 Jun 2022 18:47:11 +0530 Subject: [PATCH 1/4] Fix identities file typo --- _kratos/identity.schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_kratos/identity.schema.json b/_kratos/identity.schema.json index 082a42d..6b6990e 100644 --- a/_kratos/identity.schema.json +++ b/_kratos/identity.schema.json @@ -38,7 +38,7 @@ }, "idp_group": { "title": "IDP group", - "type": "string", + "type": "string" } }, "required": [ From 4a38e1ee9a3ab3c2bc33f69da1d7ce0786ec2c57 Mon Sep 17 00:00:00 2001 From: Abin Simon Date: Wed, 8 Jun 2022 18:47:28 +0530 Subject: [PATCH 2/4] Drop unecessary logging now that dev flag is remvoved for auth --- main.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/main.go b/main.go index 1830e72..643216a 100644 --- a/main.go +++ b/main.go @@ -581,8 +581,6 @@ func runRPC(wg *sync.WaitGroup, ctx context.Context) { } var opts []_grpc.ServerOption - // var asv authv3.AuthService - _log.Infow("adding auth interceptor") ac := authv3.NewAuthContext(db, kc, ks, as) asv := authv3.NewAuthService(ac) o := authv3.Option{ From 38f937bfcf5dac890efccd9e53091a8d27732ba0 Mon Sep 17 00:00:00 2001 From: Abin Simon Date: Wed, 8 Jun 2022 19:19:57 +0530 Subject: [PATCH 3/4] User GetM instead of GetByID when fetching user This is necessary as we do not have `trash` in case of user and GetByID explects that column to be available. --- pkg/service/user.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/service/user.go b/pkg/service/user.go index e4728fe..184f811 100644 --- a/pkg/service/user.go +++ b/pkg/service/user.go @@ -514,7 +514,7 @@ func (s *userService) GetByID(ctx context.Context, user *userv3.User) (*userv3.U if err != nil { return &userv3.User{}, err } - entity, err := dao.GetByID(ctx, s.db, uid, &models.KratosIdentities{}) + entity, err := dao.GetM(ctx, s.db, map[string]interface{}{"id": uid}, &models.KratosIdentities{}) if err != nil { return &userv3.User{}, err } From 5274a5861c25ea5c8859791bd0c1eddec7a9d42b Mon Sep 17 00:00:00 2001 From: Abin Simon Date: Wed, 8 Jun 2022 19:21:07 +0530 Subject: [PATCH 4/4] Add audit log for kubeconfig revoke --- main.go | 2 +- pkg/service/audit_utils.go | 18 +++++++++++ pkg/service/kubeconfig_revocation.go | 38 +++++++++++++++++------ pkg/service/kubeconfig_revocation_test.go | 2 +- 4 files changed, 48 insertions(+), 12 deletions(-) diff --git a/main.go b/main.go index 643216a..6a57934 100644 --- a/main.go +++ b/main.go @@ -344,7 +344,7 @@ func setup() { //sentry related services bs = service.NewBootstrapService(db) - krs = service.NewKubeconfigRevocationService(db) + krs = service.NewKubeconfigRevocationService(db, auditLogger) kss = service.NewKubeconfigSettingService(db) ns = service.NewNamespaceService(db) kcs = service.NewkubectlClusterSettingsService(db) diff --git a/pkg/service/audit_utils.go b/pkg/service/audit_utils.go index 5c2b0fe..38decb3 100644 --- a/pkg/service/audit_utils.go +++ b/pkg/service/audit_utils.go @@ -389,6 +389,24 @@ func CreateApiKeyAuditEvent(ctx context.Context, al *zap.Logger, action string, } } +func RevokeKubeconfigAuditEvent(ctx context.Context, al *zap.Logger, user 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("User %s kubeconfig revoked", user), + Meta: map[string]string{ + "user": user, + }, + } + if err := audit.CreateV1Event(al, sd, detail, "user.kubeconfig.revoke", ""); 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 { diff --git a/pkg/service/kubeconfig_revocation.go b/pkg/service/kubeconfig_revocation.go index ef80b36..a0e115e 100644 --- a/pkg/service/kubeconfig_revocation.go +++ b/pkg/service/kubeconfig_revocation.go @@ -3,6 +3,7 @@ package service import ( "context" "database/sql" + "fmt" "time" "github.com/RafayLabs/rcloud-base/internal/constants" @@ -11,6 +12,7 @@ import ( "github.com/RafayLabs/rcloud-base/proto/types/sentry" "github.com/google/uuid" "github.com/uptrace/bun" + "go.uber.org/zap" "google.golang.org/protobuf/types/known/timestamppb" ) @@ -23,11 +25,12 @@ type KubeconfigRevocationService interface { // bootstrapService implements BootstrapService type kubeconfigRevocationService struct { db *bun.DB + al *zap.Logger } // NewKubeconfigRevocation return new kubeconfig revocation service -func NewKubeconfigRevocationService(db *bun.DB) KubeconfigRevocationService { - return &kubeconfigRevocationService{db} +func NewKubeconfigRevocationService(db *bun.DB, al *zap.Logger) KubeconfigRevocationService { + return &kubeconfigRevocationService{db, al} } func (krs *kubeconfigRevocationService) Get(ctx context.Context, orgID string, accountID string, isSSOUser bool) (*sentry.KubeconfigRevocation, error) { @@ -52,15 +55,30 @@ func prepareKubeCfgRevocationResponse(kr *models.KubeconfigRevocation) *sentry.K } func (krs *kubeconfigRevocationService) Patch(ctx context.Context, kr *sentry.KubeconfigRevocation) error { - return krs.db.RunInTx(ctx, &sql.TxOptions{}, func(ctx context.Context, tx bun.Tx) error { - _, err := dao.GetKubeconfigRevocation(ctx, tx, uuid.MustParse(kr.OrganizationID), uuid.MustParse(kr.AccountID), kr.IsSSOUser) - if err != nil && err == sql.ErrNoRows { - kcr := convertToModel(kr) - kcr.CreatedAt = time.Now() - return dao.CreateKubeconfigRevocation(ctx, tx, kcr) + accId := uuid.MustParse(kr.AccountID) + entity, err := dao.GetM(ctx, krs.db, map[string]interface{}{"id": accId}, &models.KratosIdentities{}) + if err != nil { + return err + } + if usr, ok := entity.(*models.KratosIdentities); ok { + // We need user info inorder to add the audit log + err = krs.db.RunInTx(ctx, &sql.TxOptions{}, func(ctx context.Context, tx bun.Tx) error { + _, err := dao.GetKubeconfigRevocation(ctx, tx, uuid.MustParse(kr.OrganizationID), accId, kr.IsSSOUser) + if err != nil && err == sql.ErrNoRows { + kcr := convertToModel(kr) + kcr.CreatedAt = time.Now() + return dao.CreateKubeconfigRevocation(ctx, tx, kcr) + } + return dao.UpdateKubeconfigRevocation(ctx, tx, convertToModel(kr)) + }) + if err != nil { + return err } - return dao.UpdateKubeconfigRevocation(ctx, tx, convertToModel(kr)) - }) + RevokeKubeconfigAuditEvent(ctx, krs.al, getUserTraits(usr.Traits).Email) + return nil + } + + return fmt.Errorf("unable to fetch user") } func convertToModel(kr *sentry.KubeconfigRevocation) *models.KubeconfigRevocation { diff --git a/pkg/service/kubeconfig_revocation_test.go b/pkg/service/kubeconfig_revocation_test.go index 0b92e21..1aab041 100644 --- a/pkg/service/kubeconfig_revocation_test.go +++ b/pkg/service/kubeconfig_revocation_test.go @@ -12,7 +12,7 @@ func TestGetKubeconfigRevocation(t *testing.T) { db, mock := getDB(t) defer db.Close() - ps := NewKubeconfigRevocationService(db) + ps := NewKubeconfigRevocationService(db, getLogger()) ouuid := uuid.New().String() cuuid := uuid.New().String()