Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose the encrypted saved objects key rotation API as internal in serverless #189238

Merged
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ export class EncryptionKeyRotationService {
}

this.options.logger.info(
`Encryption key rotation is completed. ${result.successful} objects out ouf ${result.total} were successfully re-encrypted with the primary encryption key and ${result.failed} objects failed.`
`Encryption key rotation is completed. ${result.successful} objects out of ${result.total} were successfully re-encrypted with the primary encryption key and ${result.failed} objects failed.`
);

return result;
Expand Down
31 changes: 15 additions & 16 deletions x-pack/plugins/encrypted_saved_objects/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,22 +110,21 @@ export class EncryptedSavedObjectsPlugin
getStartServices: core.getStartServices,
});

// In the serverless environment, the encryption keys for saved objects is managed internally and never
// exposed to users and administrators, eliminating the need for any public Encrypted Saved Objects HTTP APIs
if (this.initializerContext.env.packageInfo.buildFlavor !== 'serverless') {
defineRoutes({
router: core.http.createRouter(),
logger: this.initializerContext.logger.get('routes'),
encryptionKeyRotationService: Object.freeze(
new EncryptionKeyRotationService({
logger: this.logger.get('key-rotation-service'),
service,
getStartServices: core.getStartServices,
})
),
config,
});
}
// Expose the key rotation route for both stateful and serverless environments
// The endpoint requires admin privileges, and is internal only in serverless
defineRoutes({
router: core.http.createRouter(),
logger: this.initializerContext.logger.get('routes'),
encryptionKeyRotationService: Object.freeze(
new EncryptionKeyRotationService({
logger: this.logger.get('key-rotation-service'),
service,
getStartServices: core.getStartServices,
})
),
config,
buildFlavor: this.initializerContext.env.packageInfo.buildFlavor,
});

return {
canEncrypt,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* 2.0.
*/

import { BuildFlavor } from '@kbn/config';
import { httpServiceMock, loggingSystemMock } from '@kbn/core/server/mocks';

import type { ConfigType } from '../config';
Expand All @@ -17,5 +18,6 @@ export const routeDefinitionParamsMock = {
logger: loggingSystemMock.create().get(),
config: ConfigSchema.validate(config) as ConfigType,
encryptionKeyRotationService: encryptionKeyRotationServiceMock.create(),
buildFlavor: 'traditional' as BuildFlavor,
}),
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* 2.0.
*/

import { BuildFlavor } from '@kbn/config';
import type { IRouter, Logger } from '@kbn/core/server';
import type { PublicMethodsOf } from '@kbn/utility-types';

Expand All @@ -20,6 +21,7 @@ export interface RouteDefinitionParams {
logger: Logger;
config: ConfigType;
encryptionKeyRotationService: PublicMethodsOf<EncryptionKeyRotationService>;
buildFlavor: BuildFlavor;
}

export function defineRoutes(params: RouteDefinitionParams) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export function defineKeyRotationRoutes({
router,
logger,
config,
buildFlavor,
}: RouteDefinitionParams) {
let rotationInProgress = false;
router.post(
Expand All @@ -41,6 +42,7 @@ export function defineKeyRotationRoutes({
options: {
tags: ['access:rotateEncryptionKey', 'oas-tag:saved objects'],
description: `Rotate a key for encrypted saved objects`,
access: buildFlavor === 'serverless' ? 'internal' : undefined,
},
},
async (context, request, response) => {
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/encrypted_saved_objects/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"@kbn/core-saved-objects-api-server-mocks",
"@kbn/core-security-common",
"@kbn/test-jest-helpers",
"@kbn/config",
],
"exclude": [
"target/**/*",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* 2.0.
*/

import expect from 'expect';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { InternalRequestHeader, RoleCredentials } from '../../../../shared/services';

Expand All @@ -24,13 +25,40 @@ export default function ({ getService }: FtrProviderContext) {
await svlUserManager.invalidateM2mApiKeyWithRoleScope(roleAuthc);
});
describe('route access', () => {
describe('disabled', () => {
describe('internal', () => {
it('rotate key', async () => {
const { body, status } = await supertestWithoutAuth
let body: unknown;
let status: number;

({ body, status } = await supertestWithoutAuth
.post('/api/encrypted_saved_objects/_rotate_key')
// .set(internalReqHeader)
.set(roleAuthc.apiKeyHeader));
// svlCommonApi.assertApiNotFound(body, status);
// expect a rejection because we're not using the internal header
expect(body).toEqual({
statusCode: 400,
error: 'Bad Request',
message: expect.stringContaining('Request must contain a kbn-xsrf header.'),
});
expect(status).toBe(400);

({ body, status } = await supertestWithoutAuth
.post('/api/encrypted_saved_objects/_rotate_key')
.set(internalReqHeader)
.set(roleAuthc.apiKeyHeader);
svlCommonApi.assertApiNotFound(body, status);
.set(roleAuthc.apiKeyHeader));
// expect a different, legitimate error when we use the internal header
// the config does not contain decryptionOnlyKeys, so when the API is
// called successfully, it will error for this reason, and not for an
// access or or missing header reason
expect(body).toEqual({
statusCode: 400,
error: 'Bad Request',
message: expect.stringContaining(
'Kibana is not configured to support encryption key rotation. Update `kibana.yml` to include `xpack.encryptedSavedObjects.keyRotation.decryptionOnlyKeys` to rotate your encryption keys.'
),
});
expect(status).toBe(400);
});
});
});
Expand Down