Require gold license for ECS audit logging (#85537)

* Require gold license for ECS audit logging

* Fix unit test

* Add suggestions from code review
This commit is contained in:
Thom Heymann 2020-12-10 16:34:26 +00:00 committed by GitHub
parent a34cd20498
commit 051bbf073e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 70 additions and 40 deletions

View file

@ -43,6 +43,12 @@ export interface SecurityLicenseFeatures {
*/
readonly allowAuditLogging: boolean;
/**
* Indicates whether we allow logging of legacy audit events.
* @deprecated
*/
readonly allowLegacyAuditLogging: boolean;
/**
* Indicates whether we allow users to define document level security in roles.
*/

View file

@ -26,6 +26,7 @@ describe('license features', function () {
allowRbac: false,
allowSubFeaturePrivileges: false,
allowAuditLogging: false,
allowLegacyAuditLogging: false,
});
});
@ -48,6 +49,7 @@ describe('license features', function () {
allowRbac: false,
allowSubFeaturePrivileges: false,
allowAuditLogging: false,
allowLegacyAuditLogging: false,
});
});
@ -69,6 +71,7 @@ describe('license features', function () {
Object {
"allowAccessAgreement": false,
"allowAuditLogging": false,
"allowLegacyAuditLogging": false,
"allowLogin": false,
"allowRbac": false,
"allowRoleDocumentLevelSecurity": false,
@ -90,6 +93,7 @@ describe('license features', function () {
Object {
"allowAccessAgreement": true,
"allowAuditLogging": true,
"allowLegacyAuditLogging": true,
"allowLogin": true,
"allowRbac": true,
"allowRoleDocumentLevelSecurity": true,
@ -128,6 +132,7 @@ describe('license features', function () {
allowRbac: true,
allowSubFeaturePrivileges: false,
allowAuditLogging: false,
allowLegacyAuditLogging: false,
});
expect(getFeatureSpy).toHaveBeenCalledTimes(1);
expect(getFeatureSpy).toHaveBeenCalledWith('security');
@ -153,10 +158,36 @@ describe('license features', function () {
allowRbac: false,
allowSubFeaturePrivileges: false,
allowAuditLogging: false,
allowLegacyAuditLogging: false,
});
});
it('should allow role mappings, access agreement and sub-feature privileges, but not DLS/FLS if license = gold', () => {
it('should allow all basic features for standard license', () => {
const mockRawLicense = licenseMock.createLicense({
license: { mode: 'standard', type: 'standard' },
features: { security: { isEnabled: true, isAvailable: true } },
});
const serviceSetup = new SecurityLicenseService().setup({
license$: of(mockRawLicense),
});
expect(serviceSetup.license.isLicenseAvailable()).toEqual(true);
expect(serviceSetup.license.getFeatures()).toEqual({
showLogin: true,
allowLogin: true,
showLinks: true,
showRoleMappingsManagement: false,
allowAccessAgreement: false,
allowRoleDocumentLevelSecurity: false,
allowRoleFieldLevelSecurity: false,
allowRbac: true,
allowSubFeaturePrivileges: false,
allowAuditLogging: false,
allowLegacyAuditLogging: true,
});
});
it('should allow role mappings, access agreement, sub-feature privileges and audit logging, but not DLS/FLS if license = gold', () => {
const mockRawLicense = licenseMock.createLicense({
license: { mode: 'gold', type: 'gold' },
features: { security: { isEnabled: true, isAvailable: true } },
@ -177,6 +208,7 @@ describe('license features', function () {
allowRbac: true,
allowSubFeaturePrivileges: true,
allowAuditLogging: true,
allowLegacyAuditLogging: true,
});
});
@ -201,30 +233,7 @@ describe('license features', function () {
allowRbac: true,
allowSubFeaturePrivileges: true,
allowAuditLogging: true,
});
});
it('should allow all basic features + audit logging for standard license', () => {
const mockRawLicense = licenseMock.createLicense({
license: { mode: 'standard', type: 'standard' },
features: { security: { isEnabled: true, isAvailable: true } },
});
const serviceSetup = new SecurityLicenseService().setup({
license$: of(mockRawLicense),
});
expect(serviceSetup.license.isLicenseAvailable()).toEqual(true);
expect(serviceSetup.license.getFeatures()).toEqual({
showLogin: true,
allowLogin: true,
showLinks: true,
showRoleMappingsManagement: false,
allowAccessAgreement: false,
allowRoleDocumentLevelSecurity: false,
allowRoleFieldLevelSecurity: false,
allowRbac: true,
allowSubFeaturePrivileges: false,
allowAuditLogging: true,
allowLegacyAuditLogging: true,
});
});
});

View file

@ -79,6 +79,7 @@ export class SecurityLicenseService {
showRoleMappingsManagement: false,
allowAccessAgreement: false,
allowAuditLogging: false,
allowLegacyAuditLogging: false,
allowRoleDocumentLevelSecurity: false,
allowRoleFieldLevelSecurity: false,
allowRbac: false,
@ -98,6 +99,7 @@ export class SecurityLicenseService {
showRoleMappingsManagement: false,
allowAccessAgreement: false,
allowAuditLogging: false,
allowLegacyAuditLogging: false,
allowRoleDocumentLevelSecurity: false,
allowRoleFieldLevelSecurity: false,
allowRbac: false,
@ -114,7 +116,8 @@ export class SecurityLicenseService {
showLinks: true,
showRoleMappingsManagement: isLicenseGoldOrBetter,
allowAccessAgreement: isLicenseGoldOrBetter,
allowAuditLogging: isLicenseStandardOrBetter,
allowAuditLogging: isLicenseGoldOrBetter,
allowLegacyAuditLogging: isLicenseStandardOrBetter,
allowSubFeaturePrivileges: isLicenseGoldOrBetter,
// Only platinum and trial licenses are compliant with field- and document-level security.
allowRoleDocumentLevelSecurity: isLicensePlatinumOrBetter,

View file

@ -358,7 +358,7 @@ describe('#getLogger', () => {
const licenseWithFeatures = licenseMock.create();
licenseWithFeatures.features$ = new BehaviorSubject({
allowAuditLogging: true,
allowLegacyAuditLogging: true,
} as SecurityLicenseFeatures).asObservable();
const auditService = new AuditService(logger).setup({
@ -388,7 +388,7 @@ describe('#getLogger', () => {
const licenseWithFeatures = licenseMock.create();
licenseWithFeatures.features$ = new BehaviorSubject({
allowAuditLogging: true,
allowLegacyAuditLogging: true,
} as SecurityLicenseFeatures).asObservable();
const auditService = new AuditService(logger).setup({
@ -426,7 +426,7 @@ describe('#getLogger', () => {
const licenseWithFeatures = licenseMock.create();
licenseWithFeatures.features$ = new BehaviorSubject({
allowAuditLogging: false,
allowLegacyAuditLogging: false,
} as SecurityLicenseFeatures).asObservable();
const auditService = new AuditService(logger).setup({
@ -452,7 +452,7 @@ describe('#getLogger', () => {
const licenseWithFeatures = licenseMock.create();
licenseWithFeatures.features$ = new BehaviorSubject({
allowAuditLogging: true,
allowLegacyAuditLogging: true,
} as SecurityLicenseFeatures).asObservable();
const auditService = new AuditService(logger).setup({
@ -481,7 +481,7 @@ describe('#getLogger', () => {
const licenseWithFeatures = licenseMock.create();
const features$ = new BehaviorSubject({
allowAuditLogging: false,
allowLegacyAuditLogging: false,
} as SecurityLicenseFeatures);
licenseWithFeatures.features$ = features$.asObservable();
@ -505,7 +505,7 @@ describe('#getLogger', () => {
// perform license upgrade
features$.next({
allowAuditLogging: true,
allowLegacyAuditLogging: true,
} as SecurityLicenseFeatures);
auditLogger.log(eventType, message);

View file

@ -70,7 +70,7 @@ export class AuditService {
/**
* @deprecated
*/
private allowAuditLogging = false;
private allowLegacyAuditLogging = false;
private ecsLogger: Logger;
@ -87,9 +87,11 @@ export class AuditService {
getSpaceId,
}: AuditServiceSetupParams): AuditServiceSetup {
if (config.enabled && !config.appender) {
this.licenseFeaturesSubscription = license.features$.subscribe(({ allowAuditLogging }) => {
this.allowAuditLogging = allowAuditLogging;
});
this.licenseFeaturesSubscription = license.features$.subscribe(
({ allowLegacyAuditLogging }) => {
this.allowLegacyAuditLogging = allowLegacyAuditLogging;
}
);
}
// Configure logging during setup and when license changes
@ -169,7 +171,7 @@ export class AuditService {
const getLogger = (id?: string): LegacyAuditLogger => {
return {
log: (eventType: string, message: string, data?: Record<string, any>) => {
if (!this.allowAuditLogging) {
if (!this.allowLegacyAuditLogging) {
return;
}

View file

@ -173,6 +173,7 @@ describe('Login view routes', () => {
showRoleMappingsManagement: true,
allowSubFeaturePrivileges: true,
allowAuditLogging: true,
allowLegacyAuditLogging: true,
showLogin: true,
});

View file

@ -31,6 +31,7 @@ describe('Security UsageCollector', () => {
license.getFeatures.mockReturnValue({
allowAccessAgreement,
allowAuditLogging,
allowLegacyAuditLogging: allowAuditLogging,
allowRbac,
} as SecurityLicenseFeatures);
return license;

View file

@ -75,7 +75,12 @@ export function registerSecurityUsageCollector({ usageCollection, config, licens
},
},
fetch: () => {
const { allowRbac, allowAccessAgreement, allowAuditLogging } = license.getFeatures();
const {
allowRbac,
allowAccessAgreement,
allowAuditLogging,
allowLegacyAuditLogging,
} = license.getFeatures();
if (!allowRbac) {
return {
auditLoggingEnabled: false,
@ -87,7 +92,10 @@ export function registerSecurityUsageCollector({ usageCollection, config, licens
};
}
const auditLoggingEnabled = allowAuditLogging && config.audit.enabled;
const legacyAuditLoggingEnabled = allowLegacyAuditLogging && config.audit.enabled;
const auditLoggingEnabled =
allowAuditLogging && config.audit.enabled && config.audit.appender != null;
const loginSelectorEnabled = config.authc.selector.enabled;
const authProviderCount = config.authc.sortedProviders.length;
const enabledAuthProviders = [
@ -107,7 +115,7 @@ export function registerSecurityUsageCollector({ usageCollection, config, licens
);
return {
auditLoggingEnabled,
auditLoggingEnabled: legacyAuditLoggingEnabled || auditLoggingEnabled,
loginSelectorEnabled,
accessAgreementEnabled,
authProviderCount,