Skip to content

Commit

Permalink
Adds deprecation warnings for apiKey and elasticsearch_anonymous_user…
Browse files Browse the repository at this point in the history
… credentials of anonymous authentication providers.

Adds telemetry for usage of anonymous authentication credential type.
  • Loading branch information
jeramysoucy committed May 10, 2022
1 parent 7f07d24 commit 9cdb5c3
Show file tree
Hide file tree
Showing 6 changed files with 375 additions and 1 deletion.
6 changes: 5 additions & 1 deletion docs/settings/security-settings.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,8 @@ In addition to <<authentication-provider-settings,the settings that are valid fo
NOTE: You can configure only one anonymous provider per {kib} instance.

xpack.security.authc.providers.anonymous.<provider-name>.credentials {ess-icon}::
Credentials that {kib} should use internally to authenticate anonymous requests to {es}. Possible values are: username and password, API key, or the constant `elasticsearch_anonymous_user` if you want to leverage {ref}/anonymous-access.html[{es} anonymous access].
API Key and `elasticsearch_anonymous_user` credentials are deprecated. Use username and password credentials instead.
Credentials that {kib} should use internally to authenticate anonymous requests to {es}.
+
For example:
+
Expand All @@ -125,17 +126,20 @@ xpack.security.authc.providers.anonymous.anonymous1:
password: "anonymous_service_account_password"
# API key (concatenated and base64-encoded)
# Deprecated. Use username and password instead.
xpack.security.authc.providers.anonymous.anonymous1:
credentials:
apiKey: "VnVhQ2ZHY0JDZGJrUW0tZTVhT3g6dWkybHAyYXhUTm1zeWFrdzl0dk5udw=="
# API key (as returned from Elasticsearch API)
# Deprecated. Use username and password instead.
xpack.security.authc.providers.anonymous.anonymous1:
credentials:
apiKey.id: "VuaCfGcBCdbkQm-e5aOx"
apiKey.key: "ui2lp2axTNmsyakw9tvNnw"
# Elasticsearch anonymous access
# Deprecated. Use username and password instead.
xpack.security.authc.providers.anonymous.anonymous1:
credentials: "elasticsearch_anonymous_user"
----------------------------------------
Expand Down
88 changes: 88 additions & 0 deletions x-pack/plugins/security/server/config_deprecations.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -295,4 +295,92 @@ describe('Config Deprecations', () => {
]
`);
});

it(`warns that 'xpack.security.authc.providers.anonymous.<provider-name>.credentials.apiKey' is deprecated`, () => {
const config = {
xpack: {
security: {
authc: {
providers: {
anonymous: {
anonymous1: {
credentials: {
apiKey: 'VnVhQ2ZHY0JDZGJrUW0tZTVhT3g6dWkybHAyYXhUTm1zeWFrdzl0dk5udw==',
},
},
},
},
},
},
},
};
const { messages, configPaths } = applyConfigDeprecations(cloneDeep(config));
expect(messages).toMatchInlineSnapshot(`
Array [
"Support for apiKey is being removed from the 'anonymous' authentication provider. Use username and password credentials.",
]
`);

expect(configPaths).toEqual([
'xpack.security.authc.providers.anonymous.anonymous1.credentials.apiKey',
]);
});

it(`warns that 'xpack.security.authc.providers.anonymous.<provider-name>.credentials.apiKey' with id and key is deprecated`, () => {
const config = {
xpack: {
security: {
authc: {
providers: {
anonymous: {
anonymous1: {
credentials: {
apiKey: { id: 'VuaCfGcBCdbkQm-e5aOx', key: 'ui2lp2axTNmsyakw9tvNnw' },
},
},
},
},
},
},
},
};
const { messages, configPaths } = applyConfigDeprecations(cloneDeep(config));
expect(messages).toMatchInlineSnapshot(`
Array [
"Support for apiKey is being removed from the 'anonymous' authentication provider. Use username and password credentials.",
]
`);

expect(configPaths).toEqual([
'xpack.security.authc.providers.anonymous.anonymous1.credentials.apiKey',
]);
});

it(`warns that 'xpack.security.authc.providers.anonymous.<provider-name>.credentials' of 'elasticsearch_anonymous_user' is deprecated`, () => {
const config = {
xpack: {
security: {
authc: {
providers: {
anonymous: {
anonymous1: {
credentials: 'elasticsearch_anonymous_user',
},
},
},
},
},
},
};
const { messages, configPaths } = applyConfigDeprecations(cloneDeep(config));
expect(messages).toMatchInlineSnapshot(`
Array [
"Support for 'elasticsearch_anonymous_user' is being removed from the 'anonymous' authentication provider. Use username and password credentials.",
]
`);

expect(configPaths).toEqual([
'xpack.security.authc.providers.anonymous.anonymous1.credentials',
]);
});
});
53 changes: 53 additions & 0 deletions x-pack/plugins/security/server/config_deprecations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,4 +138,57 @@ export const securityConfigDeprecationProvider: ConfigDeprecationProvider = ({
});
}
},
(settings, _fromPath, addDeprecation, { branch }) => {
// TODO: remove when docs support "main"
const docsBranch = branch === 'main' ? 'master' : 'main';
const anonProviders = (settings?.xpack?.security?.authc?.providers?.anonymous ?? {}) as Record<
string,
any
>;

const credTypeElasticsearchAnonUser = 'elasticsearch_anonymous_user';
const credTypeApiKey = 'apiKey';

for (const provider of Object.entries(anonProviders)) {
if (
!!provider[1].credentials.apiKey ||
provider[1].credentials === credTypeElasticsearchAnonUser
) {
const isApiKey: boolean = !!provider[1].credentials.apiKey;
addDeprecation({
configPath: `xpack.security.authc.providers.anonymous.${provider[0]}.credentials${
isApiKey ? '.apiKey' : ''
}`,
title: i18n.translate(
'xpack.security.deprecations.anonymousApiKeyOrElasticsearchAnonUserTitle',
{
values: {
credType: isApiKey ? `${credTypeApiKey}` : `'${credTypeElasticsearchAnonUser}'`,
},
defaultMessage: `Use of {credType} for "xpack.security.authc.providers.anonymous.credentials" is deprecated.`,
}
),
message: i18n.translate(
'xpack.security.deprecations.anonymousApiKeyOrElasticsearchAnonUserMesage',
{
values: {
credType: isApiKey ? `${credTypeApiKey}` : `'${credTypeElasticsearchAnonUser}'`,
},
defaultMessage: `Support for {credType} is being removed from the 'anonymous' authentication provider. Use username and password credentials.`,
}
),
level: 'warning',
documentationUrl: `https://www.elastic.co/guide/en/kibana/${docsBranch}/security-settings-kb.html#authentication-security-settings`,
correctiveActions: {
manualSteps: [
i18n.translate('xpack.security.deprecations.anonAuthCredentials.manualSteps1', {
defaultMessage:
'Change anonymous authentication provider to use username and password credentials.',
}),
],
},
});
}
}
},
];
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ describe('Security UsageCollector', () => {
sessionIdleTimeoutInMinutes: 480,
sessionLifespanInMinutes: 43200,
sessionCleanupInMinutes: 60,
anonymousCredentialType: undefined,
};

describe('initialization', () => {
Expand Down Expand Up @@ -109,6 +110,7 @@ describe('Security UsageCollector', () => {
sessionIdleTimeoutInMinutes: 0,
sessionLifespanInMinutes: 0,
sessionCleanupInMinutes: 0,
anonymousCredentialType: undefined,
});
});

Expand Down Expand Up @@ -465,4 +467,197 @@ describe('Security UsageCollector', () => {
});
});
});

