Skip to content

Commit

Permalink
[Security Solution][Endpoint] Update the run_endpoint_agent dev scr…
Browse files Browse the repository at this point in the history
…ipt to support use of an API Key (elastic#190449)

## Summary

- Updates the
`/x-pack/plugins/security_solution/scripts/endpoint/run_endpoint_agent.js`
with a new optional argument: `--apiKey`
- This argument enables use of a Kibana/ES API key with the script
instead of `--username` and `--password`
- Ideal for use against Serverless environments where the use of
`username/password` is not ideal
  • Loading branch information
paul-tavares authored Sep 3, 2024
1 parent 8928aeb commit 243b4fa
Show file tree
Hide file tree
Showing 5 changed files with 25 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,16 @@ import type { StatusResponse } from '@kbn/core-status-common-internal';
import { catchAxiosErrorFormatAndThrow } from '../format_axios_error';

export const fetchKibanaStatus = async (kbnClient: KbnClient): Promise<StatusResponse> => {
return (await kbnClient.status.get().catch(catchAxiosErrorFormatAndThrow)) as StatusResponse;
// We DO NOT use `kbnClient.status.get()` here because the `kbnClient` passed on input could be our enhanced
// client (created by `x-pack/plugins/security_solution/scripts/endpoint/common/stack_services.ts:267`)
// which could be using an API key (which the core KbnClient does not support)
return kbnClient
.request({
method: 'GET',
path: '/api/status',
})
.then((response) => response.data as StatusResponse)
.catch(catchAxiosErrorFormatAndThrow);
};
/**
* Checks to see if Kibana/ES is running in serverless mode
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,11 @@ interface CreateRuntimeServicesOptions {
class KbnClientExtended extends KbnClient {
private readonly apiKey: string | undefined;

constructor({ apiKey, url, ...options }: KbnClientOptions & { apiKey?: string }) {
constructor(protected readonly options: KbnClientOptions & { apiKey?: string }) {
const { apiKey, url, ...opt } = options;

super({
...options,
...opt,
url: apiKey ? buildUrlWithCredentials(url, '', '') : url,
});

Expand All @@ -94,6 +96,7 @@ class KbnClientExtended extends KbnClient {

if (this.apiKey) {
headers.Authorization = `ApiKey ${this.apiKey}`;
this.options.log.verbose(`Adding API key header to request header 'Authorization'`);
}

return super.request({
Expand Down Expand Up @@ -322,7 +325,7 @@ export const fetchStackVersion = async (kbnClient: KbnClient): Promise<string> =
export const waitForKibana = async (kbnClient: KbnClient): Promise<void> => {
await pRetry(
async () => {
const response = await kbnClient.status.get();
const response = await fetchKibanaStatus(kbnClient);

if (response.status.overall.level !== 'available') {
throw new Error(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { setupAll } from './setup';
const runSetupAll: RunFn = async (cliContext) => {
const username = cliContext.flags.username as string;
const password = cliContext.flags.password as string;
const apiKey = cliContext.flags.apiKey as string;
const kibanaUrl = cliContext.flags.kibanaUrl as string;
const elasticUrl = cliContext.flags.elasticUrl as string;
const fleetServerUrl = cliContext.flags.fleetServerUrl as string;
Expand All @@ -25,6 +26,7 @@ const runSetupAll: RunFn = async (cliContext) => {
fleetServerUrl,
username,
password,
apiKey,
version,
policy,
log,
Expand All @@ -43,12 +45,13 @@ export const cli = () => {
'multipass', install Elastic Agent and enroll it with Fleet. Can be used multiple times
against the same stack.`,
flags: {
string: ['kibana', 'elastic', 'username', 'password', 'version', 'policy'],
string: ['kibana', 'elastic', 'username', 'password', 'version', 'policy', 'apiKey'],
default: {
kibanaUrl: 'http://127.0.0.1:5601',
elasticUrl: 'http://127.0.0.1:9200',
username: 'elastic',
password: 'changeme',
apiKey: '',
version: '',
policy: '',
},
Expand All @@ -62,6 +65,8 @@ export const cli = () => {
--username Optional. User name to be used for auth against elasticsearch and
kibana (Default: elastic).
--password Optional. Password associated with the username (Default: changeme)
--apiKey Optional. A Kibana API key to use for authz. When defined, 'username'
and 'password' arguments are ignored.
--kibanaUrl Optional. The url to Kibana (Default: http://127.0.0.1:5601)
--elasticUrl Optional. The url to Elasticsearch (Default: http://127.0.0.1:9200)
`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export const startRuntimeServices = async ({
fleetServerUrl,
username,
password,
apiKey,
...otherOptions
}: StartRuntimeServicesOptions) => {
const stackServices = await createRuntimeServices({
Expand All @@ -36,6 +37,7 @@ export const startRuntimeServices = async ({
fleetServerUrl,
username,
password,
apiKey,
log,
asSuperuser: otherOptions?.asSuperuser,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export interface StartRuntimeServicesOptions {
fleetServerUrl?: string;
username: string;
password: string;
apiKey?: string;
version?: string;
policy?: string;
log?: ToolingLog;
Expand Down

0 comments on commit 243b4fa

Please sign in to comment.