[Enterprise Search] Fix cloudId decoding on index detail (#137478)

* Fix cloudId decoding on index detail

* Add filepaths

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Efe Gürkan YALAMAN 2022-07-29 15:30:10 +02:00 committed by GitHub
parent ec15a9ce53
commit 8bd2c273f8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 177 additions and 11 deletions

View file

@ -21,6 +21,8 @@ import {
import { i18n } from '@kbn/i18n';
import { useCloudDetails } from '../../../shared/cloud_details/cloud_details';
import { decodeCloudId } from '../../utils/decode_cloud_id';
import { DOCUMENTS_API_JSON_EXAMPLE } from '../new_index/constants';
import { ClientLibrariesPopover } from './components/client_libraries_popover/popover';
@ -29,21 +31,15 @@ import { ManageKeysPopover } from './components/manage_api_keys_popover/popover'
import { OverviewLogic } from './overview.logic';
const getDeploymentUrls = (cloudId: string) => {
const [host, kibanaHost, elasticHost] = window.atob(cloudId);
return {
elasticUrl: `https://${elasticHost}.${host}`,
kibanaUrl: `https://${kibanaHost}.${host}`,
};
};
export const GenerateApiKeyPanel: React.FC = () => {
const { apiKey, isGenerateModalOpen, indexData } = useValues(OverviewLogic);
const { closeGenerateModal } = useActions(OverviewLogic);
const cloudContext = useCloudDetails();
const searchIndexApiUrl = cloudContext.cloudId
? getDeploymentUrls(cloudContext.cloudId).elasticUrl
: '<elasticsearch-host>:<elasticsearch-port>/';
const DEFAULT_URL = '<ELASTICSEARCH-HOST>:<ELASTICSEARCH-PORT>';
const searchIndexApiUrl =
(cloudContext.cloudId && decodeCloudId(cloudContext.cloudId)?.elasticsearchUrl) || DEFAULT_URL;
const apiKeyExample = apiKey || '<Create an API Key>';
@ -88,7 +84,7 @@ export const GenerateApiKeyPanel: React.FC = () => {
<EuiFlexItem>
<EuiCodeBlock language="bash" fontSize="m" isCopyable>
{`\
curl -X POST '${searchIndexApiUrl}${indexData?.name}/_doc' \\
curl -X POST '${searchIndexApiUrl}/${indexData?.name}/_doc' \\
-H 'Content-Type: application/json' \\
-H 'Authorization: ApiKey ${apiKeyExample}' \\
-d '${JSON.stringify(DOCUMENTS_API_JSON_EXAMPLE, null, 2)}'

View file

@ -0,0 +1,104 @@
/*
* 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 { decodeCloudId } from './decode_cloud_id';
// Copied from Fleet's solution
// x-pack/fleet/common/services/decode_cloud_id.test.ts
describe('Enterprise Search - decodeCloudId', () => {
it('parses various CloudID formats', () => {
const tests = [
{
cloudID:
'staging:dXMtZWFzdC0xLmF3cy5mb3VuZC5pbyRjZWM2ZjI2MWE3NGJmMjRjZTMzYmI4ODExYjg0Mjk0ZiRjNmMyY2E2ZDA0MjI0OWFmMGNjN2Q3YTllOTYyNTc0Mw==',
expectedEsURL: 'https://cec6f261a74bf24ce33bb8811b84294f.us-east-1.aws.found.io:443',
expectedKibanaURL: 'https://c6c2ca6d042249af0cc7d7a9e9625743.us-east-1.aws.found.io:443',
},
{
cloudID:
'dXMtZWFzdC0xLmF3cy5mb3VuZC5pbyRjZWM2ZjI2MWE3NGJmMjRjZTMzYmI4ODExYjg0Mjk0ZiRjNmMyY2E2ZDA0MjI0OWFmMGNjN2Q3YTllOTYyNTc0Mw==',
expectedEsURL: 'https://cec6f261a74bf24ce33bb8811b84294f.us-east-1.aws.found.io:443',
expectedKibanaURL: 'https://c6c2ca6d042249af0cc7d7a9e9625743.us-east-1.aws.found.io:443',
},
{
cloudID:
':dXMtZWFzdC0xLmF3cy5mb3VuZC5pbyRjZWM2ZjI2MWE3NGJmMjRjZTMzYmI4ODExYjg0Mjk0ZiRjNmMyY2E2ZDA0MjI0OWFmMGNjN2Q3YTllOTYyNTc0Mw==',
expectedEsURL: 'https://cec6f261a74bf24ce33bb8811b84294f.us-east-1.aws.found.io:443',
expectedKibanaURL: 'https://c6c2ca6d042249af0cc7d7a9e9625743.us-east-1.aws.found.io:443',
},
{
cloudID:
'gcp-cluster:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvJDhhMDI4M2FmMDQxZjE5NWY3NzI5YmMwNGM2NmEwZmNlJDBjZDVjZDU2OGVlYmU1M2M4OWViN2NhZTViYWM4YjM3',
expectedEsURL: 'https://8a0283af041f195f7729bc04c66a0fce.us-central1.gcp.cloud.es.io:443',
expectedKibanaURL:
'https://0cd5cd568eebe53c89eb7cae5bac8b37.us-central1.gcp.cloud.es.io:443',
},
{
cloudID:
'custom-port:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvOjkyNDMkYWMzMWViYjkwMjQxNzczMTU3MDQzYzM0ZmQyNmZkNDYkYTRjMDYyMzBlNDhjOGZjZTdiZTg4YTA3NGEzYmIzZTA=',
expectedEsURL: 'https://ac31ebb90241773157043c34fd26fd46.us-central1.gcp.cloud.es.io:9243',
expectedKibanaURL:
'https://a4c06230e48c8fce7be88a074a3bb3e0.us-central1.gcp.cloud.es.io:9243',
},
{
cloudID:
'different-es-kb-port:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvJGFjMzFlYmI5MDI0MTc3MzE1NzA0M2MzNGZkMjZmZDQ2OjkyNDMkYTRjMDYyMzBlNDhjOGZjZTdiZTg4YTA3NGEzYmIzZTA6OTI0NA==',
expectedEsURL: 'https://ac31ebb90241773157043c34fd26fd46.us-central1.gcp.cloud.es.io:9243',
expectedKibanaURL:
'https://a4c06230e48c8fce7be88a074a3bb3e0.us-central1.gcp.cloud.es.io:9244',
},
{
cloudID:
'only-kb-set:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvJGFjMzFlYmI5MDI0MTc3MzE1NzA0M2MzNGZkMjZmZDQ2JGE0YzA2MjMwZTQ4YzhmY2U3YmU4OGEwNzRhM2JiM2UwOjkyNDQ=',
expectedEsURL: 'https://ac31ebb90241773157043c34fd26fd46.us-central1.gcp.cloud.es.io:443',
expectedKibanaURL:
'https://a4c06230e48c8fce7be88a074a3bb3e0.us-central1.gcp.cloud.es.io:9244',
},
{
cloudID:
'host-and-kb-set:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvOjkyNDMkYWMzMWViYjkwMjQxNzczMTU3MDQzYzM0ZmQyNmZkNDYkYTRjMDYyMzBlNDhjOGZjZTdiZTg4YTA3NGEzYmIzZTA6OTI0NA==',
expectedEsURL: 'https://ac31ebb90241773157043c34fd26fd46.us-central1.gcp.cloud.es.io:9243',
expectedKibanaURL:
'https://a4c06230e48c8fce7be88a074a3bb3e0.us-central1.gcp.cloud.es.io:9244',
},
{
cloudID:
'extra-items:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvJGFjMzFlYmI5MDI0MTc3MzE1NzA0M2MzNGZkMjZmZDQ2JGE0YzA2MjMwZTQ4YzhmY2U3YmU4OGEwNzRhM2JiM2UwJGFub3RoZXJpZCRhbmRhbm90aGVy',
expectedEsURL: 'https://ac31ebb90241773157043c34fd26fd46.us-central1.gcp.cloud.es.io:443',
expectedKibanaURL:
'https://a4c06230e48c8fce7be88a074a3bb3e0.us-central1.gcp.cloud.es.io:443',
},
];
for (const test of tests) {
const decoded = decodeCloudId(test.cloudID);
expect(decoded).toBeTruthy();
expect(decoded?.elasticsearchUrl === test.expectedEsURL).toBe(true);
expect(decoded?.kibanaUrl === test.expectedKibanaURL).toBe(true);
}
});
it('returns undefined for invalid formats', () => {
const tests = [
{
cloudID:
'staging:garbagedXMtZWFzdC0xLmF3cy5mb3VuZC5pbyRjZWM2ZjI2MWE3NGJmMjRjZTMzYmI4ODExYjg0Mjk0ZiRjNmMyY2E2ZDA0MjI0OWFmMGNjN2Q3YTllOTYyNTc0Mw==',
errorMsg: 'base64 decoding failed',
},
{
cloudID: 'dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvJDhhMDI4M2FmMDQxZjE5NWY3NzI5YmMwNGM2NmEwZg==',
errorMsg: 'Expected at least 3 parts',
},
];
for (const test of tests) {
const decoded = decodeCloudId(test.cloudID);
expect(decoded).toBe(undefined);
// decodeCloudId currently only logs; not throws errors
}
});
});

View file

@ -0,0 +1,66 @@
/*
* 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.
*/
// copied this solution from fleet due to time constraints
// x-pack/fleet/common/services/decode_cloud_id.ts
// decodeCloudId decodes the c.id into c.esURL and c.kibURL
export function decodeCloudId(cid: string):
| {
defaultPort: string;
elasticsearchUrl: string;
host: string;
kibanaUrl: string;
}
| undefined {
// 1. Ignore anything before `:`.
const id = cid.split(':').pop();
if (!id) {
// throw new Error(`Unable to decode ${id}`);
// eslint-disable-next-line no-console
console.debug(`Unable to decode ${id}`);
return;
}
// 2. base64 decode
let decoded: string | undefined;
try {
decoded = Buffer.from(id, 'base64').toString('utf8');
} catch {
// throw new Error(`base64 decoding failed on ${id}`);
// eslint-disable-next-line no-console
console.debug(`base64 decoding failed on ${id}`);
return;
}
// 3. separate based on `$`
const words = decoded.split('$');
if (words.length < 3) {
// throw new Error(`Expected at least 3 parts in ${decoded}`);
// eslint-disable-next-line no-console
console.debug(`Expected at least 3 parts in ${decoded}`);
return;
}
// 4. extract port from the ES and Kibana host
const [host, defaultPort] = extractPortFromName(words[0]);
const [esId, esPort] = extractPortFromName(words[1], defaultPort);
const [kbId, kbPort] = extractPortFromName(words[2], defaultPort);
// 5. form the URLs
const esUrl = `https://${esId}.${host}:${esPort}`;
const kbUrl = `https://${kbId}.${host}:${kbPort}`;
return {
defaultPort,
elasticsearchUrl: esUrl,
host,
kibanaUrl: kbUrl,
};
}
// extractPortFromName takes a string in the form `id:port` and returns the
// Id and the port. If there's no `:`, the default port is returned
function extractPortFromName(word: string, defaultPort = '443') {
const [host, port = defaultPort] = word.split(':');
return [host, port];
}