Skip to content

Commit

Permalink
Splitting apiKey generation from setup variables
Browse files Browse the repository at this point in the history
  • Loading branch information
yngrdyn committed Jun 7, 2023
1 parent 6b37769 commit c182f03
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 79 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import React from 'react';
import { APIReturnType } from '../../../../services/rest/create_call_api';

type ApiKeyPayload =
APIReturnType<'POST /internal/observability_onboarding/custom_logs/install_shipper_setup'>;
APIReturnType<'POST /internal/observability_onboarding/custom_logs/save'>;

export function ApiKeyBanner({
status,
Expand All @@ -41,7 +41,7 @@ export function ApiKeyBanner({
</EuiFlexItem>
<EuiFlexItem>
{i18n.translate(
'xpack.observabilityOnboarding.apiKeyBanner.loading',
'xpack.observability_onboarding.apiKeyBanner.loading',
{
defaultMessage: 'Creating API Key',
}
Expand All @@ -56,7 +56,7 @@ export function ApiKeyBanner({
const apiKeySuccessCallout = (
<EuiCallOut
title={i18n.translate(
'xpack.observabilityOnboarding.apiKeyBanner.created',
'xpack.observability_onboarding.apiKeyBanner.created',
{
defaultMessage: 'API Key created.',
}
Expand All @@ -66,7 +66,7 @@ export function ApiKeyBanner({
>
<p>
{i18n.translate(
'xpack.observabilityOnboarding.apiKeyBanner.created.description',
'xpack.observability_onboarding.apiKeyBanner.created.description',
{
defaultMessage:
'Remember to store this information in a safe place. It won’t be displayed anymore after you continue.',
Expand All @@ -78,9 +78,9 @@ export function ApiKeyBanner({
readOnly
value={payload?.apiKeyEncoded}
aria-label={i18n.translate(
'xpack.apm.settings.agentKeys.copyAgentKeyField.agentKeyLabel',
'xpack.observability_onboarding.apiKeyBanner.field.label',
{
defaultMessage: 'APM agent key',
defaultMessage: 'Api Key',
}
)}
append={
Expand All @@ -92,7 +92,7 @@ export function ApiKeyBanner({
color="success"
style={{ backgroundColor: 'transparent' }}
aria-label={i18n.translate(
'xpack.apm.settings.agentKeys.copyAgentKeyField.copyButton',
'xpack.observability_onboarding.apiKeyBanner.field.copyButton',
{
defaultMessage: 'Copy to clipboard',
}
Expand All @@ -108,7 +108,7 @@ export function ApiKeyBanner({
const apiKeyFailureCallout = (
<EuiCallOut
title={i18n.translate(
'xpack.observabilityOnboarding.apiKeyBanner.failed',
'xpack.observability_onboarding.apiKeyBanner.failed',
{
defaultMessage: 'Failed to create API key.',
}
Expand All @@ -118,7 +118,7 @@ export function ApiKeyBanner({
>
<p>
{i18n.translate(
'xpack.observabilityOnboarding.apiKeyBanner.failed.description',
'xpack.observability_onboarding.apiKeyBanner.failed.description',
{
defaultMessage: 'Something went wrong: {message}',
values: {
Expand All @@ -133,7 +133,7 @@ export function ApiKeyBanner({
const noPermissionsCallout = (
<EuiCallOut
title={i18n.translate(
'xpack.observabilityOnboarding.apiKeyBanner.noPermissions',
'xpack.observability_onboarding.apiKeyBanner.noPermissions',
{
defaultMessage: 'User does not have permissions to create API key.',
}
Expand All @@ -143,7 +143,7 @@ export function ApiKeyBanner({
>
<p>
{i18n.translate(
'xpack.observabilityOnboarding.apiKeyBanner.noPermissions.description',
'xpack.observability_onboarding.apiKeyBanner.noPermissions.description',
{
defaultMessage:
'Please add the key generated by the admin in the dedicated space in the config below.',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,23 @@ export function InstallElasticAgent() {
goBack();
}

const { data: monitoringRole } = useFetcher((callApi) => {
return callApi(
'GET /internal/observability_onboarding/custom_logs/privileges'
);
const { data: monitoringRole, status: monitoringRoleStatus } = useFetcher(
(callApi) => {
if (CurrentStep === InstallElasticAgent) {
return callApi(
'GET /internal/observability_onboarding/custom_logs/privileges'
);
}
},
[]
);

const { data: setup } = useFetcher((callApi) => {
if (CurrentStep === InstallElasticAgent) {
return callApi(
'GET /internal/observability_onboarding/custom_logs/install_shipper_setup'
);
}
}, []);

const {
Expand All @@ -58,7 +71,7 @@ export function InstallElasticAgent() {
monitoringRole?.hasPrivileges
) {
return callApi(
'POST /internal/observability_onboarding/custom_logs/install_shipper_setup',
'POST /internal/observability_onboarding/custom_logs/save',
{
params: {
body: {
Expand All @@ -75,16 +88,12 @@ export function InstallElasticAgent() {
);
}
},
[monitoringRole],
{ showToastOnError: false }
[monitoringRole?.hasPrivileges]
);

const { data: yamlConfig = '', status: yamlConfigStatus } = useFetcher(
(callApi) => {
if (
CurrentStep === InstallElasticAgent &&
installShipperSetup?.apiKeyEncoded
) {
if (CurrentStep === InstallElasticAgent) {
const options = {
headers: {
authorization: `ApiKey ${installShipperSetup?.apiKeyEncoded}`,
Expand All @@ -97,7 +106,7 @@ export function InstallElasticAgent() {
);
}
},
[installShipperSetup?.apiKeyId, installShipperSetup?.apiKeyEncoded]
[installShipperSetup?.apiKeyEncoded]
);

const apiKeyEncoded = installShipperSetup?.apiKeyEncoded;
Expand All @@ -115,15 +124,18 @@ export function InstallElasticAgent() {
</p>
</EuiText>
<EuiSpacer size="m" />
<ApiKeyBanner
payload={installShipperSetup}
status={
monitoringRole?.hasPrivileges
? installShipperSetupStatus
: 'noPrivileges'
}
error={error}
/>
{monitoringRoleStatus !== FETCH_STATUS.NOT_INITIATED &&
monitoringRoleStatus !== FETCH_STATUS.LOADING && (
<ApiKeyBanner
payload={installShipperSetup}
status={
monitoringRole?.hasPrivileges
? installShipperSetupStatus
: 'noPrivileges'
}
error={error}
/>
)}
<EuiSpacer size="m" />
<EuiSteps
steps={[
Expand Down Expand Up @@ -159,25 +171,14 @@ export function InstallElasticAgent() {
}
/>
<EuiSpacer size="m" />
<EuiSkeletonRectangle
isLoading={
installShipperSetupStatus === FETCH_STATUS.LOADING
}
contentAriaLabel="Command to install elastic agent"
width="100%"
height={80}
borderRadius="s"
>
<EuiCodeBlock language="bash" isCopyable>
{getInstallShipperCommand({
elasticAgentPlatform,
apiKeyEncoded,
apiEndpoint: installShipperSetup?.apiEndpoint,
scriptDownloadUrl:
installShipperSetup?.scriptDownloadUrl,
})}
</EuiCodeBlock>
</EuiSkeletonRectangle>
<EuiCodeBlock language="bash" isCopyable>
{getInstallShipperCommand({
elasticAgentPlatform,
apiKeyEncoded,
apiEndpoint: setup?.apiEndpoint,
scriptDownloadUrl: setup?.scriptDownloadUrl,
})}
</EuiCodeBlock>
</>
),
},
Expand All @@ -197,7 +198,7 @@ export function InstallElasticAgent() {
</EuiText>
<EuiSpacer size="m" />
<EuiSkeletonRectangle
isLoading={yamlConfigStatus === FETCH_STATUS.LOADING}
isLoading={yamlConfigStatus === FETCH_STATUS.NOT_INITIATED}
contentAriaLabel="Elastic agent yaml configuration"
width="100%"
height={300}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@ import { HTTPAuthorizationHeader } from '@kbn/security-plugin/server';

export const getAuthenticationAPIKey = (request: KibanaRequest) => {
const authorizationHeader = HTTPAuthorizationHeader.parseFromRequest(request);
if (!authorizationHeader) {
throw new Error('Authorization header is missing');
}

// If we don't perform this check we could end up exposing user password because this will return
// something similar to username:password when we are using basic authentication
if (authorizationHeader.scheme.toLowerCase() !== 'apikey') {
return null;
}

if (authorizationHeader && authorizationHeader.credentials) {
const apiKey = Buffer.from(authorizationHeader.credentials, 'base64')
.toString()
Expand All @@ -19,5 +29,4 @@ export const getAuthenticationAPIKey = (request: KibanaRequest) => {
apiKey: apiKey[1],
};
}
throw new Error('Authorization header is missing');
};
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,41 @@ const logMonitoringPrivilegesRoute = createObservabilityOnboardingServerRoute({
},
});

const createApiKeyRoute = createObservabilityOnboardingServerRoute({
const installShipperSetupRoute = createObservabilityOnboardingServerRoute({
endpoint:
'POST /internal/observability_onboarding/custom_logs/install_shipper_setup',
'GET /internal/observability_onboarding/custom_logs/install_shipper_setup',
options: { tags: [] },
async handler(resources): Promise<{
apiEndpoint: string;
scriptDownloadUrl: string;
esHost: string;
}> {
const { core, plugins } = resources;
const coreStart = await core.start();
const scriptDownloadUrl = getKibanaUrl(
coreStart,
'/plugins/observabilityOnboarding/assets/standalone_agent_setup.sh'
);
const apiEndpoint = getKibanaUrl(
coreStart,
'/api/observability_onboarding/custom_logs'
);

const [esHost] = getESHosts({
cloudSetup: plugins.cloud.setup,
esClient: coreStart.elasticsearch.client.asInternalUser as Client,
});

return {
apiEndpoint,
scriptDownloadUrl,
esHost,
};
},
});

const createApiKeyRoute = createObservabilityOnboardingServerRoute({
endpoint: 'POST /internal/observability_onboarding/custom_logs/save',
options: { tags: [] },
params: t.type({
body: t.type({
Expand All @@ -55,39 +87,23 @@ const createApiKeyRoute = createObservabilityOnboardingServerRoute({
async handler(resources): Promise<{
apiKeyId: string;
apiKeyEncoded: string;
apiEndpoint: string;
scriptDownloadUrl: string;
esHost: string;
}> {
const {
context,
params: {
body: { name, state },
},
core,
plugins,
request,
} = resources;
const coreStart = await core.start();
const scriptDownloadUrl = getKibanaUrl(
coreStart,
'/plugins/observabilityOnboarding/assets/standalone_agent_setup.sh'
);
const apiEndpoint = getKibanaUrl(
coreStart,
'/api/observability_onboarding/custom_logs'
);
const {
elasticsearch: { client },
} = await context.core;
const { id: apiKeyId, encoded: apiKeyEncoded } = await createShipperApiKey(
client.asCurrentUser,
name
);
const [esHost] = getESHosts({
cloudSetup: plugins.cloud.setup,
esClient: coreStart.elasticsearch.client.asInternalUser as Client,
});

const savedObjectsClient = coreStart.savedObjects.getScopedClient(request);

Expand All @@ -100,9 +116,6 @@ const createApiKeyRoute = createObservabilityOnboardingServerRoute({
return {
apiKeyId, // key the status off this
apiKeyEncoded,
apiEndpoint,
scriptDownloadUrl,
esHost,
};
},
});
Expand All @@ -128,15 +141,15 @@ const stepProgressUpdateRoute = createObservabilityOnboardingServerRoute({
request,
core,
} = resources;
const { apiKeyId } = getAuthenticationAPIKey(request);
const authApiKey = getAuthenticationAPIKey(request);
const coreStart = await core.start();
const savedObjectsClient =
coreStart.savedObjects.createInternalRepository();

const savedObservabilityOnboardingState =
await getObservabilityOnboardingState({
savedObjectsClient,
apiKeyId,
apiKeyId: authApiKey?.apiKeyId as string,
});

if (!savedObservabilityOnboardingState) {
Expand All @@ -150,7 +163,7 @@ const stepProgressUpdateRoute = createObservabilityOnboardingServerRoute({
savedObservabilityOnboardingState;
await saveObservabilityOnboardingState({
savedObjectsClient,
apiKeyId,
apiKeyId: authApiKey?.apiKeyId as string,
observabilityOnboardingState: {
...observabilityOnboardingState,
progress: {
Expand Down Expand Up @@ -270,6 +283,7 @@ const deleteStatesRoute = createObservabilityOnboardingServerRoute({

export const customLogsRouteRepository = {
...logMonitoringPrivilegesRoute,
...installShipperSetupRoute,
...createApiKeyRoute,
...stepProgressUpdateRoute,
...getStateRoute,
Expand Down
Loading

0 comments on commit c182f03

Please sign in to comment.