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

[ML] Adds secondary authorization header to Transforms in Fleet #154665

Merged
merged 25 commits into from
Apr 20, 2023
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
1056f2f
Cherry pick only Fleet changes
qn895 Apr 6, 2023
a151080
Cherry pick only Fleet changes
qn895 Apr 7, 2023
59b7541
Fix i18n and types
qn895 Apr 10, 2023
605b27b
Fix tests
qn895 Apr 10, 2023
918c9c4
[CI] Auto-commit changed files from 'node scripts/lint_ts_projects --…
kibanamachine Apr 10, 2023
b74f843
[ML] Update hash
qn895 Apr 11, 2023
bef90f7
Merge remote-tracking branch 'upstream/main' into ml-fleet-2nd-auth
qn895 Apr 11, 2023
bc55ec8
[ML] Add username to transform meta
qn895 Apr 11, 2023
40802ff
[ML] Add callout message
qn895 Apr 11, 2023
98a01d4
[ML] Fix messaging
qn895 Apr 11, 2023
2885aa6
Merge remote-tracking branch 'upstream/main' into ml-fleet-2nd-auth
qn895 Apr 11, 2023
49562f4
[Fleet] Fix test
qn895 Apr 12, 2023
d11196c
[Fleet] Fix deferred missing due to transform not set to auto start
qn895 Apr 12, 2023
1cf340f
Merge upstream/main into branch
qn895 Apr 12, 2023
5bb5690
Add run_as_kibana_system check
qn895 Apr 13, 2023
d9b9da5
Add run_as_kibana_system check per transform basis
qn895 Apr 13, 2023
1400547
Merge remote-tracking branch 'upstream/main' into ml-fleet-2nd-auth
qn895 Apr 15, 2023
4d2eb77
Merge remote-tracking branch 'upstream/main' into ml-fleet-2nd-auth
qn895 Apr 17, 2023
0870d08
Remove todo
qn895 Apr 17, 2023
4e54dee
- Add key to fragment to rid of React errors
qn895 Apr 18, 2023
73b1216
Merge remote-tracking branch 'upstream/main' into ml-fleet-2nd-auth
qn895 Apr 18, 2023
22b5f9d
Merge remote-tracking branch 'upstream/main' into ml-fleet-2nd-auth
qn895 Apr 19, 2023
c7ad1c7
Update messaging
qn895 Apr 19, 2023
57bc06a
Merge remote-tracking branch 'upstream/main' into ml-fleet-2nd-auth
qn895 Apr 20, 2023
0187c5f
Add icon, remove fixme
qn895 Apr 20, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ describe('checking migration metadata changes on all registered SO types', () =>
"endpoint:user-artifact": "a5b154962fb6cdf5d9e7452e58690054c95cc72a",
"endpoint:user-artifact-manifest": "5989989c0f84dd2d02da1eb46b6254e334bd2ccd",
"enterprise_search_telemetry": "4b41830e3b28a16eb92dee0736b44ae6276ced9b",
"epm-packages": "83235af7c95fd9bfb1d70996a5511e05b3fcc9ef",
"epm-packages": "8755f947a00613f994b1bc5d5580e104043e27f6",
"epm-packages-assets": "00c8b5e5bf059627ffc9fbde920e1ac75926c5f6",
"event_loop_delays_daily": "ef49e7f15649b551b458c7ea170f3ed17f89abd0",
"exception-list": "38181294f64fc406c15f20d85ca306c8a4feb3c0",
Expand Down
29 changes: 29 additions & 0 deletions x-pack/plugins/fleet/common/authz.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

import { DEFAULT_APP_CATEGORIES } from '@kbn/core-application-common';

import { TRANSFORM_PLUGIN_ID } from './constants/plugin';

import {
calculatePackagePrivilegesFromCapabilities,
calculatePackagePrivilegesFromKibanaPrivileges,
Expand Down Expand Up @@ -39,16 +41,33 @@ describe('fleet authz', () => {
writeHostIsolationExceptions: true,
writeHostIsolation: false,
};

const transformCapabilities = {
canCreateTransform: false,
canDeleteTransform: false,
canGetTransform: true,
canStartStopTransform: false,
};

const expected = {
endpoint: {
actions: generateActions(ENDPOINT_PRIVILEGES, endpointCapabilities),
},
transform: {
actions: {
canCreateTransform: { executePackageAction: false },
canDeleteTransform: { executePackageAction: false },
canGetTransform: { executePackageAction: true },
canStartStopTransform: { executePackageAction: false },
},
},
};
const actual = calculatePackagePrivilegesFromCapabilities({
navLinks: {},
management: {},
catalogue: {},
siem: endpointCapabilities,
transform: transformCapabilities,
});

expect(actual).toEqual(expected);
Expand All @@ -65,6 +84,8 @@ describe('fleet authz', () => {
{ privilege: `${SECURITY_SOLUTION_ID}-writeHostIsolationExceptions`, authorized: true },
{ privilege: `${SECURITY_SOLUTION_ID}-writeHostIsolation`, authorized: false },
{ privilege: `${SECURITY_SOLUTION_ID}-ignoreMe`, authorized: true },
{ privilege: `${TRANSFORM_PLUGIN_ID}-admin`, authorized: true },
{ privilege: `${TRANSFORM_PLUGIN_ID}-read`, authorized: true },
];
const expected = {
endpoint: {
Expand All @@ -77,6 +98,14 @@ describe('fleet authz', () => {
writeHostIsolation: false,
}),
},
transform: {
actions: {
canCreateTransform: { executePackageAction: true },
canDeleteTransform: { executePackageAction: true },
canGetTransform: { executePackageAction: true },
canStartStopTransform: { executePackageAction: true },
},
},
};
const actual = calculatePackagePrivilegesFromKibanaPrivileges(endpointPrivileges);
expect(actual).toEqual(expected);
Expand Down
51 changes: 51 additions & 0 deletions x-pack/plugins/fleet/common/authz.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,16 @@

import type { Capabilities } from '@kbn/core-capabilities-common';

import { TRANSFORM_PLUGIN_ID } from './constants/plugin';

import { ENDPOINT_PRIVILEGES } from './constants';

export type TransformPrivilege =
| 'canGetTransform'
| 'canCreateTransform'
| 'canDeleteTransform'
| 'canStartStopTransform';

export interface FleetAuthz {
fleet: {
all: boolean;
Expand Down Expand Up @@ -106,10 +114,22 @@ export function calculatePackagePrivilegesFromCapabilities(
{}
);

const transformActions = Object.keys(capabilities.transform).reduce((acc, privilegeName) => {
return {
...acc,
[privilegeName]: {
executePackageAction: capabilities.transform[privilegeName] || false,
},
};
}, {});

return {
endpoint: {
actions: endpointActions,
},
transform: {
actions: transformActions,
},
};
}

Expand Down Expand Up @@ -158,9 +178,40 @@ export function calculatePackagePrivilegesFromKibanaPrivileges(
{}
);

const hasTransformAdmin = getAuthorizationFromPrivileges(
kibanaPrivileges,
`${TRANSFORM_PLUGIN_ID}-`,
`admin`
);
const transformActions: {
[key in TransformPrivilege]: {
executePackageAction: boolean;
};
} = {
canCreateTransform: {
executePackageAction: hasTransformAdmin,
},
canDeleteTransform: {
executePackageAction: hasTransformAdmin,
},
canStartStopTransform: {
executePackageAction: hasTransformAdmin,
},
canGetTransform: {
executePackageAction: getAuthorizationFromPrivileges(
kibanaPrivileges,
`${TRANSFORM_PLUGIN_ID}-`,
`read`
),
},
};

return {
endpoint: {
actions: endpointActions,
},
transform: {
actions: transformActions,
},
};
}
1 change: 1 addition & 0 deletions x-pack/plugins/fleet/common/constants/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@

export const PLUGIN_ID = 'fleet' as const;
export const INTEGRATIONS_PLUGIN_ID = 'integrations' as const;
export const TRANSFORM_PLUGIN_ID = 'transform' as const;
2 changes: 2 additions & 0 deletions x-pack/plugins/fleet/common/constants/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ export const EPM_API_ROUTES = {
INFO_PATTERN_DEPRECATED: EPM_PACKAGES_ONE_DEPRECATED,
INSTALL_FROM_REGISTRY_PATTERN_DEPRECATED: EPM_PACKAGES_ONE_DEPRECATED,
DELETE_PATTERN_DEPRECATED: EPM_PACKAGES_ONE_DEPRECATED,

REAUTHORIZE_TRANSFORMS: `${EPM_PACKAGES_ONE}/transforms/authorize`,
};

// Data stream API routes
Expand Down
59 changes: 59 additions & 0 deletions x-pack/plugins/fleet/common/http_authorization_header.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import type { KibanaRequest } from '@kbn/core/server';

// Extended version of x-pack/plugins/security/server/authentication/http_authentication/http_authorization_header.ts
// to prevent bundle being required in security_solution
// FIXME: Put this in a package
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this FIXME comment do we have an issue for the fix? When do we expect to fix it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed this FIXME for now as the file is modified from the original copy of security_solution's code 0187c5f (#154665)

export class HTTPAuthorizationHeader {
/**
* The authentication scheme. Should be consumed in a case-insensitive manner.
* https://www.iana.org/assignments/http-authschemes/http-authschemes.xhtml#authschemes
*/
readonly scheme: string;

/**
* The authentication credentials for the scheme.
*/
readonly credentials: string;

/**
* The authentication credentials for the scheme.
*/
readonly username: string | undefined;

constructor(scheme: string, credentials: string, username?: string) {
this.scheme = scheme;
this.credentials = credentials;
this.username = username;
}

/**
* Parses request's `Authorization` HTTP header if present.
* @param request Request instance to extract the authorization header from.
*/
static parseFromRequest(request: KibanaRequest, username?: string) {
const authorizationHeaderValue = request.headers.authorization;
if (!authorizationHeaderValue || typeof authorizationHeaderValue !== 'string') {
return null;
}

const [scheme] = authorizationHeaderValue.split(/\s+/);
const credentials = authorizationHeaderValue.substring(scheme.length + 1);

return new HTTPAuthorizationHeader(scheme, credentials, username);
}

toString() {
return `${this.scheme} ${this.credentials}`;
}

getUsername() {
return this.username;
}
}
8 changes: 8 additions & 0 deletions x-pack/plugins/fleet/common/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ export const createFleetAuthzMock = (): FleetAuthz => {
endpoint: {
actions: endpointActions,
},
transform: {
actions: {
canCreateTransform: { executePackageAction: true },
canDeleteTransform: { executePackageAction: true },
canGetTransform: { executePackageAction: true },
canStartStopTransform: { executePackageAction: true },
},
},
},
};
};
6 changes: 6 additions & 0 deletions x-pack/plugins/fleet/common/services/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ export const epmRouteService = {
pkgVersion
);
},

getReauthorizeTransformsPath: (pkgName: string, pkgVersion: string) => {
return EPM_API_ROUTES.REAUTHORIZE_TRANSFORMS.replace('{pkgName}', pkgName)
.replace('{pkgVersion}', pkgVersion)
.replace(/\/$/, ''); // trim trailing slash
},
};

