Merge pull request #7101 from sam-robson/sam-robson-add-clientopts-to-elastic

feat: additional options for the elasticsearch client
This commit is contained in:
Ben Lambert
2021-09-14 13:33:42 +02:00
committed by GitHub
4 changed files with 170 additions and 75 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-search-backend-module-elasticsearch': patch
---
Added rejectUnauthorized config option
+88 -75
View File
@@ -20,90 +20,103 @@ export interface Config {
/**
* Options for ElasticSearch
*/
elasticsearch?:
| // elastic = Elastic.co ElasticSearch provider
{
provider: 'elastic';
elasticsearch?: {
/** Miscellaneous options for the client */
clientOptions?: {
ssl?: {
/**
* Elastic.co CloudID
* See: https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/client-connecting.html#authentication
* If true the server will reject any connection which is not
* authorized with the list of supplied CAs.
* @default true
*/
cloudId: string;
auth: {
username: string;
rejectUnauthorized?: boolean;
};
} & (
| {
// elastic = Elastic.co ElasticSearch provider
provider: 'elastic';
/**
* @visibility secret
* Elastic.co CloudID
* See: https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/client-connecting.html#authentication
*/
password: string;
};
}
cloudId: string;
/**
* AWS = Amazon Elasticsearch Service provider
*
* Authentication is handled using the default AWS credentials provider chain
*/
| {
provider: 'aws';
auth: {
username: string;
/**
* Node configuration.
* URL AWS ES endpoint to connect to.
* Eg. https://my-es-cluster.eu-west-1.es.amazonaws.com
*/
node: string;
}
/**
* @visibility secret
*/
password: string;
};
}
/**
* Standard ElasticSearch
*
* Includes self-hosted clusters and others that provide direct connection via an endpoint
* and authentication method (see possible authentication options below)
*/
| {
/**
* Node configuration.
* URL/URLS to ElasticSearch node to connect to.
* Either direct URL like 'https://localhost:9200' or with credentials like 'https://username:password@localhost:9200'
*/
node: string | string[];
/**
* Authentication credentials for ElasticSearch
* If both ApiKey/Bearer token and username+password is provided, tokens take precedence
*/
auth?:
| {
username: string;
/**
* @visibility secret
*/
password: string;
}
| {
/**
* Base64 Encoded API key to be used to connect to the cluster.
* See: https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-api-key.html
*
* @visibility secret
*/
apiKey: string;
};
/* TODO(kuangp): unsupported until @elastic/elasticsearch@7.14 is released
/**
* AWS = Amazon Elasticsearch Service provider
*
* Authentication is handled using the default AWS credentials provider chain
*/
| {
provider: 'aws';
/**
* Bearer authentication token to connect to the cluster.
* See: https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-service-token.html
*
* @visibility secret
*
bearer: string;
};*/
};
/**
* Node configuration.
* URL AWS ES endpoint to connect to.
* Eg. https://my-es-cluster.eu-west-1.es.amazonaws.com
*/
node: string;
}
/**
* Standard ElasticSearch
*
* Includes self-hosted clusters and others that provide direct connection via an endpoint
* and authentication method (see possible authentication options below)
*/
| {
/**
* Node configuration.
* URL/URLS to ElasticSearch node to connect to.
* Either direct URL like 'https://localhost:9200' or with credentials like 'https://username:password@localhost:9200'
*/
node: string | string[];
/**
* Authentication credentials for ElasticSearch
* If both ApiKey/Bearer token and username+password is provided, tokens take precedence
*/
auth?:
| {
username: string;
/**
* @visibility secret
*/
password: string;
}
| {
/**
* Base64 Encoded API key to be used to connect to the cluster.
* See: https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-api-key.html
*
* @visibility secret
*/
apiKey: string;
};
/* TODO(kuangp): unsupported until @elastic/elasticsearch@7.14 is released
| {
/**
* Bearer authentication token to connect to the cluster.
* See: https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-service-token.html
*
* @visibility secret
*
bearer: string;
};*/
}
);
};
};
}
@@ -24,6 +24,7 @@ import {
ElasticSearchSearchEngine,
encodePageCursor,
} from './ElasticSearchSearchEngine';
import { ConfigReader } from '@backstage/config';
class ElasticSearchSearchEngineForTranslatorTests extends ElasticSearchSearchEngine {
getTranslator() {
@@ -558,6 +559,55 @@ describe('ElasticSearchSearchEngine', () => {
]);
});
});
describe('ElasticSearchSearchEngine.fromConfig', () => {
it('accesses the clientOptions config', async () => {
const esOptions = {
clientOptions: {
ssl: {
rejectUnauthorized: true,
},
},
node: 'http://test-node',
auth: {
apiKey: 'key',
},
};
const config = new ConfigReader({});
const esConfig = new ConfigReader(esOptions);
jest.spyOn(config, 'getConfig').mockImplementation(() => esConfig);
const getOptionalConfig = jest.spyOn(esConfig, 'getOptionalConfig');
await ElasticSearchSearchEngine.fromConfig({
logger: getVoidLogger(),
config,
});
expect(getOptionalConfig.mock.calls[0][0]).toEqual('clientOptions');
});
it('does not require the clientOptions config', async () => {
const config = new ConfigReader({
search: {
elasticsearch: {
node: 'http://test-node',
auth: {
apiKey: 'test-key',
},
},
},
});
expect(
async () =>
await ElasticSearchSearchEngine.fromConfig({
logger: getVoidLogger(),
config,
}),
).not.toThrowError();
});
});
});
describe('decodePageCursor', () => {
@@ -97,6 +97,9 @@ export class ElasticSearchSearchEngine implements SearchEngine {
throw new Error('No elastic search config found');
}
const clientOptionsConfig = config.getOptionalConfig('clientOptions');
const sslConfig = clientOptionsConfig?.getOptionalConfig('ssl');
if (config.getOptionalString('provider') === 'elastic') {
logger.info('Initializing Elastic.co ElasticSearch search engine.');
const authConfig = config.getConfig('auth');
@@ -108,6 +111,14 @@ export class ElasticSearchSearchEngine implements SearchEngine {
username: authConfig.getString('username'),
password: authConfig.getString('password'),
},
...(sslConfig
? {
ssl: {
rejectUnauthorized:
sslConfig?.getOptionalBoolean('rejectUnauthorized'),
},
}
: {}),
});
}
if (config.getOptionalString('provider') === 'aws') {
@@ -117,6 +128,14 @@ export class ElasticSearchSearchEngine implements SearchEngine {
return new Client({
node: config.getString('node'),
...AWSConnection,
...(sslConfig
? {
ssl: {
rejectUnauthorized:
sslConfig?.getOptionalBoolean('rejectUnauthorized'),
},
}
: {}),
});
}
logger.info('Initializing ElasticSearch search engine.');
@@ -134,6 +153,14 @@ export class ElasticSearchSearchEngine implements SearchEngine {
return new Client({
node: config.getString('node'),
auth,
...(sslConfig
? {
ssl: {
rejectUnauthorized:
sslConfig?.getOptionalBoolean('rejectUnauthorized'),
},
}
: {}),
});
}