describe('anonymous auth credentials', () => {
it('reports anonymous credential of apiKey with id and key as api_key', async () => {
const config = createSecurityConfig(
ConfigSchema.validate({
authc: {
providers: {
anonymous: {
anonymous1: {
order: 1,
credentials: {
apiKey: { id: 'VuaCfGcBCdbkQm-e5aOx', key: 'ui2lp2axTNmsyakw9tvNnw' },
},
},
},
},
},
})
);
const usageCollection = usageCollectionPluginMock.createSetupContract();
const license = createSecurityLicense({ isLicenseAvailable: true, allowAuditLogging: false });
registerSecurityUsageCollector({ usageCollection, config, license });

const usage = await usageCollection
.getCollectorByType('security')
?.fetch(collectorFetchContext);

expect(usage).toEqual({
...DEFAULT_USAGE,
enabledAuthProviders: ['anonymous'],
anonymousCredentialType: 'api_key',
});
});

it('reports anonymous credential of apiKey as api_key', async () => {
const config = createSecurityConfig(
ConfigSchema.validate({
authc: {
providers: {
anonymous: {
anonymous1: {
order: 1,
credentials: {
apiKey: 'VnVhQ2ZHY0JDZGJrUW0tZTVhT3g6dWkybHAyYXhUTm1zeWFrdzl0dk5udw==',
},
},
},
},
},
})
);
const usageCollection = usageCollectionPluginMock.createSetupContract();
const license = createSecurityLicense({ isLicenseAvailable: true, allowAuditLogging: false });
registerSecurityUsageCollector({ usageCollection, config, license });

const usage = await usageCollection
.getCollectorByType('security')
?.fetch(collectorFetchContext);

expect(usage).toEqual({
...DEFAULT_USAGE,
enabledAuthProviders: ['anonymous'],
anonymousCredentialType: 'api_key',
});
});

it(`reports anonymous credential of 'elasticsearch_anonymous_user' as elasticsearch_anonymous_user`, async () => {
const config = createSecurityConfig(
ConfigSchema.validate({
authc: {
providers: {
anonymous: {
anonymous1: {
order: 1,
credentials: 'elasticsearch_anonymous_user',
},
},
},
},
})
);
const usageCollection = usageCollectionPluginMock.createSetupContract();
const license = createSecurityLicense({ isLicenseAvailable: true, allowAuditLogging: false });
registerSecurityUsageCollector({ usageCollection, config, license });

const usage = await usageCollection
.getCollectorByType('security')
?.fetch(collectorFetchContext);

expect(usage).toEqual({
...DEFAULT_USAGE,
enabledAuthProviders: ['anonymous'],
anonymousCredentialType: 'elasticsearch_anonymous_user',
});
});

it('reports anonymous credential of username and password as usernanme_password', async () => {
const config = createSecurityConfig(
ConfigSchema.validate({
authc: {
providers: {
anonymous: {
anonymous1: {
order: 1,
credentials: {
username: 'anonymous_service_account',
password: 'anonymous_service_account_password',
},
},
},
},
},
})
);
const usageCollection = usageCollectionPluginMock.createSetupContract();
const license = createSecurityLicense({ isLicenseAvailable: true, allowAuditLogging: false });
registerSecurityUsageCollector({ usageCollection, config, license });

const usage = await usageCollection
.getCollectorByType('security')
?.fetch(collectorFetchContext);

expect(usage).toEqual({
...DEFAULT_USAGE,
enabledAuthProviders: ['anonymous'],
anonymousCredentialType: 'username_password',
});
});

it('reports lack of anonymous credential as undefined', async () => {
const config = createSecurityConfig(ConfigSchema.validate({}));
const usageCollection = usageCollectionPluginMock.createSetupContract();
const license = createSecurityLicense({ isLicenseAvailable: true, allowAuditLogging: false });
registerSecurityUsageCollector({ usageCollection, config, license });

const usage = await usageCollection
.getCollectorByType('security')
?.fetch(collectorFetchContext);

expect(usage).toEqual({
...DEFAULT_USAGE,
enabledAuthProviders: ['basic'],
anonymousCredentialType: undefined,
});
});

it('reports the enabled anonymous credential of username and password as usernanme_password', async () => {
const config = createSecurityConfig(
ConfigSchema.validate({
authc: {
providers: {
anonymous: {
anonymous1: {
order: 1,
enabled: false,
credentials: {
apiKey: 'VnVhQ2ZHY0JDZGJrUW0tZTVhT3g6dWkybHAyYXhUTm1zeWFrdzl0dk5udw==',
},
},
anonymous2: {
order: 2,
credentials: {
username: 'anonymous_service_account',
password: 'anonymous_service_account_password',
},
},
anonymous3: {
order: 3,
enabled: false,
credentials: {
apiKey: { id: 'VuaCfGcBCdbkQm-e5aOx', key: 'ui2lp2axTNmsyakw9tvNnw' },
},
},
},
},
},
})
);
const usageCollection = usageCollectionPluginMock.createSetupContract();
const license = createSecurityLicense({ isLicenseAvailable: true, allowAuditLogging: false });
registerSecurityUsageCollector({ usageCollection, config, license });

const usage = await usageCollection
.getCollectorByType('security')
?.fetch(collectorFetchContext);

expect(usage).toEqual({
...DEFAULT_USAGE,
enabledAuthProviders: ['anonymous'],
anonymousCredentialType: 'username_password',
});
});
});
});
Loading

0 comments on commit 9cdb5c3

Please sign in to comment.