export const packagePolicyRouteService = {
Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/fleet/common/types/models/epm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,7 @@ export interface IntegrationCardItem {
id: string;
categories: string[];
fromIntegrations?: string;
isReauthorizationRequired?: boolean;
isUnverified?: boolean;
isUpdateAvailable?: boolean;
showLabels?: boolean;
Expand Down Expand Up @@ -537,6 +538,7 @@ export type KibanaAssetReference = Pick<SavedObjectReference, 'id'> & {
};
export type EsAssetReference = Pick<SavedObjectReference, 'id'> & {
type: ElasticsearchAssetType;
deferred?: boolean;
};

export type PackageAssetReference = Pick<SavedObjectReference, 'id'> & {
Expand Down
19 changes: 19 additions & 0 deletions x-pack/plugins/fleet/common/types/models/transform_api_key.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import type { GrantAPIKeyResult } from '@kbn/security-plugin/server';

export interface TransformAPIKey extends GrantAPIKeyResult {
/**
* Generated encoded API key used for headers
*/
encoded: string;
}

export interface SecondaryAuthorizationHeader {
headers?: { 'es-secondary-authorization': string | string[] };
}
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,15 @@ describe('when on the package policy create page', () => {
fireEvent.click(renderResult.getByText(/Save and continue/).closest('button')!);
});

await waitFor(
async () => {
expect(
await renderResult.findByText(/Add Elastic Agent to your hosts/)
).toBeInTheDocument();
},
{ timeout: 10000 }
);

await act(async () => {
fireEvent.click(
renderResult.getByText(/Add Elastic Agent to your hosts/).closest('button')!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ import {
} from '@elastic/eui';
import type { EuiStepProps } from '@elastic/eui/src/components/steps/step';

import {
getNumTransformAssets,
TransformInstallWithCurrentUserPermissionCallout,
} from '../../../../../../components/transform_install_as_current_user_callout';

import { useCancelAddPackagePolicy } from '../hooks';

import { splitPkgKey } from '../../../../../../../common/services';
Expand Down Expand Up @@ -266,6 +271,11 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({
]
);

const numTransformAssets = useMemo(
() => getNumTransformAssets(packageInfo?.assets),
[packageInfo?.assets]
);

const extensionView = useUIExtension(packagePolicy.package?.name ?? '', 'package-policy-create');
const replaceDefineStepView = useUIExtension(
packagePolicy.package?.name ?? '',
Expand Down Expand Up @@ -406,6 +416,12 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({
integration={integrationInfo?.name}
/>
)}
{numTransformAssets > 0 ? (
<>
<TransformInstallWithCurrentUserPermissionCallout count={numTransformAssets} />
<EuiSpacer size="xl" />
</>
) : null}
<StepsWithLessPadding steps={steps} />
<EuiSpacer size="xl" />
<EuiSpacer size="xl" />
Expand Down
Loading