diff --git a/apis/cmk/cmk-ui.yaml b/apis/cmk/cmk-ui.yaml index f12646a8..a1f2d90a 100644 --- a/apis/cmk/cmk-ui.yaml +++ b/apis/cmk/cmk-ui.yaml @@ -1894,9 +1894,6 @@ components: enabled: description: Flag indicating whether the Key is enabled type: boolean - isPrimary: - description: Flag indicating whether this Key is the primary (default) key for its associated key configuration. - type: boolean accessDetails: $ref: "#/components/schemas/KeyAccessDetails" additionalProperties: false @@ -2239,6 +2236,11 @@ components: type: string maxLength: 4096 example: This Key Configuration is used for connecting with Systems in Europe. + primaryKeyID: + description: The ID of the primary key of the configuration + type: string + format: uuid + example: 12345678-90ab-cdef-1234-567890abcdef additionalProperties: false KeyConfigurationKeyAdd: type: object diff --git a/cmd/task-worker/main.go b/cmd/task-worker/main.go index 0f2c99ed..f2367777 100644 --- a/cmd/task-worker/main.go +++ b/cmd/task-worker/main.go @@ -154,7 +154,7 @@ func registerTasks( certManager := manager.NewCertificateManager(ctx, r, svcRegistry, cfg) tenantConfigManager := manager.NewTenantConfigManager(r, svcRegistry, cfg) tagManager := manager.NewTagManager(r) - keyConfigManager := manager.NewKeyConfigManager(r, certManager, userManager, tagManager, cmkAuditor, cfg) + keyConfigManager := manager.NewKeyConfigManager(r, certManager, userManager, tagManager, cmkAuditor, eventFactory, cfg) keyManager := manager.NewKeyManager( r, svcRegistry, tenantConfigManager, keyConfigManager, userManager, certManager, eventFactory, cmkAuditor) systemManager := manager.NewSystemManager(ctx, r, nil, eventFactory, svcRegistry, cfg, keyConfigManager, userManager) diff --git a/cmd/tenant-manager-cli/cli_test.go b/cmd/tenant-manager-cli/cli_test.go index 8d40fc78..a0a0c4fb 100644 --- a/cmd/tenant-manager-cli/cli_test.go +++ b/cmd/tenant-manager-cli/cli_test.go @@ -79,7 +79,7 @@ func (s *CLISuite) SetupSuite() { cm := manager.NewCertificateManager(ctx, r, svcRegistry, cfg) um := manager.NewUserManager(r, cmkAuditor) tagm := manager.NewTagManager(r) - kcm := manager.NewKeyConfigManager(r, cm, um, tagm, cmkAuditor, cfg) + kcm := manager.NewKeyConfigManager(r, cm, um, tagm, cmkAuditor, eventFactory, cfg) sys := manager.NewSystemManager( ctx, diff --git a/cmd/tenant-manager-cli/commands/commands.go b/cmd/tenant-manager-cli/commands/commands.go index 51e400c6..02e5c385 100644 --- a/cmd/tenant-manager-cli/commands/commands.go +++ b/cmd/tenant-manager-cli/commands/commands.go @@ -46,7 +46,7 @@ func NewCommandFactory( cm := manager.NewCertificateManager(ctx, r, svcRegistry, cfg) um := manager.NewUserManager(r, cmkAuditor) tagm := manager.NewTagManager(r) - kcm := manager.NewKeyConfigManager(r, cm, um, tagm, cmkAuditor, cfg) + kcm := manager.NewKeyConfigManager(r, cm, um, tagm, cmkAuditor, eventFactory, cfg) sys := manager.NewSystemManager( ctx, diff --git a/cmd/tenant-manager/main.go b/cmd/tenant-manager/main.go index a6565535..7645ad9b 100644 --- a/cmd/tenant-manager/main.go +++ b/cmd/tenant-manager/main.go @@ -134,7 +134,7 @@ func createTenantManager( um := manager.NewUserManager(r, cmkAuditor) tagm := manager.NewTagManager(r) - kcm := manager.NewKeyConfigManager(r, cm, um, tagm, cmkAuditor, cfg) + kcm := manager.NewKeyConfigManager(r, cm, um, tagm, cmkAuditor, eventFactory, cfg) sys := manager.NewSystemManager( ctx, diff --git a/internal/api/cmkapi/cmkapi.go b/internal/api/cmkapi/cmkapi.go index 685e643f..81f73932 100644 --- a/internal/api/cmkapi/cmkapi.go +++ b/internal/api/cmkapi/cmkapi.go @@ -534,6 +534,9 @@ type KeyConfigurationPatch struct { // Name The name of the Key Configuration Name *string `json:"name,omitempty"` + + // PrimaryKeyID The ID of the primary key of the configuration + PrimaryKeyID *openapi_types.UUID `json:"primaryKeyID,omitempty"` } // KeyID The ID of the Key @@ -581,9 +584,6 @@ type KeyPatch struct { // Enabled Flag indicating whether the Key is enabled Enabled *bool `json:"enabled,omitempty"` - // IsPrimary Flag indicating whether this Key is the primary (default) key for its associated key configuration. - IsPrimary *bool `json:"isPrimary,omitempty"` - // Name The name of the Key Name *string `json:"name,omitempty"` } @@ -6713,120 +6713,120 @@ var swaggerSpec = []string{ "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", - "JHWTmC6pl+Th54f/HwAA//9cyaYuagsBAA==", + "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", + "iS8kdZOYLqmX5OHnh/8fAAD//6D66IJ4CwEA", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/apierrors/key.go b/internal/apierrors/key.go index ef4ddf80..3a6671a9 100644 --- a/internal/apierrors/key.go +++ b/internal/apierrors/key.go @@ -80,14 +80,6 @@ var key = []errs.ExposedErrors[*APIError]{ Status: http.StatusInternalServerError, }, }, - { - InternalErrorChain: []error{manager.ErrPrimaryKeyUnmark}, - ExposedError: &APIError{ - Code: "PRIMARY_KEY_UNMARK", - Message: "Primary key cannot be unmarked primary", - Status: http.StatusForbidden, - }, - }, { InternalErrorChain: []error{manager.ErrGetKeyDB, gorm.ErrRecordNotFound}, ExposedError: &APIError{ diff --git a/internal/controllers/cmk/key_controller.go b/internal/controllers/cmk/key_controller.go index f3ef98bd..adf9cb49 100644 --- a/internal/controllers/cmk/key_controller.go +++ b/internal/controllers/cmk/key_controller.go @@ -72,7 +72,7 @@ func (c *APIController) GetKeys(ctx context.Context, Count: ptr.GetSafeDeref(request.Params.Count), } - keys, total, err := c.Manager.Keys.GetKeys(ctx, ptr.PointTo(keyConfigID), pagination) + keys, total, err := c.Manager.Keys.GetKeys(ctx, keyConfigID, pagination) if err != nil { return nil, errs.Wrap(apierrors.ErrQueryKeyList, err) } @@ -134,16 +134,6 @@ func (c *APIController) GetKeysKeyID(ctx context.Context, func (c *APIController) UpdateKey(ctx context.Context, request cmkapi.UpdateKeyRequestObject, ) (cmkapi.UpdateKeyResponseObject, error) { - if ptr.GetSafeDeref(request.Body.IsPrimary) { - required, err := c.Manager.Workflow.IsWorkflowRequired(ctx) - if err != nil { - return nil, err - } - - if required { - return nil, apierrors.ErrActionRequireWorkflow - } - } dbKey, err := c.Manager.Keys.UpdateKey(ctx, request.KeyID, *request.Body) if err != nil { return nil, errs.Wrap(apierrors.ErrUpdateKey, err) diff --git a/internal/controllers/cmk/key_controller_test.go b/internal/controllers/cmk/key_controller_test.go index 029aab68..92105d1f 100644 --- a/internal/controllers/cmk/key_controller_test.go +++ b/internal/controllers/cmk/key_controller_test.go @@ -629,21 +629,29 @@ func TestKeyControllerDeleteKeysKeyID(t *testing.T) { authClient := testutils.NewAuthClient(ctx, t, r, testutils.WithKeyAdminRole()) - keyConfig := testutils.NewKeyConfig(func(_ *model.KeyConfiguration) {}, - testutils.WithAuthClientDataKC(authClient)) + keyConfig := testutils.NewKeyConfig( + func(k *model.KeyConfiguration) {}, + testutils.WithAuthClientDataKC(authClient), + ) key := testutils.NewKey(func(k *model.Key) { k.KeyConfigurationID = keyConfig.ID }) - keyConfigWSys := testutils.NewKeyConfig(func(_ *model.KeyConfiguration) {}, - testutils.WithAuthClientDataKC(authClient)) + pKeyID := uuid.New() + keyConfigWSys := testutils.NewKeyConfig( + func(k *model.KeyConfiguration) { + k.PrimaryKeyID = ptr.PointTo(pKeyID) + }, + testutils.WithAuthClientDataKC(authClient), + ) sys := testutils.NewSystem(func(s *model.System) { s.KeyConfigurationID = ptr.PointTo(keyConfigWSys.ID) + s.Status = cmkapi.SystemStatusCONNECTED }) pkey := testutils.NewKey(func(k *model.Key) { - k.IsPrimary = true k.KeyConfigurationID = keyConfigWSys.ID + k.ID = pKeyID }) testutils.CreateTestEntities( @@ -744,7 +752,10 @@ func TestKeyControllerUpdateKey(t *testing.T) { authClient := testutils.NewAuthClient(ctx, t, r, testutils.WithKeyAdminRole()) - kc := testutils.NewKeyConfig(func(_ *model.KeyConfiguration) {}, + keyID := uuid.New() + kc := testutils.NewKeyConfig(func(k *model.KeyConfiguration) { + k.PrimaryKeyID = ptr.PointTo(keyID) + }, testutils.WithAuthClientDataKC(authClient)) sysFailed := testutils.NewSystem(func(sys *model.System) { @@ -760,7 +771,7 @@ func TestKeyControllerUpdateKey(t *testing.T) { }) key := testutils.NewKey(func(k *model.Key) { - k.IsPrimary = true + k.ID = keyID k.CryptoAccessData = cryptoData k.ManagementAccessData = json.RawMessage("{\"test\":\"test\"}") k.KeyConfigurationID = kc.ID @@ -847,21 +858,10 @@ func TestKeyControllerUpdateKey(t *testing.T) { expectedName: "", expectedDesc: "", }, - { - name: "Should error on unmark primary key", - keyID: key.ID.String(), - input: cmkapi.KeyPatch{ - IsPrimary: ptr.PointTo(false), - }, - expectedStatus: http.StatusForbidden, - expectedName: "", - expectedDesc: "", - }, { name: "Should code 403 on management role update", keyID: key.ID.String(), input: cmkapi.KeyPatch{ - IsPrimary: ptr.PointTo(false), AccessDetails: &cmkapi.KeyAccessDetails{ Management: &map[string]any{ "a": "b", @@ -906,14 +906,6 @@ func TestKeyControllerUpdateKey(t *testing.T) { expectedName: "updated-key", expectedDesc: "updated description", }, - { - name: "Should 403 when update primary key and workflow is required", - keyID: key.ID.String(), - input: cmkapi.KeyPatch{ - IsPrimary: ptr.PointTo(true), - }, - expectedStatus: http.StatusForbidden, - }, } for _, tt := range tests { diff --git a/internal/controllers/cmk/keyconfiguration_controller.go b/internal/controllers/cmk/keyconfiguration_controller.go index c3393df6..dc951a7e 100644 --- a/internal/controllers/cmk/keyconfiguration_controller.go +++ b/internal/controllers/cmk/keyconfiguration_controller.go @@ -132,10 +132,28 @@ func (c *APIController) GetKeyConfigurationByID( } // UpdateKeyConfigurationByID updates a key configuration by ID +// +//nolint:nestif func (c *APIController) UpdateKeyConfigurationByID( ctx context.Context, request cmkapi.UpdateKeyConfigurationByIDRequestObject, ) (cmkapi.UpdateKeyConfigurationByIDResponseObject, error) { + if request.Body.PrimaryKeyID != nil { + required, err := c.Manager.Workflow.IsWorkflowRequired(ctx) + if err != nil { + return nil, err + } + + if required { + kc, err := c.Manager.KeyConfig.GetKeyConfigurationByID(ctx, request.KeyConfigurationID) + if err != nil { + return nil, err + } + if kc.PrimaryKeyID != nil && *kc.PrimaryKeyID != *request.Body.PrimaryKeyID { + return nil, apierrors.ErrActionRequireWorkflow + } + } + } keyConfig, err := c.Manager.KeyConfig.UpdateKeyConfigurationByID(ctx, request.KeyConfigurationID, *request.Body) if err != nil { return nil, err diff --git a/internal/controllers/cmk/keyconfiguration_controller_test.go b/internal/controllers/cmk/keyconfiguration_controller_test.go index 3943c6fc..373f29e7 100644 --- a/internal/controllers/cmk/keyconfiguration_controller_test.go +++ b/internal/controllers/cmk/keyconfiguration_controller_test.go @@ -36,10 +36,7 @@ import ( ) func startAPIKeyConfig(t *testing.T) ( - cmkapi.ServeMux, - string, - context.Context, - *sql.ResourceRepository, + cmkapi.ServeMux, string, context.Context, *sql.ResourceRepository, ) { t.Helper() db, tenants, _ := testutils.NewTestDB(t, testutils.TestDBConfig{}) @@ -49,7 +46,6 @@ func startAPIKeyConfig(t *testing.T) ( sv := testutils.NewAPIServer(t, db, testutils.TestAPIServerConfig{ Plugins: []catalog.BuiltInPlugin{testplugins.NewIdentityManagement()}, }) - ctx := cmkcontext.CreateTenantContext(t.Context(), tenant) r := sql.NewRepository(db) @@ -430,7 +426,7 @@ func TestKeyConfigurationController_UpdateByID(t *testing.T) { type testCase struct { name string - configID string + keyConfigID string inputJSON string expectedStatus int expectedBody string @@ -441,8 +437,8 @@ func TestKeyConfigurationController_UpdateByID(t *testing.T) { tests := []testCase{ { - name: "KeyConfigPATCH_Success_WithoutClientDataUserGroups (backward compatibility)", - configID: keyConfig.ID.String(), + name: "KeyConfigPATCH_Success_WithoutClientDataUserGroups (backward compatibility)", + keyConfigID: keyConfig.ID.String(), inputJSON: `{ "name": "updated-config", "description": "updated description" @@ -459,8 +455,8 @@ func TestKeyConfigurationController_UpdateByID(t *testing.T) { }, }, { - name: "KeyConfigPATCH_NameOnly", - configID: keyConfig.ID.String(), + name: "KeyConfigPATCH_NameOnly", + keyConfigID: keyConfig.ID.String(), inputJSON: `{ "name": "updated-name-only" }`, @@ -469,8 +465,8 @@ func TestKeyConfigurationController_UpdateByID(t *testing.T) { additionalContext: authClient.GetClientMap(), }, { - name: "KeyConfigPATCH_WithClientDataUserGroups", - configID: keyConfig.ID.String(), + name: "KeyConfigPATCH_WithClientDataUserGroups", + keyConfigID: keyConfig.ID.String(), inputJSON: `{ "name": "updated-name-only-client-data" }`, @@ -480,8 +476,8 @@ func TestKeyConfigurationController_UpdateByID(t *testing.T) { testutils.WithAdditionalGroup(uuid.NewString())), }, { - name: "KeyConfigPATCH_Unauthorised_WithWrongClientDataUserGroups", - configID: keyConfig.ID.String(), + name: "KeyConfigPATCH_Unauthorised_WithWrongClientDataUserGroups", + keyConfigID: keyConfig.ID.String(), inputJSON: `{ "name": "updated-name-only-client-data" }`, @@ -491,8 +487,8 @@ func TestKeyConfigurationController_UpdateByID(t *testing.T) { additionalContext: authClient.GetClientMap(testutils.WithOverriddenGroup(2)), }, { - name: "KeyConfigPATCH_Unauthorised_WithEmptyClientDataUserGroups", - configID: keyConfig.ID.String(), + name: "KeyConfigPATCH_Unauthorised_WithEmptyClientDataUserGroups", + keyConfigID: keyConfig.ID.String(), inputJSON: `{ "name": "updated-name-only-client-data" }`, @@ -502,8 +498,8 @@ func TestKeyConfigurationController_UpdateByID(t *testing.T) { additionalContext: testutils.GetGrouplessClientMap(), }, { - name: "KeyConfigPATCH_DescriptionOnly", - configID: keyConfig.ID.String(), + name: "KeyConfigPATCH_DescriptionOnly", + keyConfigID: keyConfig.ID.String(), inputJSON: `{ "description": "updated description only" }`, @@ -512,8 +508,8 @@ func TestKeyConfigurationController_UpdateByID(t *testing.T) { additionalContext: authClient.GetClientMap(), }, { - name: "KeyConfigPATCH_EmptyName", - configID: keyConfig.ID.String(), + name: "KeyConfigPATCH_EmptyName", + keyConfigID: keyConfig.ID.String(), inputJSON: `{ "name": "" }`, @@ -522,8 +518,8 @@ func TestKeyConfigurationController_UpdateByID(t *testing.T) { additionalContext: authClient.GetClientMap(), }, { - name: "KeyConfigPATCH_AdminGroupIDNotAllowed", - configID: keyConfig.ID.String(), + name: "KeyConfigPATCH_AdminGroupIDNotAllowed", + keyConfigID: keyConfig.ID.String(), inputJSON: `{ "name": "updated-config", "adminGroupID": "` + newAdminGroupID.String() + `" @@ -540,8 +536,8 @@ func TestKeyConfigurationController_UpdateByID(t *testing.T) { additionalContext: authClient.GetClientMap(), }, { - name: "KeyConfigPATCH_NameConflict", - configID: keyConfig.ID.String(), + name: "KeyConfigPATCH_NameConflict", + keyConfigID: keyConfig.ID.String(), inputJSON: `{ "name": "existing-config" }`, @@ -551,8 +547,8 @@ func TestKeyConfigurationController_UpdateByID(t *testing.T) { additionalContext: authClient.GetClientMap(), }, { - name: "KeyConfigPATCH_InvalidID", - configID: "invalid-uuid", + name: "KeyConfigPATCH_InvalidID", + keyConfigID: "invalid-uuid", inputJSON: `{ "name": "updated-config" "adminGroupID": "invalid-id" @@ -561,8 +557,8 @@ func TestKeyConfigurationController_UpdateByID(t *testing.T) { expectedBody: "error", }, { - name: "KeyConfigPATCH_NotFound", - configID: uuid.New().String(), + name: "KeyConfigPATCH_NotFound", + keyConfigID: uuid.New().String(), inputJSON: `{ "name": "updated-config" }`, @@ -571,8 +567,8 @@ func TestKeyConfigurationController_UpdateByID(t *testing.T) { additionalContext: authClient.GetClientMap(), }, { - name: "KeyConfigPATCH_InvalidJSON", - configID: keyConfig.ID.String(), + name: "KeyConfigPATCH_InvalidJSON", + keyConfigID: keyConfig.ID.String(), inputJSON: `{ "name": "updated-config", invalid json @@ -581,13 +577,21 @@ func TestKeyConfigurationController_UpdateByID(t *testing.T) { expectedBody: "error", additionalContext: authClient.GetClientMap(), }, + { + name: "Should 403 when update primary key and workflow is required", + keyConfigID: keyConfig.ID.String(), + inputJSON: `{ + "primaryKeyID": "id" + }`, + expectedStatus: http.StatusForbidden, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { w := testutils.MakeHTTPRequest(t, sv, testutils.RequestOptions{ Method: http.MethodPatch, - Endpoint: "/keyConfigurations/" + tt.configID, + Endpoint: "/keyConfigurations/" + tt.keyConfigID, Tenant: tenant, Body: testutils.WithString(t, tt.inputJSON), AdditionalContext: tt.additionalContext, diff --git a/internal/manager/base.go b/internal/manager/base.go index f570220f..777ba826 100644 --- a/internal/manager/base.go +++ b/internal/manager/base.go @@ -49,7 +49,7 @@ func New( tenantConfigManager := NewTenantConfigManager(repo, svcRegistry, config) userManager := NewUserManager(repo, cmkAuditor) tagManager := NewTagManager(repo) - keyConfigManager := NewKeyConfigManager(repo, certManager, userManager, tagManager, cmkAuditor, config) + keyConfigManager := NewKeyConfigManager(repo, certManager, userManager, tagManager, cmkAuditor, eventFactory, config) keyManager := NewKeyManager( repo, svcRegistry, diff --git a/internal/manager/errors.go b/internal/manager/errors.go index b501a037..b8f23c89 100644 --- a/internal/manager/errors.go +++ b/internal/manager/errors.go @@ -40,7 +40,6 @@ var ( ErrGetImportParamsFromProvider = errors.New("failed to get import parameters from provider") ErrImportKeyMaterialsToProvider = errors.New("failed to import key materials to provider") ErrKeyIsNotEnabled = errors.New("key is not enabled") - ErrPrimaryKeyUnmark = errors.New("primary key cannot be unmarked primary") ErrGetKeyDB = errors.New("failed to get key from database") ErrGettingKeyByID = errors.New("failed to get key by ID") diff --git a/internal/manager/key.go b/internal/manager/key.go index 8738ebfc..a7dc12d0 100644 --- a/internal/manager/key.go +++ b/internal/manager/key.go @@ -115,26 +115,22 @@ func (km *KeyManager) Create( return nil, err } - // Set as primary if this is the first key - if err := km.setPrimaryIfFirstKey(ctx, key); err != nil { - return nil, errs.Wrap(ErrUpdatePrimary, err) - } - - // Save key to database and create initial version for HYOK keys - // Both operations are wrapped in a transaction to ensure atomicity - err = km.repo.Transaction(ctx, func(txCtx context.Context) error { - // Create the key - if err := km.createKey(txCtx, key); err != nil { - return err + err = km.repo.Transaction(ctx, func(ctx context.Context) error { + err = km.setPrimaryIfFirstKey(ctx, key) + if err != nil { + return errs.Wrap(ErrUpdatePrimary, err) + } + err := km.repo.Create(ctx, key) + if err != nil { + return errs.Wrap(ErrCreateKeyDB, err) } // For HYOK keys, create initial version from keystore response if key.KeyType == constants.KeyTypeHYOK && keyResp != nil { - if err := km.syncKeyVersion(txCtx, key, keyResp); err != nil { + if err := km.syncKeyVersion(ctx, key, keyResp); err != nil { return errs.Wrap(ErrCreateKeyVersionDB, err) } } - return nil }) if err != nil { @@ -166,6 +162,12 @@ func (km *KeyManager) Get(ctx context.Context, keyID uuid.UUID) (*model.Key, err return nil, errs.Wrap(ErrGetKeyDB, err) } + isPrimary, err := repo.IsPrimaryKey(ctx, km.repo, key) + if err != nil { + return nil, errs.Wrap(ErrGetKeyDB, err) + } + key.IsPrimary = isPrimary + _, err = km.user.HasKeyAccess(ctx, authz.APIActionRead, key.KeyConfigurationID) if err != nil { return nil, err @@ -192,31 +194,42 @@ func (km *KeyManager) Get(ctx context.Context, keyID uuid.UUID) (*model.Key, err func (km *KeyManager) GetKeys( ctx context.Context, - keyConfigID *uuid.UUID, + keyConfigID uuid.UUID, pagination repo.Pagination, ) ([]*model.Key, int, error) { query := repo.NewQuery(). Preload(repo.Preload{"KeyVersions"}) - if keyConfigID != nil { - _, err := km.user.HasKeyAccess(ctx, authz.APIActionRead, *keyConfigID) - if err != nil { - return nil, 0, err - } + _, err := km.user.HasKeyAccess(ctx, authz.APIActionRead, keyConfigID) + if err != nil { + return nil, 0, err + } - _, err = km.keyConfigManager.GetKeyConfigurationByID(ctx, *keyConfigID) - if err != nil { - return nil, 0, errs.Wrap(ErrKeyConfigurationNotFound, err) - } + primaryKeyID, err := repo.GetKeyConfigPrimaryKey(ctx, km.repo, keyConfigID) + if err != nil { + return nil, 0, err + } + + ck := repo.NewCompositeKey().Where(fmt.Sprintf("%s.%s", model.Key{}.TableName(), repo.KeyConfigIDField), keyConfigID) + query = query.Where(repo.NewCompositeKeyGroup(ck)) - ck := repo.NewCompositeKey().Where(fmt.Sprintf("%s.%s", model.Key{}.TableName(), repo.KeyConfigIDField), keyConfigID) - query = query.Where(repo.NewCompositeKeyGroup(ck)) + keys, count, err := repo.ListAndCount(ctx, km.repo, pagination, model.Key{}, query) + if err != nil { + return nil, 0, err + } + + // All are non primary + if primaryKeyID == nil { + return keys, count, nil } - return repo.ListAndCount(ctx, km.repo, pagination, model.Key{}, query) + for _, k := range keys { + k.IsPrimary = *primaryKeyID == k.ID + } + + return keys, count, nil } -//nolint:cyclop func (km *KeyManager) UpdateKey(ctx context.Context, keyID uuid.UUID, keyPatch cmkapi.KeyPatch) (*model.Key, error) { if isManagementDetailsUpdate(keyPatch) { return nil, ErrManagementDetailsUpdate @@ -241,19 +254,6 @@ func (km *KeyManager) UpdateKey(ctx context.Context, keyID uuid.UUID, keyPatch c enablementUpdated := copyFieldsToModelKey(keyPatch, key) err = km.repo.Transaction(ctx, func(ctx context.Context) error { - if keyPatch.IsPrimary != nil { - if key.IsPrimary && !*keyPatch.IsPrimary { - return ErrPrimaryKeyUnmark - } - - err := km.setPrimaryKey(ctx, key) - if err != nil { - return errs.Wrap(ErrUpdateKeyDB, err) - } - - key.IsPrimary = *keyPatch.IsPrimary - } - _, err := km.repo.Patch(ctx, key, *repo.NewQuery().UpdateAll(true)) if err != nil { return errs.Wrap(ErrUpdateKeyDB, err) @@ -538,34 +538,6 @@ func (km *KeyManager) handleCryptoDetailsUpdate( return nil } -func (km *KeyManager) createKey(ctx context.Context, key *model.Key) error { - err := km.repo.Transaction(ctx, func(ctx context.Context) error { - // Create Key - err := km.repo.Create(ctx, key) - if err != nil { - return errs.Wrap(ErrCreateKeyDB, err) - } - - if key.IsPrimary { - _, err = km.repo.Patch( - ctx, - &model.KeyConfiguration{ID: key.KeyConfigurationID, PrimaryKeyID: &key.ID}, - *repo.NewQuery().Update(repo.PrimaryKeyIDField), - ) - if err != nil { - return errs.Wrap(ErrUpdateKeyConfigurationDB, err) - } - } - - return nil - }) - if err != nil { - return errs.Wrap(ErrCreateKeyDB, err) - } - - return nil -} - func (km *KeyManager) createManagedProviderKey( ctx context.Context, key *model.Key, @@ -754,48 +726,18 @@ func (km *KeyManager) setPrimaryIfFirstKey(ctx context.Context, key *model.Key) return err } + // Update keyconfig primaryKey if !exist { - key.IsPrimary = true - } - - return nil -} - -func (km *KeyManager) getPrimaryKeys(ctx context.Context, keyConfigID *uuid.UUID) ([]*model.Key, error) { - keys := []*model.Key{} - - err := km.repo.List( - ctx, - model.Key{}, - &keys, - *repo.NewQuery().Where( - repo.NewCompositeKeyGroup( - repo.NewCompositeKey().Where( - repo.IsPrimaryField, true).Where( - repo.KeyConfigIDField, keyConfigID))), - ) - if err != nil { - return nil, errs.Wrap(ErrGetPrimaryKeyVersionDB, err) - } - - return keys, nil -} - -func (km *KeyManager) removePrimaryKeyState(ctx context.Context, keyConfigID *uuid.UUID) error { - keys, err := km.getPrimaryKeys(ctx, keyConfigID) - if err != nil { - return err - } - - for _, k := range keys { - k.IsPrimary = false - - _, err := km.repo.Patch( - ctx, - k, - *repo.NewQuery().Update(repo.IsPrimaryField)) + if key.State == string(cmkapi.KeyStateDISABLED) { + return ErrKeyIsNotEnabled + } + keyConfig := &model.KeyConfiguration{ + ID: key.KeyConfigurationID, + PrimaryKeyID: &key.ID, + } + _, err := km.repo.Patch(ctx, keyConfig, *repo.NewQuery()) if err != nil { - return errs.Wrap(ErrUpdatePrimary, err) + return err } } @@ -992,51 +934,6 @@ func (km *KeyManager) importProviderKeyMaterial( return key, nil } -// Whenever Keyconfig PrimaryKey switches, systems need to send switch events -// If systems had a previous switch event the event key needs to be updated for the retru -func (km *KeyManager) handleSystemsOnNewPrimaryKey(ctx context.Context, key *model.Key) error { - keyConfig := &model.KeyConfiguration{ID: key.KeyConfigurationID} - - _, err := km.repo.First(ctx, keyConfig, *repo.NewQuery()) - if err != nil { - return errs.Wrap(ErrGettingKeyConfigByID, err) - } - - err = km.updatePrimaryKeySystemEvents(ctx, ptr.GetSafeDeref(keyConfig.PrimaryKeyID).String(), key.ID.String()) - if err != nil { - return err - } - - // Send system switches for systems in keyconfig - query := repo.NewQuery().Where( - repo.NewCompositeKeyGroup( - repo.NewCompositeKey().Where( - repo.KeyConfigIDField, keyConfig.ID), - ), - ) - return repo.ProcessInBatch( - ctx, - km.repo, - query, - repo.DefaultLimit, - func(systems []*model.System) error { - for _, s := range systems { - _, err := km.eventFactory.SystemSwitchNewPrimaryKey( - ctx, - s, - key.ID.String(), - keyConfig.PrimaryKeyID.String(), - ) - if err != nil { - return err - } - } - - return nil - }, - ) -} - // handleSystemsOnKeyRotation sends SYSTEM_KEY_ROTATE events to all systems // connected to the key's KeyConfiguration. This is triggered when a primary key's // key material is rotated (new version detected). @@ -1081,68 +978,6 @@ func (km *KeyManager) handleSystemsOnKeyRotation(ctx context.Context, key *model ) } -// updateOldPKeySystemEvents updates keyTo for system event retries -// This can be done as now there is a new primary key and systems -// can only be linked to primary keys, the previous keyTo needs now -// updated the newly set primary key -func (km *KeyManager) updatePrimaryKeySystemEvents(ctx context.Context, oldPkey string, newPkey string) error { - query := repo.NewQuery().Where( - repo.NewCompositeKeyGroup( - repo.NewCompositeKey().Where( - repo.JSONBField(repo.DataField, "keyIDTo"), oldPkey), - ), - ) - return repo.ProcessInBatch(ctx, km.repo, query, repo.DefaultLimit, func(events []*model.Event) error { - for _, e := range events { - systemJobData, err := eventprocessor.GetSystemJobData(e) - if err != nil { - return err - } - - systemJobData.KeyIDTo = newPkey - bytes, err := json.Marshal(systemJobData) - if err != nil { - return err - } - - e.Data = bytes - _, err = km.repo.Patch(ctx, e, *repo.NewQuery()) - if err != nil { - return err - } - } - return nil - }) -} - -// Ensures only the updated key is primary and updates the keyconfig primaryKeyID -func (km *KeyManager) setPrimaryKey(ctx context.Context, key *model.Key) error { - if key.State != string(cmkapi.KeyStateENABLED) { - return ErrKeyIsNotEnabled - } - - err := km.removePrimaryKeyState(ctx, &key.KeyConfigurationID) - if err != nil { - return errs.Wrap(ErrUpdateKeyDB, err) - } - - err = km.handleSystemsOnNewPrimaryKey(ctx, key) - if err != nil { - return errs.Wrap(ErrFailedToReencryptSystem, err) - } - - _, err = km.repo.Patch( - ctx, - &model.KeyConfiguration{ID: key.KeyConfigurationID, PrimaryKeyID: &key.ID}, - *repo.NewQuery().Update(repo.PrimaryKeyIDField), - ) - if err != nil { - return errs.Wrap(ErrUpdateKeyDB, err) - } - - return nil -} - func (km *KeyManager) syncHYOKKeyState(ctx context.Context, key *model.Key) error { oldKeyState := key.State @@ -1253,8 +1088,13 @@ func (km *KeyManager) handleNewKeyVersion( // Send audit log for rotation detection km.sendRotateAuditLog(ctx, key) + isPrimary, err := repo.IsPrimaryKey(ctx, km.repo, key) + if err != nil { + return err + } + // Notify systems if this is a primary key - if key.IsPrimary { + if isPrimary { if err := km.handleSystemsOnKeyRotation(ctx, key); err != nil { // Log error but don't fail the version creation // Systems will get updated on next scheduled sync diff --git a/internal/manager/key_test.go b/internal/manager/key_test.go index 4c02d252..cef49f78 100644 --- a/internal/manager/key_test.go +++ b/internal/manager/key_test.go @@ -17,7 +17,6 @@ import ( "github.com/openkcm/cmk/internal/config" "github.com/openkcm/cmk/internal/constants" eventprocessor "github.com/openkcm/cmk/internal/event-processor" - "github.com/openkcm/cmk/internal/event-processor/proto" "github.com/openkcm/cmk/internal/manager" "github.com/openkcm/cmk/internal/model" cmkpluginregistry "github.com/openkcm/cmk/internal/pluginregistry" @@ -85,6 +84,9 @@ func SetupKeyTest(t *testing.T) ( cmkAuditor := auditor.New(ctx, cfg) + eventFactory, err := eventprocessor.NewEventFactory(ctx, cfg, r) + assert.NoError(t, err) + tenantConfigManager := manager.NewTenantConfigManager(r, svcRegistry, nil) certManager := manager.NewCertificateManager(ctx, r, svcRegistry, &config.Config{ @@ -92,10 +94,7 @@ func SetupKeyTest(t *testing.T) ( }) userManager := manager.NewUserManager(r, cmkAuditor) tagManager := manager.NewTagManager(r) - keyConfigManager := manager.NewKeyConfigManager(r, certManager, userManager, tagManager, cmkAuditor, cfg) - - eventFactory, err := eventprocessor.NewEventFactory(ctx, cfg, r) - require.NoError(t, err) + keyConfigManager := manager.NewKeyConfigManager(r, certManager, userManager, tagManager, cmkAuditor, eventFactory, cfg) km := manager.NewKeyManager( r, svcRegistry, tenantConfigManager, keyConfigManager, userManager, certManager, eventFactory, cmkAuditor) @@ -400,10 +399,8 @@ func TestSetFirstKeyPrimary(t *testing.T) { t.Run("Should set first key as primary", func(t *testing.T) { createdKey1 := createTestSystemManagedKey(t, km, ctx, keyConfig.ID) - assert.True(t, createdKey1.IsPrimary) - createdKey2 := createTestSystemManagedKey(t, km, ctx, keyConfig.ID) - assert.False(t, createdKey2.IsPrimary) + _ = createTestSystemManagedKey(t, km, ctx, keyConfig.ID) resKeyConfig := &model.KeyConfiguration{ID: keyConfig.ID, AdminGroup: model.Group{ID: uuid.New()}} _, err := r.First(ctx, resKeyConfig, *repo.NewQuery()) @@ -440,7 +437,6 @@ func TestEditableCryptoData(t *testing.T) { }) key := testutils.NewKey(func(k *model.Key) { - k.IsPrimary = false k.CryptoAccessData = cryptoData k.KeyConfigurationID = kc.ID }) @@ -456,7 +452,7 @@ func TestEditableCryptoData(t *testing.T) { }) t.Run("Should be editable on pkey only on failed regions", func(t *testing.T) { - kc := testutils.NewKeyConfig(func(_ *model.KeyConfiguration) {}) + kc := testutils.NewKeyConfig(func(kc *model.KeyConfiguration) {}) sysFailed := testutils.NewSystem(func(sys *model.System) { sys.KeyConfigurationID = ptr.PointTo(kc.ID) @@ -473,7 +469,6 @@ func TestEditableCryptoData(t *testing.T) { testutils.CreateTestEntities(ctx, t, r, kc, sysFailed, sysConnected) key := testutils.NewKey(func(k *model.Key) { - k.IsPrimary = true k.CryptoAccessData = cryptoData k.KeyConfigurationID = kc.ID }) @@ -759,7 +754,6 @@ func TestList(t *testing.T) { name string skip int top int - keyConfigID *uuid.UUID expectedCount int wantErr bool }{ @@ -767,15 +761,6 @@ func TestList(t *testing.T) { name: "List all keys", skip: 0, top: 10, - keyConfigID: nil, - expectedCount: 2, - wantErr: false, - }, - { - name: "List all keys from same keyConfig", - skip: 0, - top: 10, - keyConfigID: ptr.PointTo(keyConfig.ID), expectedCount: 2, wantErr: false, }, @@ -783,7 +768,6 @@ func TestList(t *testing.T) { name: "List with pagination", skip: 0, top: 1, - keyConfigID: nil, expectedCount: 2, wantErr: false, }, @@ -791,7 +775,7 @@ func TestList(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - results, total, err := km.GetKeys(ctx, nil, repo.Pagination{Skip: tt.skip, Top: tt.top, Count: true}) + results, total, err := km.GetKeys(ctx, keyConfig.ID, repo.Pagination{Skip: tt.skip, Top: tt.top, Count: true}) if tt.wantErr { assert.Error(t, err) @@ -891,18 +875,20 @@ func TestDelete(t *testing.T) { createdKey := createTestSystemManagedKey(t, km, ctx, keyConfig.ID) createdPrimaryKey, err := km.Create(ctx, testutils.NewKey(func(k *model.Key) { k.KeyConfigurationID = keyConfig.ID - k.IsPrimary = true })) require.NoError(t, err) byokKey := createTestBYOKKey(t, r, ctx, keyConfig.ID, string(cmkapi.KeyStatePENDINGIMPORT)) - keyConfigWSystems := testutils.NewKeyConfig(func(_ *model.KeyConfiguration) {}) + keyID := uuid.New() + keyConfigWSystems := testutils.NewKeyConfig(func(k *model.KeyConfiguration) { + k.PrimaryKeyID = ptr.PointTo(keyID) + }) sys := testutils.NewSystem(func(s *model.System) { s.KeyConfigurationID = ptr.PointTo(keyConfigWSystems.ID) }) keyFailSystems := testutils.NewKey(func(k *model.Key) { + k.ID = keyID k.KeyConfigurationID = keyConfigWSystems.ID - k.IsPrimary = true }) testutils.CreateTestEntities(ctx, t, r, keyConfigWSystems, sys, keyFailSystems) @@ -954,141 +940,6 @@ func TestDelete(t *testing.T) { } } -func TestUpdateKeyPrimary(t *testing.T) { - t.Run("Should update primary key and exiting events", func(t *testing.T) { - km, r, ctx, _ := SetupKeyTest(t) - - keyConfig := testutils.NewKeyConfig(func(_ *model.KeyConfiguration) {}) - oldPrimaryKey := testutils.NewKey(func(k *model.Key) { - k.IsPrimary = true - k.KeyConfigurationID = keyConfig.ID - }) - keyConfig.PrimaryKeyID = &oldPrimaryKey.ID - - sys := testutils.NewSystem(func(s *model.System) { - s.KeyConfigurationID = ptr.PointTo(keyConfig.ID) - }) - - key := testutils.NewKey(func(k *model.Key) { - k.IsPrimary = false - k.KeyConfigurationID = keyConfig.ID - }) - - data := eventprocessor.SystemActionJobData{ - KeyIDTo: oldPrimaryKey.ID.String(), - } - dataBytes, err := json.Marshal(data) - assert.NoError(t, err) - - event := &model.Event{ - Identifier: uuid.NewString(), - Type: proto.TaskType_SYSTEM_SWITCH.String(), - Data: dataBytes, - } - - testutils.CreateTestEntities(ctx, t, r, keyConfig, oldPrimaryKey, key, sys, event) - localCtx := testutils.InjectClientDataIntoContext(ctx, uuid.NewString(), []string{keyConfig.AdminGroup.IAMIdentifier}) - - key, err = km.UpdateKey(localCtx, key.ID, cmkapi.KeyPatch{ - IsPrimary: ptr.PointTo(true), - }) - assert.NoError(t, err) - assert.True(t, key.IsPrimary) - - resKeyConfig := &model.KeyConfiguration{ID: keyConfig.ID} - _, err = r.First(localCtx, resKeyConfig, *repo.NewQuery()) - assert.NoError(t, err) - - assert.Equal(t, key.ID, *resKeyConfig.PrimaryKeyID) - - _, err = r.First(localCtx, event, *repo.NewQuery()) - assert.NoError(t, err) - jobData, err := eventprocessor.GetSystemJobData(event) - assert.NoError(t, err) - assert.Equal(t, key.ID.String(), jobData.KeyIDTo) - - oldK1, err := km.Get(localCtx, oldPrimaryKey.ID) - assert.NoError(t, err) - assert.False(t, oldK1.IsPrimary) - }) - - t.Run("Should use old pkey on switch event when updating ", func(t *testing.T) { - km, r, ctx, _ := SetupKeyTest(t) - - keyConfig := testutils.NewKeyConfig(func(_ *model.KeyConfiguration) {}) - oldPrimaryKey := testutils.NewKey(func(k *model.Key) { - k.IsPrimary = true - k.KeyConfigurationID = keyConfig.ID - }) - keyConfig.PrimaryKeyID = &oldPrimaryKey.ID - - sys := testutils.NewSystem(func(s *model.System) { - s.KeyConfigurationID = ptr.PointTo(keyConfig.ID) - }) - - key := testutils.NewKey(func(k *model.Key) { - k.IsPrimary = false - k.KeyConfigurationID = keyConfig.ID - }) - - testutils.CreateTestEntities(ctx, t, r, keyConfig, oldPrimaryKey, key, sys) - localCtx := testutils.InjectClientDataIntoContext(ctx, uuid.NewString(), []string{keyConfig.AdminGroup.IAMIdentifier}) - - k, err := km.UpdateKey(localCtx, key.ID, cmkapi.KeyPatch{ - IsPrimary: ptr.PointTo(true), - }) - assert.NoError(t, err) - assert.True(t, k.IsPrimary) - - orbitalCtx := testutils.CreateCtxWithTenant("orbital") - jobFromDB := &testutils.OrbitalJob{} - _, err = r.First( - orbitalCtx, - jobFromDB, - *repo.NewQuery().Where( - repo.NewCompositeKeyGroup( - repo.NewCompositeKey().Where("external_id", sys.ID.String()), - ), - ), - ) - assert.NoError(t, err) - - jobData := &eventprocessor.SystemActionJobData{} - err = json.Unmarshal(jobFromDB.Data, jobData) - assert.NoError(t, err) - assert.Equal(t, oldPrimaryKey.ID.String(), jobData.KeyIDFrom) - }) - - t.Run("Should error on set primary on disabled key", func(t *testing.T) { - km, r, ctx, keyConfig := SetupKeyTest(t) - - key1 := testutils.NewKey(func(k *model.Key) { - k.IsPrimary = false - k.State = string(cmkapi.KeyStateDISABLED) - k.KeyConfigurationID = keyConfig.ID - }) - testutils.CreateTestEntities(ctx, t, r, key1) - _, err := km.UpdateKey(ctx, key1.ID, cmkapi.KeyPatch{ - IsPrimary: ptr.PointTo(true), - }) - assert.ErrorIs(t, err, manager.ErrKeyIsNotEnabled) - }) - - t.Run("Should error on unmark primary on primary key", func(t *testing.T) { - km, r, ctx, keyConfig := SetupKeyTest(t) - - key1 := testutils.NewKey(func(k *model.Key) { - k.IsPrimary = true - k.KeyConfigurationID = keyConfig.ID - }) - testutils.CreateTestEntities(ctx, t, r, key1) - _, err := km.UpdateKey(ctx, key1.ID, cmkapi.KeyPatch{ - IsPrimary: ptr.PointTo(false), - }) - assert.ErrorIs(t, err, manager.ErrPrimaryKeyUnmark) - }) -} - func TestGetImportParams(t *testing.T) { cachedPublicKeyFromDB := "mock-public-key-from-database" fetchedPublicKeyFromProvider := "mock-public-key-from-provider" @@ -1347,6 +1198,9 @@ func TestKeyRotationTime(t *testing.T) { svcRegistry, err := cmkpluginregistry.New(ctx, cfg, cmkpluginregistry.WithBuiltInPlugins(ps)) require.NoError(t, err) + eventFactory, err := eventprocessor.NewEventFactory(t.Context(), cfg, r) + assert.NoError(t, err) + cmkAuditor := auditor.New(ctx, cfg) tenantConfigManager := manager.NewTenantConfigManager(r, svcRegistry, nil) certManager := manager.NewCertificateManager(ctx, r, svcRegistry, @@ -1355,7 +1209,7 @@ func TestKeyRotationTime(t *testing.T) { }) userManager := manager.NewUserManager(r, cmkAuditor) tagManager := manager.NewTagManager(r) - keyConfigManager := manager.NewKeyConfigManager(r, certManager, userManager, tagManager, cmkAuditor, cfg) + keyConfigManager := manager.NewKeyConfigManager(r, certManager, userManager, tagManager, cmkAuditor, eventFactory, cfg) km := manager.NewKeyManager(r, svcRegistry, tenantConfigManager, keyConfigManager, userManager, certManager, nil, cmkAuditor) // Create test data @@ -1551,9 +1405,12 @@ func TestHandleSystemsOnKeyRotation(t *testing.T) { k.Region = testRegionUSEast1 k.NativeID = ptr.PointTo("primary-key-native-id") k.ManagementAccessData = hyokInfo - k.IsPrimary = true }) + keyConfig.PrimaryKeyID = ptr.PointTo(primaryKey.ID) + _, err = r.Patch(ctx, keyConfig, *repo.NewQuery()) + assert.NoError(t, err) + nonPrimaryKey := testutils.NewKey(func(k *model.Key) { k.Name = "non-primary-key" k.KeyConfigurationID = keyConfig.ID @@ -1563,7 +1420,6 @@ func TestHandleSystemsOnKeyRotation(t *testing.T) { k.Region = testRegionUSEast1 k.NativeID = ptr.PointTo("non-primary-key-native-id") k.ManagementAccessData = hyokInfo - k.IsPrimary = false }) // Create systems linked to this key configuration diff --git a/internal/manager/keyconfiguration.go b/internal/manager/keyconfiguration.go index e6040c10..f2f60345 100644 --- a/internal/manager/keyconfiguration.go +++ b/internal/manager/keyconfiguration.go @@ -4,6 +4,7 @@ import ( "context" "crypto/x509" "crypto/x509/pkix" + "encoding/json" "encoding/pem" "errors" "fmt" @@ -20,9 +21,15 @@ import ( "github.com/openkcm/cmk/internal/config" "github.com/openkcm/cmk/internal/constants" "github.com/openkcm/cmk/internal/errs" + eventprocessor "github.com/openkcm/cmk/internal/event-processor" "github.com/openkcm/cmk/internal/model" "github.com/openkcm/cmk/internal/repo" cmkcontext "github.com/openkcm/cmk/utils/context" + "github.com/openkcm/cmk/utils/ptr" +) + +const ( + DefaultCertName = "hyok-default" ) var ( @@ -44,12 +51,13 @@ type KeyConfigurationAPI interface { } type KeyConfigManager struct { - repository repo.Repo - user User - certs *CertificateManager - tagManager Tags - cmkAuditor *auditor.Auditor - cfg *config.Config + r repo.Repo + user User + certs *CertificateManager + tagManager Tags + cmkAuditor *auditor.Auditor + cfg *config.Config + eventFactory *eventprocessor.EventFactory } type KeyConfigFilter struct { @@ -63,15 +71,17 @@ func NewKeyConfigManager( user User, tagManager Tags, cmkAuditor *auditor.Auditor, + eventFactory *eventprocessor.EventFactory, cfg *config.Config, ) *KeyConfigManager { return &KeyConfigManager{ - repository: repository, - certs: certManager, - user: user, - cmkAuditor: cmkAuditor, - tagManager: tagManager, - cfg: cfg, + r: repository, + certs: certManager, + user: user, + cmkAuditor: cmkAuditor, + tagManager: tagManager, + eventFactory: eventFactory, + cfg: cfg, } } @@ -94,7 +104,7 @@ func (m *KeyConfigManager) GetKeyConfigurations( return []*model.KeyConfiguration{}, 0, nil } - return repo.ListAndCount(ctx, m.repository, filter.Pagination, model.KeyConfiguration{}, query) + return repo.ListAndCount(ctx, m.r, filter.Pagination, model.KeyConfiguration{}, query) } func (m *KeyConfigManager) PostKeyConfigurations( @@ -103,7 +113,7 @@ func (m *KeyConfigManager) PostKeyConfigurations( ) (*model.KeyConfiguration, error) { var group model.Group - exist, err := m.repository.First( + exist, err := m.r.First( ctx, &group, *repo.NewQuery(). @@ -128,7 +138,7 @@ func (m *KeyConfigManager) PostKeyConfigurations( return nil, ErrNameCannotBeEmpty } - err = m.repository.Create(ctx, keyConfiguration) + err = m.r.Create(ctx, keyConfiguration) if err != nil { return nil, errs.Wrap(ErrCreateKeyConfiguration, err) } @@ -147,7 +157,7 @@ func (m *KeyConfigManager) DeleteKeyConfigurationByID( return err } - exist, err := repo.HasConnectedSystems(ctx, m.repository, keyConfigID) + exist, err := repo.HasConnectedSystems(ctx, m.r, keyConfigID) if err != nil { return err } @@ -156,8 +166,8 @@ func (m *KeyConfigManager) DeleteKeyConfigurationByID( return errs.Wrap(ErrDeleteKeyConfiguration, ErrConnectedSystemToKeyConfig) } - return m.repository.Transaction(ctx, func(ctx context.Context) error { - _, err = m.repository.Delete(ctx, keyConfig, *repo.NewQuery()) + return m.r.Transaction(ctx, func(ctx context.Context) error { + _, err = m.r.Delete(ctx, keyConfig, *repo.NewQuery()) if err != nil { return errs.Wrap(ErrDeleteKeyConfiguration, err) } @@ -180,7 +190,7 @@ func (m *KeyConfigManager) GetKeyConfigurationByID( } query := getKeyConfigWithTotalsQuery().Preload(repo.Preload{"AdminGroup"}) - _, err = m.repository.First(ctx, keyConfig, *query) + _, err = m.r.First(ctx, keyConfig, *query) if err != nil { return nil, errs.Wrap(ErrGettingKeyConfigByID, err) } @@ -188,6 +198,10 @@ func (m *KeyConfigManager) GetKeyConfigurationByID( return keyConfig, nil } +// UpdateKeyConfigurationByID updates a keyconfig +// In case there is an update to the primaryKey invoke system switch events +// +//nolint:cyclop func (m *KeyConfigManager) UpdateKeyConfigurationByID( ctx context.Context, keyConfigID uuid.UUID, @@ -202,7 +216,7 @@ func (m *KeyConfigManager) UpdateKeyConfigurationByID( return nil, err } - _, err = m.repository.First( + _, err = m.r.First( ctx, keyConfig, *repo.NewQuery(), @@ -223,9 +237,23 @@ func (m *KeyConfigManager) UpdateKeyConfigurationByID( keyConfig.Description = *patchKeyConfig.Description } - _, err = m.repository.Patch(ctx, keyConfig, *repo.NewQuery()) + err = m.r.Transaction(ctx, func(ctx context.Context) error { + if patchKeyConfig.PrimaryKeyID != nil { + err := m.handleUpdatePrimaryKey(ctx, keyConfig, *patchKeyConfig.PrimaryKeyID) + if err != nil { + return errs.Wrap(ErrUpdateKeyConfiguration, err) + } + keyConfig.PrimaryKeyID = patchKeyConfig.PrimaryKeyID + } + + _, err = m.r.Patch(ctx, keyConfig, *repo.NewQuery()) + if err != nil { + return errs.Wrap(ErrUpdateKeyConfiguration, err) + } + return nil + }) if err != nil { - return nil, errs.Wrap(ErrUpdateKeyConfiguration, err) + return nil, err } return keyConfig, nil @@ -437,3 +465,97 @@ func (m *KeyConfigManager) applyIAMGroupFilter( return false, nil } + +// Whenever Keyconfig PrimaryKey switches, systems need to send switch events +// If systems had a previous switch event the event key needs to be updated for the retru +func (m *KeyConfigManager) handleUpdatePrimaryKey( + ctx context.Context, + keyConfig *model.KeyConfiguration, + primaryKeyID uuid.UUID, +) error { + key := &model.Key{ID: primaryKeyID, KeyConfigurationID: keyConfig.ID} + _, err := m.r.First(ctx, key, *repo.NewQuery()) + if err != nil { + return err + } + if key.State == string(cmkapi.KeyStateDISABLED) { + return ErrKeyIsNotEnabled + } + + // Key is valid. If keyconfig has no existing key no need for further validations + if keyConfig.PrimaryKeyID == nil { + return nil + } + + err = m.updatePrimaryKeySystemEvents( + ctx, + ptr.GetSafeDeref(keyConfig.PrimaryKeyID).String(), + primaryKeyID.String(), + ) + if err != nil { + return err + } + + // Send system switches for systems in keyconfig + query := repo.NewQuery().Where( + repo.NewCompositeKeyGroup( + repo.NewCompositeKey().Where( + repo.KeyConfigIDField, keyConfig.ID), + ), + ) + return repo.ProcessInBatch( + ctx, + m.r, + query, + repo.DefaultLimit, + func(systems []*model.System) error { + for _, s := range systems { + _, err := m.eventFactory.SystemSwitchNewPrimaryKey( + ctx, + s, + primaryKeyID.String(), + keyConfig.PrimaryKeyID.String(), + ) + if err != nil { + return err + } + } + + return nil + }, + ) +} + +// updateOldPKeySystemEvents updates keyTo for system event retries +// This can be done as now there is a new primary key and systems +// can only be linked to primary keys, the previous keyTo needs now +// updated the newly set primary key +func (m *KeyConfigManager) updatePrimaryKeySystemEvents(ctx context.Context, oldPkey string, newPkey string) error { + query := repo.NewQuery().Where( + repo.NewCompositeKeyGroup( + repo.NewCompositeKey().Where( + repo.JSONBField(repo.DataField, "keyIDTo"), oldPkey), + ), + ) + return repo.ProcessInBatch(ctx, m.r, query, repo.DefaultLimit, func(events []*model.Event) error { + for _, e := range events { + systemJobData, err := eventprocessor.GetSystemJobData(e) + if err != nil { + return err + } + + systemJobData.KeyIDTo = newPkey + bytes, err := json.Marshal(systemJobData) + if err != nil { + return err + } + + e.Data = bytes + _, err = m.r.Patch(ctx, e, *repo.NewQuery()) + if err != nil { + return err + } + } + return nil + }) +} diff --git a/internal/manager/keyconfiguration_test.go b/internal/manager/keyconfiguration_test.go index 0cb5c6d3..3e6b33fb 100644 --- a/internal/manager/keyconfiguration_test.go +++ b/internal/manager/keyconfiguration_test.go @@ -18,6 +18,8 @@ import ( "github.com/openkcm/cmk/internal/auditor" "github.com/openkcm/cmk/internal/config" "github.com/openkcm/cmk/internal/constants" + eventprocessor "github.com/openkcm/cmk/internal/event-processor" + "github.com/openkcm/cmk/internal/event-processor/proto" "github.com/openkcm/cmk/internal/manager" "github.com/openkcm/cmk/internal/model" cmkpluginregistry "github.com/openkcm/cmk/internal/pluginregistry" @@ -55,7 +57,9 @@ var ( func SetupKeyConfigManager(t *testing.T) (*manager.KeyConfigManager, *multitenancy.DB, string) { t.Helper() - db, tenants, _ := testutils.NewTestDB(t, testutils.TestDBConfig{}) + db, tenants, dbCfg := testutils.NewTestDB(t, testutils.TestDBConfig{ + WithOrbital: true, + }) r := sql.NewRepository(db) cryptoCerts := []manager.ClientCertificate{ @@ -80,6 +84,7 @@ func SetupKeyConfigManager(t *testing.T) (*manager.KeyConfigManager, *multitenan Value: string(bytes), }, }, + Database: dbCfg, } cmkAuditor := auditor.New(t.Context(), cfg) @@ -90,7 +95,9 @@ func SetupKeyConfigManager(t *testing.T) (*manager.KeyConfigManager, *multitenan tagManager := manager.NewTagManager(r) certManager := manager.NewCertificateManager(t.Context(), r, svcRegistry, cfg) - m := manager.NewKeyConfigManager(r, certManager, userManager, tagManager, cmkAuditor, cfg) + eventFactory, err := eventprocessor.NewEventFactory(t.Context(), cfg, r) + assert.NoError(t, err) + m := manager.NewKeyConfigManager(r, certManager, userManager, tagManager, cmkAuditor, eventFactory, cfg) return m, db, tenants[0] } @@ -307,14 +314,12 @@ func TestTotalSystemAndKey(t *testing.T) { ID: uuid.New(), Name: uuid.NewString(), KeyConfigurationID: keyConfig.ID, - IsPrimary: false, } key2 := &model.Key{ ID: uuid.New(), Name: uuid.NewString(), KeyConfigurationID: keyConfig.ID, - IsPrimary: false, } testutils.CreateTestEntities(ctx, t, r, group, keyConfig, sys, key1, key2) @@ -824,6 +829,126 @@ func TestUpdateKeyConfigurations(t *testing.T) { ) assert.ErrorIs(t, err, manager.ErrKeyConfigurationNotAllowed) }) + + t.Run("Should update primary key and existing events", func(t *testing.T) { + oldPKeyID := uuid.New() + keyConfig := testutils.NewKeyConfig(func(k *model.KeyConfiguration) { + k.PrimaryKeyID = ptr.PointTo(oldPKeyID) + }) + oldPrimaryKey := testutils.NewKey(func(k *model.Key) { + k.ID = oldPKeyID + k.KeyConfigurationID = keyConfig.ID + }) + + sys := testutils.NewSystem(func(s *model.System) { + s.KeyConfigurationID = ptr.PointTo(keyConfig.ID) + }) + + key := testutils.NewKey(func(k *model.Key) { + k.KeyConfigurationID = keyConfig.ID + }) + + data := eventprocessor.SystemActionJobData{ + KeyIDTo: oldPrimaryKey.ID.String(), + } + dataBytes, err := json.Marshal(data) + assert.NoError(t, err) + + event := &model.Event{ + Identifier: uuid.NewString(), + Type: proto.TaskType_SYSTEM_SWITCH.String(), + Data: dataBytes, + } + + testutils.CreateTestEntities(ctx, t, r, keyConfig, oldPrimaryKey, key, sys, event) + ctx := testutils.InjectClientDataIntoContext(ctx, uuid.NewString(), []string{keyConfig.AdminGroup.IAMIdentifier}) + + keyConfig, err = m.UpdateKeyConfigurationByID( + ctx, + keyConfig.ID, + cmkapi.KeyConfigurationPatch{ + PrimaryKeyID: ptr.PointTo(key.ID), + }, + ) + assert.NoError(t, err) + assert.Equal(t, key.ID, *keyConfig.PrimaryKeyID) + + _, err = r.First(ctx, event, *repo.NewQuery()) + assert.NoError(t, err) + jobData, err := eventprocessor.GetSystemJobData(event) + assert.NoError(t, err) + assert.Equal(t, key.ID.String(), jobData.KeyIDTo) + }) + + t.Run("Should error on set primary on disabled key", func(t *testing.T) { + oldPkeyID := uuid.New() + keyConfig := testutils.NewKeyConfig(func(k *model.KeyConfiguration) { + k.PrimaryKeyID = ptr.PointTo(oldPkeyID) + }) + oldPrimaryKey := testutils.NewKey(func(k *model.Key) { + k.ID = oldPkeyID + k.KeyConfigurationID = keyConfig.ID + }) + + key := testutils.NewKey(func(k *model.Key) { + k.State = string(cmkapi.KeyStateDISABLED) + k.KeyConfigurationID = keyConfig.ID + }) + testutils.CreateTestEntities(ctx, t, r, oldPrimaryKey, keyConfig, key) + ctx := testutils.InjectClientDataIntoContext(ctx, uuid.NewString(), []string{keyConfig.AdminGroup.IAMIdentifier}) + + _, err := m.UpdateKeyConfigurationByID( + ctx, + keyConfig.ID, + cmkapi.KeyConfigurationPatch{ + PrimaryKeyID: ptr.PointTo(key.ID), + }, + ) + assert.ErrorIs(t, err, manager.ErrKeyIsNotEnabled) + }) + + t.Run("Should use old pkey on switch event when system updating", func(t *testing.T) { + keyConfig := testutils.NewKeyConfig(func(_ *model.KeyConfiguration) {}) + oldPrimaryKey := testutils.NewKey(func(k *model.Key) { + k.KeyConfigurationID = keyConfig.ID + }) + keyConfig.PrimaryKeyID = &oldPrimaryKey.ID + + sys := testutils.NewSystem(func(s *model.System) { + s.KeyConfigurationID = ptr.PointTo(keyConfig.ID) + }) + + key := testutils.NewKey(func(k *model.Key) { + k.KeyConfigurationID = keyConfig.ID + }) + + testutils.CreateTestEntities(ctx, t, r, keyConfig, oldPrimaryKey, key, sys) + ctx := testutils.InjectClientDataIntoContext(ctx, uuid.NewString(), []string{keyConfig.AdminGroup.IAMIdentifier}) + + _, err := m.UpdateKeyConfigurationByID(ctx, keyConfig.ID, cmkapi.KeyConfigurationPatch{ + PrimaryKeyID: ptr.PointTo(key.ID), + }) + + assert.NoError(t, err) + + orbitalCtx := cmkcontext.CreateTenantContext(ctx, "orbital") + jobFromDB := &testutils.OrbitalJob{} + _, err = r.First( + orbitalCtx, + jobFromDB, + *repo.NewQuery().Where( + repo.NewCompositeKeyGroup( + repo.NewCompositeKey().Where("external_id", sys.ID.String()), + ), + ), + ) + assert.NoError(t, err) + + data := &eventprocessor.SystemActionJobData{} + err = json.Unmarshal(jobFromDB.Data, data) + assert.NoError(t, err) + assert.Equal(t, oldPrimaryKey.ID.String(), data.KeyIDFrom) + }) } func TestDeleteKeyConfiguration(t *testing.T) { diff --git a/internal/manager/keyversion_test.go b/internal/manager/keyversion_test.go index 0299dfde..cf2dc67b 100644 --- a/internal/manager/keyversion_test.go +++ b/internal/manager/keyversion_test.go @@ -68,7 +68,7 @@ func (s *KeyVersionManagerSuit) SetupSuite() { cmkAuditor := auditor.New(s.ctx, &cfg) userManager := manager.NewUserManager(s.r, cmkAuditor) tagManager := manager.NewTagManager(s.r) - keyConfigManager := manager.NewKeyConfigManager(s.r, certManager, userManager, tagManager, cmkAuditor, &cfg) + keyConfigManager := manager.NewKeyConfigManager(s.r, certManager, userManager, tagManager, cmkAuditor, nil, &cfg) s.km = manager.NewKeyManager(s.r, svcRegistry, tenantConfigManager, keyConfigManager, userManager, certManager, nil, cmkAuditor) s.kvm = manager.NewKeyVersionManager( s.r, diff --git a/internal/manager/system_test.go b/internal/manager/system_test.go index 0ca03a38..788c721a 100644 --- a/internal/manager/system_test.go +++ b/internal/manager/system_test.go @@ -40,7 +40,9 @@ func SetupSystemManager(t *testing.T, clientsFactory clients.Factory) ( ) { t.Helper() - db, tenants, dbCfg := testutils.NewTestDB(t, testutils.TestDBConfig{}) + db, tenants, dbCfg := testutils.NewTestDB(t, testutils.TestDBConfig{ + WithOrbital: true, + }) ps, psCfg := testutils.NewTestPlugins( testplugins.NewSystemInformation(), @@ -78,10 +80,9 @@ func SetupSystemManager(t *testing.T, clientsFactory clients.Factory) ( Certificates: config.Certificates{ValidityDays: config.MinCertificateValidityDays}, }, ) - userManager := manager.NewUserManager(r, auditor.New(t.Context(), &cfg)) tagManager := manager.NewTagManager(r) - keyConfigManager := manager.NewKeyConfigManager(r, certManager, userManager, tagManager, nil, &cfg) + keyConfigManager := manager.NewKeyConfigManager(r, certManager, userManager, tagManager, nil, nil, &cfg) eventFactory, err := eventprocessor.NewEventFactory(t.Context(), &cfg, r) require.NoError(t, err) @@ -1176,16 +1177,18 @@ func TestLinkSystemAction(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - m, db, tenant := SetupSystemManager(t, nil) - ctx := testutils.CreateCtxWithTenant(tenant) - ctx = testutils.InjectClientDataIntoContext(ctx, "test-user", []string{"test-group"}) - r := sql.NewRepository(db) testGroup := testutils.NewGroup( func(g *model.Group) { - g.IAMIdentifier = "test-group" + g.IAMIdentifier = uuid.NewString() }, ) + ctx := testutils.InjectClientDataIntoContext( + ctx, + testGroup.IAMIdentifier, + []string{testGroup.IAMIdentifier}, + ) + keyConfig, key := tt.setupKeyConfig(testGroup) system := testutils.NewSystem( func(s *model.System) { diff --git a/internal/manager/tenant.go b/internal/manager/tenant.go index 5213bd5f..918181e4 100644 --- a/internal/manager/tenant.go +++ b/internal/manager/tenant.go @@ -3,6 +3,7 @@ package manager import ( "context" "errors" + "fmt" "strings" "google.golang.org/grpc/codes" @@ -274,17 +275,12 @@ func (m *TenantManager) checkAllSystemsUnlinked(ctx context.Context) (bool, erro return count == 0, nil } +// List all primary keys that are not yet detached and trigger detach events for them. func (m *TenantManager) detachPrimaryKeys(ctx context.Context) error { - // List all primary keys that are not yet detached and trigger detach events for them. - query := repo.NewCompositeKey(). - Where(repo.IsPrimaryField, true). - Where(repo.StateField, cmkapi.KeyStateDETACHING, repo.NotEq). - Where(repo.StateField, cmkapi.KeyStateDETACHED, repo.NotEq) - return repo.ProcessInBatch( ctx, m.repo, - repo.NewQuery().Where(repo.NewCompositeKeyGroup(query)), + checkKeyDetatchingQuery(), repo.DefaultLimit, func(keys []*model.Key) error { for _, k := range keys { @@ -320,7 +316,6 @@ func (m *TenantManager) unmapAllSystemsFromRegistry(ctx context.Context) Offboar return nil }, ) - if err != nil { log.Error(ctx, "error while processing systems in batch to unmap from registry", err) return OffboardingContinueAndWait @@ -373,15 +368,10 @@ func (m *TenantManager) escalateOffboardingStatus(current, target OffboardingSta } func (m *TenantManager) checkAllPrimaryKeysProcessed(ctx context.Context) (bool, error) { - query := repo.NewCompositeKey(). - Where(repo.IsPrimaryField, true). - Where(repo.StateField, cmkapi.KeyStateDETACHING, repo.NotEq). - Where(repo.StateField, cmkapi.KeyStateDETACHED, repo.NotEq) - count, err := m.repo.Count( ctx, &model.Key{}, - *repo.NewQuery().Where(repo.NewCompositeKeyGroup(query)), + *checkKeyDetatchingQuery(), ) if err != nil { return false, err @@ -390,15 +380,38 @@ func (m *TenantManager) checkAllPrimaryKeysProcessed(ctx context.Context) (bool, return count == 0, nil } +func checkKeyDetatchingQuery() *repo.Query { + cond := repo.NewCompositeKey(). + Where(fmt.Sprintf(`"%s".%s`, model.KeyConfiguration{}.TableName(), repo.PrimaryKeyIDField), repo.NotNull). + Where(repo.StateField, cmkapi.KeyStateDETACHING, repo.NotEq). + Where(repo.StateField, cmkapi.KeyStateDETACHED, repo.NotEq) + + return repo.NewQuery().Where(repo.NewCompositeKeyGroup(cond)).Join( + repo.LeftJoin, repo.JoinCondition{ + Table: model.Key{}, + Field: repo.KeyConfigIDField, + JoinTable: model.KeyConfiguration{}, + JoinField: repo.IDField, + }) +} + func (m *TenantManager) checkAllPrimaryKeysDetached(ctx context.Context) (bool, error) { - query := repo.NewCompositeKey(). - Where(repo.IsPrimaryField, true). + cond := repo.NewCompositeKey(). + Where(fmt.Sprintf(`"%s".%s`, model.KeyConfiguration{}.TableName(), repo.PrimaryKeyIDField), repo.NotNull). Where(repo.StateField, cmkapi.KeyStateDETACHED, repo.NotEq) + query := repo.NewQuery().Where(repo.NewCompositeKeyGroup(cond)).Join( + repo.LeftJoin, repo.JoinCondition{ + Table: model.Key{}, + Field: repo.KeyConfigIDField, + JoinTable: model.KeyConfiguration{}, + JoinField: repo.IDField, + }) + count, err := m.repo.Count( ctx, &model.Key{}, - *repo.NewQuery().Where(repo.NewCompositeKeyGroup(query)), + *query, ) if err != nil { return false, err diff --git a/internal/manager/tenant_test.go b/internal/manager/tenant_test.go index 01b64cf7..6a0a839e 100644 --- a/internal/manager/tenant_test.go +++ b/internal/manager/tenant_test.go @@ -60,7 +60,7 @@ func SetupTenantManager(t *testing.T, opts ...testutils.TestDBConfigOpt) ( cm := manager.NewCertificateManager(ctx, r, svcRegistry, cfg) um := testutils.NewUserManager() tagManager := manager.NewTagManager(r) - kcm := manager.NewKeyConfigManager(r, cm, um, tagManager, cmkAuditor, cfg) + kcm := manager.NewKeyConfigManager(r, cm, um, tagManager, cmkAuditor, eventFactory, cfg) mappingService := mapping.NewFakeService() _, grpcClient := testutils.NewGRPCSuite(t, @@ -183,6 +183,24 @@ func TestOffboardTenant(t *testing.T) { testutils.CreateTestEntities(ctx, t, r, keyConfig, key) t.Run("Should return success", func(t *testing.T) { + m, r, tenants := SetupTenantManager(t) + ctx := cmkcontext.CreateTenantContext(t.Context(), tenants[0]) + + keyID := uuid.New() + keyConfig := testutils.NewKeyConfig( + func(k *model.KeyConfiguration) { + k.PrimaryKeyID = ptr.PointTo(keyID) + }, + ) + key := testutils.NewKey( + func(k *model.Key) { + k.KeyConfigurationID = keyConfig.ID + k.State = string(cmkapi.KeyStateDETACHED) + k.ID = keyID + }, + ) + ctx = testutils.InjectClientDataIntoContext(ctx, uuid.NewString(), []string{keyConfig.AdminGroup.IAMIdentifier}) + testutils.CreateTestEntities( ctx, t, r, testutils.NewSystem( @@ -191,13 +209,8 @@ func TestOffboardTenant(t *testing.T) { s.KeyConfigurationID = nil }, ), - testutils.NewKey( - func(k *model.Key) { - k.KeyConfigurationID = keyConfig.ID - k.IsPrimary = true - k.State = string(cmkapi.KeyStateDETACHED) - }, - ), + key, + keyConfig, ) result, err := m.OffboardTenant(ctx) assert.NoError(t, err) @@ -239,14 +252,20 @@ func TestOffboardTenant(t *testing.T) { t.Run("Should return in processing on keys that havent been processed", func(t *testing.T) { disconnectAllExistingSystems(t, ctx, r) + keyID := uuid.New() + keyConfig := testutils.NewKeyConfig( + func(k *model.KeyConfiguration) { + k.PrimaryKeyID = ptr.PointTo(key.ID) + }, + ) key := testutils.NewKey( func(k *model.Key) { k.KeyConfigurationID = keyConfig.ID - k.IsPrimary = true k.State = string(cmkapi.KeyStateENABLED) + k.ID = keyID }, ) - testutils.CreateTestEntities(ctx, t, r, key) + testutils.CreateTestEntities(ctx, t, r, key, keyConfig) result, err := m.OffboardTenant(ctx) assert.NoError(t, err) @@ -392,6 +411,7 @@ func (s *mockSystemManager) UnlinkSystemAction(context.Context, uuid.UUID, strin func (s *mockSystemManager) GetAllSystems(context.Context, repo.QueryMapper) ([]*model.System, int, error) { panic("not implemented") } + func (s *mockSystemManager) GetSystemByID(context.Context, uuid.UUID) (*model.System, error) { panic("not implemented") } @@ -400,9 +420,11 @@ func (s *mockSystemManager) RefreshSystemsData(context.Context) bool { return tr func (s *mockSystemManager) LinkSystemAction(context.Context, uuid.UUID, cmkapi.SystemPatch) (*model.System, error) { panic("not implemented") } + func (s *mockSystemManager) GetRecoveryActions(context.Context, uuid.UUID) (cmkapi.SystemRecoveryAction, error) { panic("not implemented") } + func (s *mockSystemManager) SendRecoveryActions( context.Context, uuid.UUID, diff --git a/internal/manager/tenantconfigs.go b/internal/manager/tenantconfigs.go index 9d1f6f0f..0138c895 100644 --- a/internal/manager/tenantconfigs.go +++ b/internal/manager/tenantconfigs.go @@ -20,7 +20,6 @@ import ( ) const ( - DefaultCertName = "hyok-default" // Since the workflow expiry must be less than the retention minus a day minimumRetentionPeriodDays = 2 diff --git a/internal/manager/workflow_test.go b/internal/manager/workflow_test.go index 4bf4de38..f942c322 100644 --- a/internal/manager/workflow_test.go +++ b/internal/manager/workflow_test.go @@ -70,7 +70,7 @@ func SetupWorkflowManager( cmkAuditor := auditor.New(t.Context(), cfg) userManager := manager.NewUserManager(r, cmkAuditor) tagManager := manager.NewTagManager(r) - keyConfigManager := manager.NewKeyConfigManager(r, certManager, userManager, tagManager, cmkAuditor, cfg) + keyConfigManager := manager.NewKeyConfigManager(r, certManager, userManager, tagManager, cmkAuditor, nil, cfg) groupManager := manager.NewGroupManager(r, svcRegistry, userManager) clientsFactory, err := clients.NewFactory(cfg.Services) @@ -280,11 +280,13 @@ func TestWorkflowManager_CheckWorkflow(t *testing.T) { }) t.Run("should not be valid on primary key change with unconnected system", func(t *testing.T) { - key := testutils.NewKey(func(k *model.Key) { - k.IsPrimary = true - }) + keyID := uuid.New() keyConfig := testutils.NewKeyConfig(func(kc *model.KeyConfiguration) { - kc.PrimaryKeyID = &key.ID + kc.PrimaryKeyID = ptr.PointTo(keyID) + }) + key := testutils.NewKey(func(k *model.Key) { + k.ID = keyID + k.KeyConfigurationID = keyConfig.ID }) system := testutils.NewSystem(func(s *model.System) { s.KeyConfigurationID = &keyConfig.ID @@ -311,12 +313,11 @@ func TestWorkflowManager_CheckWorkflow(t *testing.T) { }) t.Run("should not be valid on change primary key to primary key", func(t *testing.T) { - key := testutils.NewKey(func(k *model.Key) { - k.IsPrimary = true - }) + key := testutils.NewKey(func(k *model.Key) {}) keyConfig := testutils.NewKeyConfig(func(kc *model.KeyConfiguration) { kc.PrimaryKeyID = &key.ID + kc.PrimaryKeyID = ptr.PointTo(key.ID) }) testutils.CreateTestEntities(ctxSys, t, repo, key, keyConfig) diff --git a/internal/model/key.go b/internal/model/key.go index d6477cbb..7674bd16 100644 --- a/internal/model/key.go +++ b/internal/model/key.go @@ -33,8 +33,9 @@ type Key struct { LastUsed *time.Time ManagementAccessData json.RawMessage `gorm:"type:jsonb"` CryptoAccessData json.RawMessage `gorm:"type:jsonb"` - IsPrimary bool `gorm:"type:bool"` - EditableRegions map[string]bool `gorm:"-:all"` + + IsPrimary bool `gorm:"-:all"` // Loaded on the managear/get methods + EditableRegions map[string]bool `gorm:"-:all"` } // TableResourceType return the authz resource type @@ -53,7 +54,8 @@ func (Key) IsSharedModel() bool { func (m Key) CheckAuthz(ctx context.Context, authzHandler *authz.Handler[authz.RepoResourceTypeName, authz.RepoAction], - action authz.RepoAction) (bool, error) { + action authz.RepoAction, +) (bool, error) { return authz.CheckAuthz(ctx, authzHandler, m.TableResourceType(), action) } diff --git a/internal/operator/operator_test.go b/internal/operator/operator_test.go index c3ae270a..6407318a 100644 --- a/internal/operator/operator_test.go +++ b/internal/operator/operator_test.go @@ -99,7 +99,7 @@ func createManagers( cm := manager.NewCertificateManager(ctx, r, svcRegistry, cfg) um := manager.NewUserManager(r, cmkAuditor) tagm := manager.NewTagManager(r) - kcm := manager.NewKeyConfigManager(r, cm, um, tagm, cmkAuditor, cfg) + kcm := manager.NewKeyConfigManager(r, cm, um, tagm, cmkAuditor, nil, cfg) sys := manager.NewSystemManager( ctx, diff --git a/internal/repo/repository.go b/internal/repo/repository.go index 04b5abeb..4743b542 100644 --- a/internal/repo/repository.go +++ b/internal/repo/repository.go @@ -310,6 +310,32 @@ func ProcessInBatchWithOptions[T Resource]( return nil } +func GetKeyConfigPrimaryKey(ctx context.Context, r Repo, keyConfigID uuid.UUID) (*uuid.UUID, error) { + keyConfig := &model.KeyConfiguration{ + ID: keyConfigID, + } + + _, err := r.First( + ctx, + keyConfig, + *NewQuery(), + ) + + if err != nil && !errors.Is(err, ErrNotFound) { + return nil, err + } + return keyConfig.PrimaryKeyID, nil +} + +func IsPrimaryKey(ctx context.Context, r Repo, key *model.Key) (bool, error) { + pkeyID, err := GetKeyConfigPrimaryKey(ctx, r, key.KeyConfigurationID) + if err != nil || pkeyID == nil { + return false, err + } + + return *pkeyID == key.ID, nil +} + // ProcessInBatch retrieves and processes records in batches from the database based on the provided query parameters. // It iterates through all matching records using pagination to avoid loading large datasets into memory. // The processFunc is called on the records, allowing custom processing logic. diff --git a/internal/repo/sql/repo.go b/internal/repo/sql/repo.go index 2cfd785c..648c73d5 100644 --- a/internal/repo/sql/repo.go +++ b/internal/repo/sql/repo.go @@ -30,9 +30,7 @@ type ctxKey string const dbCtxKey ctxKey = "transactionRepo" -var ( - ErrUnsupportedOrderDirective = errors.New("unsupported order directive") -) +var ErrUnsupportedOrderDirective = errors.New("unsupported order directive") // ResourceRepository represents the repository for managing Resource data. type ResourceRepository struct { diff --git a/internal/workflow/key_configuration_actions.go b/internal/workflow/key_configuration_actions.go index 1a41b02a..31d2359b 100644 --- a/internal/workflow/key_configuration_actions.go +++ b/internal/workflow/key_configuration_actions.go @@ -7,11 +7,17 @@ import ( "github.com/openkcm/cmk/internal/api/cmkapi" "github.com/openkcm/cmk/internal/errs" + "github.com/openkcm/cmk/internal/model" "github.com/openkcm/cmk/utils/ptr" ) type KeyConfigurationActions interface { DeleteKeyConfigurationByID(ctx context.Context, keyConfigID uuid.UUID) error + UpdateKeyConfigurationByID( + ctx context.Context, + keyConfigID uuid.UUID, + patchKeyConfig cmkapi.KeyConfigurationPatch, + ) (*model.KeyConfiguration, error) } func (l *Lifecycle) deleteKeyConfiguration(ctx context.Context) error { @@ -29,7 +35,9 @@ func (l *Lifecycle) updatePrimaryKey(ctx context.Context) error { return errs.Wrap(ErrWorkflowExecution, err) } - _, err = l.KeyActions.UpdateKey(ctx, keyID, cmkapi.KeyPatch{IsPrimary: ptr.PointTo(true)}) + _, err = l.KeyConfigurationActions.UpdateKeyConfigurationByID(ctx, l.Workflow.ArtifactID, cmkapi.KeyConfigurationPatch{ + PrimaryKeyID: ptr.PointTo(keyID), + }) if err != nil { return errs.Wrap(ErrWorkflowExecution, err) } diff --git a/internal/workflow/key_configuration_actions_test.go b/internal/workflow/key_configuration_actions_test.go index ce83de2d..886a392d 100644 --- a/internal/workflow/key_configuration_actions_test.go +++ b/internal/workflow/key_configuration_actions_test.go @@ -11,6 +11,7 @@ import ( sqlRepo "github.com/openkcm/cmk/internal/repo/sql" "github.com/openkcm/cmk/internal/testutils" "github.com/openkcm/cmk/internal/workflow" + "github.com/openkcm/cmk/utils/ptr" ) func TestWorkflowKeyConfigActions(t *testing.T) { @@ -20,16 +21,16 @@ func TestWorkflowKeyConfigActions(t *testing.T) { tests := []struct { name string - workflow func(k *model.Key) *model.Workflow + workflow func(kc *model.KeyConfiguration, k *model.Key) *model.Workflow transition workflow.Transition expectedState workflow.State }{ { name: "Delete key config", - workflow: func(k *model.Key) *model.Workflow { + workflow: func(kc *model.KeyConfiguration, k *model.Key) *model.Workflow { return testutils.NewWorkflow(func(wf *model.Workflow) { wf.State = workflow.StateWaitConfirmation.String() - wf.ActionType = workflow.ActionTypeUpdatePrimary.String() + wf.ActionType = workflow.ActionTypeDelete.String() wf.ArtifactType = workflow.ArtifactTypeKeyConfiguration.String() wf.Approvers = []model.WorkflowApprover{ *testutils.NewWorkflowApprover(func(a *model.WorkflowApprover) { @@ -39,6 +40,7 @@ func TestWorkflowKeyConfigActions(t *testing.T) { a.Approved = sqlNullBoolNull }), } + wf.ArtifactID = kc.ID wf.Parameters = k.ID.String() }) }, @@ -47,7 +49,7 @@ func TestWorkflowKeyConfigActions(t *testing.T) { }, { name: "Update primary key", - workflow: func(k *model.Key) *model.Workflow { + workflow: func(kc *model.KeyConfiguration, k *model.Key) *model.Workflow { return testutils.NewWorkflow(func(wf *model.Workflow) { wf.State = workflow.StateWaitConfirmation.String() wf.ActionType = workflow.ActionTypeUpdatePrimary.String() @@ -60,6 +62,7 @@ func TestWorkflowKeyConfigActions(t *testing.T) { a.Approved = sqlNullBoolNull }), } + wf.ArtifactID = kc.ID wf.Parameters = k.ID.String() }) }, @@ -70,7 +73,10 @@ func TestWorkflowKeyConfigActions(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - keyConfig := testutils.NewKeyConfig(func(_ *model.KeyConfiguration) {}) + keyID := uuid.New() + keyConfig := testutils.NewKeyConfig(func(k *model.KeyConfiguration) { + k.PrimaryKeyID = ptr.PointTo(keyID) + }) err := r.Create(ctx, keyConfig) assert.NoError(t, err) @@ -81,12 +87,13 @@ func TestWorkflowKeyConfigActions(t *testing.T) { ) key := testutils.NewKey(func(k *model.Key) { + k.ID = keyID k.KeyConfigurationID = keyConfig.ID }) err = r.Create(ctx, key) assert.NoError(t, err) - wf := tt.workflow(key) + wf := tt.workflow(keyConfig, key) err = r.Create(ctx, wf) assert.NoError(t, err) @@ -100,11 +107,6 @@ func TestWorkflowKeyConfigActions(t *testing.T) { assert.NoError(t, err) assert.True(t, ok) - keyConfig = &model.KeyConfiguration{ID: keyConfig.ID} - ok, err = r.First(ctx, keyConfig, *repo.NewQuery()) - assert.True(t, ok) - assert.NoError(t, err) - assert.Equal(t, tt.expectedState.String(), wf.State) }) } diff --git a/migrations/tenant/schema/00008_delete_key_primary.sql b/migrations/tenant/schema/00008_delete_key_primary.sql new file mode 100644 index 00000000..6886998e --- /dev/null +++ b/migrations/tenant/schema/00008_delete_key_primary.sql @@ -0,0 +1,6 @@ +-- This can be safely removed as it only mirrors the keyconfig primary key ID +-- +goose Up +ALTER TABLE keys DROP is_primary; + +-- +goose Down +ALTER TABLE keys ADD is_primary bool NULL; diff --git a/test/db-migration/migration_test.go b/test/db-migration/migration_test.go index 460fbe13..82b65968 100644 --- a/test/db-migration/migration_test.go +++ b/test/db-migration/migration_test.go @@ -350,13 +350,13 @@ func TestSchemaMigrations(t *testing.T) { version: 5, }, { - name: "Should up tenant/00006_refactor_key_version_table.sql", - downgrade: false, + name: "Should up tenant/00006_refactor_key_version.sql", + downgrade: true, target: db.TenantTarget, version: 6, }, { - name: "Should down tenant/00006_refactor_key_version_table.sql", + name: "Should down tenant/00006_refactor_key_version.sql", downgrade: true, target: db.TenantTarget, version: 6, @@ -365,25 +365,25 @@ func TestSchemaMigrations(t *testing.T) { name: "Should up tenant/00007_delete_user_names.sql", downgrade: true, target: db.TenantTarget, - version: 5, + version: 7, }, { name: "Should down tenant/00007_delete_user_names.sql", downgrade: true, target: db.TenantTarget, - version: 5, + version: 7, }, { - name: "Should up tenant/00006_delete_user_names.sql", - downgrade: false, + name: "Should up tenant/00007_delete_key_primary.sql", + downgrade: true, target: db.TenantTarget, - version: 6, + version: 8, }, { - name: "Should down tenant/00006_delete_user_names.sql", + name: "Should down tenant/00007_delete_key_primary.sql", downgrade: true, target: db.TenantTarget, - version: 6, + version: 8, }, } for _, tt := range tests { diff --git a/test/integration/async_test/common_test.go b/test/integration/async_test/common_test.go index 8cedde55..4f730e2a 100644 --- a/test/integration/async_test/common_test.go +++ b/test/integration/async_test/common_test.go @@ -96,7 +96,7 @@ func overrideDatabase(t *testing.T, a *async.App, db *multitenancy.DB, cfg *conf tc := manager.NewTenantConfigManager(tenancyRepo, svcRegistry, nil) um := manager.NewUserManager(tenancyRepo, cmkAuditor) tam := manager.NewTagManager(tenancyRepo) - kc := manager.NewKeyConfigManager(tenancyRepo, cm, um, tam, nil, cfg) + kc := manager.NewKeyConfigManager(tenancyRepo, cm, um, tam, nil, eventFactory, cfg) km := manager.NewKeyManager(tenancyRepo, svcRegistry, tc, kc, um, cm, eventFactory, nil) hyokCl := val.FieldByName("hyokClient") @@ -183,7 +183,6 @@ func createTestKeyEntities() (model.Group, model.KeyConfiguration, model.Key) { KeyConfigurationID: keyConfig.ID, ManagementAccessData: json.RawMessage(`{"roleArn": "test"}`), CryptoAccessData: json.RawMessage(`{}`), - IsPrimary: true, State: "DISABLED", } diff --git a/test/integration/async_test/workflowassign_test.go b/test/integration/async_test/workflowassign_test.go index a378e7d0..97871085 100644 --- a/test/integration/async_test/workflowassign_test.go +++ b/test/integration/async_test/workflowassign_test.go @@ -109,7 +109,7 @@ func TestWorkflowApproversAssignment(t *testing.T) { cmkAuditor := auditor.New(ctx, testConfig) userManager := manager.NewUserManager(r, cmkAuditor) tagManager := manager.NewTagManager(r) - keyConfigManager := manager.NewKeyConfigManager(r, nil, userManager, tagManager, nil, testConfig) + keyConfigManager := manager.NewKeyConfigManager(r, nil, userManager, tagManager, nil, nil, testConfig) keyManager := manager.NewKeyManager(r, svcRegistry, nil, keyConfigManager, userManager, nil, nil, nil) systemManager := manager.NewSystemManager(ctx, r, nil, nil, svcRegistry, testConfig, keyConfigManager, userManager) groupManager := manager.NewGroupManager(r, svcRegistry, userManager) diff --git a/test/integration/tenant-manager/provisioning_test.go b/test/integration/tenant-manager/provisioning_test.go index 9b5f9561..0985b475 100644 --- a/test/integration/tenant-manager/provisioning_test.go +++ b/test/integration/tenant-manager/provisioning_test.go @@ -69,7 +69,7 @@ func (s *DBSuite) SetupSuite() { cm := manager.NewCertificateManager(ctx, r, svcRegistry, cfg) um := manager.NewUserManager(r, cmkAuditor) tagm := manager.NewTagManager(r) - kcm := manager.NewKeyConfigManager(r, cm, um, tagm, cmkAuditor, cfg) + kcm := manager.NewKeyConfigManager(r, cm, um, tagm, cmkAuditor, eventFactory, cfg) sys := manager.NewSystemManager( ctx, diff --git a/test/security/xss/key_controller_test.go b/test/security/xss/key_controller_test.go index af6fff77..e661e1de 100644 --- a/test/security/xss/key_controller_test.go +++ b/test/security/xss/key_controller_test.go @@ -230,7 +230,6 @@ func TestKeyController_ForJSONXSS(t *testing.T) { testutils.WithAuthClientDataKC(authClient)) key := testutils.NewKey(func(k *model.Key) { - k.IsPrimary = true k.KeyType = constants.KeyTypeHYOK k.ManagementAccessData = json.RawMessage("{\"<>\":\"><\"}") k.CryptoAccessData = json.RawMessage("{\"<>\":{\"test\":\"test\"}}")