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

Add ssl encryption to Elasticsearch #3978

Draft
wants to merge 32 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
cddcc82
add encrypt test to package.json
sotojn Feb 27, 2025
f5aed04
update opensearch2 chart from 2.17.1 to 2.31.0 in e2e helmfile
sotojn Feb 27, 2025
b0cd06d
add ssl settings to e2e helmfile values.yaml
sotojn Feb 27, 2025
ff376c2
add ssl settings in os2 helm template
sotojn Feb 27, 2025
b806fd5
add initial ssl settings/logic to teraslice helm template
sotojn Feb 27, 2025
f1a8840
add opensearch ssl env variables to test config files
sotojn Feb 27, 2025
d271e44
update teraslice harness init func to handle ssl
sotojn Feb 27, 2025
97f50c8
add proper handling of ssl config in es createClient func
sotojn Feb 27, 2025
ebca265
add caCertificate as optional es client config param
sotojn Feb 27, 2025
6176599
leave note to fix teardown when in ssl in e2e
sotojn Feb 27, 2025
2ec3911
add early logic for generating os2 certs in ssl tests
sotojn Feb 27, 2025
5dbd283
replace commandline method of passing in variables to helm in favor o…
sotojn Feb 27, 2025
282bb48
add caCertificate, username, and password to es client schema
sotojn Feb 27, 2025
03978f4
add create_internal_users_file func to cert gen script
sotojn Feb 27, 2025
be08fc7
fix lint issues
sotojn Feb 28, 2025
0f6e39b
rename createValuesYaml to createValuesFileFromServicesArray
sotojn Feb 28, 2025
1d18ee7
remove base64 caCert option from e2e helmfile
sotojn Feb 28, 2025
10a47ff
add ssl opensearch support for makeClient func
sotojn Feb 28, 2025
fe9a24d
add ENCYPT_OPENSEARCH into scripts tests
sotojn Feb 28, 2025
1920eef
refactor createValuesFileFromServicesArray func
sotojn Feb 28, 2025
72d7888
add getAdminDnFromCert() to get proper os2 ssl config
sotojn Feb 28, 2025
c9b763e
add e2e-k8s-v2-encrypted-tests to ci tests
sotojn Feb 28, 2025
4a7c7bb
fix lint errors
sotojn Feb 28, 2025
466301d
fix ci tests
sotojn Feb 28, 2025
f0d94e4
temp comment out working tests in ci
sotojn Mar 3, 2025
2689dc5
add temp console log for debugging
sotojn Mar 3, 2025
b004279
add more temp debugging
sotojn Mar 3, 2025
b5c7e7d
remove un-needed volumes in os2 init container
sotojn Mar 3, 2025
7ae9510
more debugging for helmfile sync
sotojn Mar 3, 2025
e2070df
load image into kind when testing with helmfile
sotojn Mar 3, 2025
ac2bb0d
more debugging for ci
sotojn Mar 3, 2025
c212bb1
fix debugging
sotojn Mar 3, 2025
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
785 changes: 435 additions & 350 deletions .github/workflows/test.yml

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion e2e/helm/helmfile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ releases:
- name: opensearch2
namespace: services-dev1
chart: opensearch/opensearch
version: 2.17.1
version: 2.31.0
installed: {{ .Values | get "opensearch2.enabled" true }}
values:
- ./templates/os2.yaml.gotmpl
Expand Down
63 changes: 63 additions & 0 deletions e2e/helm/templates/os2.yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,28 @@ config:
{{- if eq (.Values | get "opensearch2.instances" 1) 1 }}
discovery.type: single-node
{{- end }}
{{- if eq (.Values | get "opensearch2.ssl.enabled" false) true}}
plugins.security.ssl.transport.pemcert_filepath: certs/opensearch-cert.pem
plugins.security.ssl.transport.pemkey_filepath: certs/opensearch-key.pem
plugins.security.ssl.transport.pemtrustedcas_filepath: certs/CAs/rootCA.pem # Root CA

plugins.security.ssl.http.enabled: true
plugins.security.ssl.http.pemcert_filepath: certs/opensearch-cert.pem
plugins.security.ssl.http.pemkey_filepath: certs/opensearch-key.pem
plugins.security.ssl.http.pemtrustedcas_filepath: certs/CAs/rootCA.pem # Root CA

plugins.security.authcz.admin_dn:
- "{{ .Values | get "opensearch2.ssl.admin_dn" "" }}"
{{- end }}

extraEnvs:
{{- if eq (.Values | get "opensearch2.ssl.enabled" false) true}}
- name: OPENSEARCH_INITIAL_ADMIN_PASSWORD
value: "passwordsufhbivbU123%$"
{{- else }}
- name: DISABLE_SECURITY_PLUGIN
value: "true"
{{- end }}

clusterName: opensearch2-cluster

Expand All @@ -37,3 +55,48 @@ resources:

persistence:
size: {{ .Values | get "opensearch2.persistentVolumeSize" "8Gi" }}

{{- if eq (.Values | get "opensearch2.ssl.enabled" false) true }}
extraVolumes:
- name: certs
hostPath:
path: /certs
type: Directory
extraVolumeMounts:
- name: certs
mountPath: /usr/share/opensearch/config/certs
readOnly: false

extraContainers:
- name: security-admin-init
image: opensearchproject/opensearch:{{ .Values | get "opensearch2.version" "2.15.0" }}
command: ["/bin/sh", "-c"]
args:
- |
echo "Waiting for OpenSearch to be ready..."
until curl -k --silent --output /dev/null https://opensearch2.services-dev1:9200; do
echo "Still waiting..."
sleep 5
done
echo "Building securityConfig Directory..."
mkdir -p /usr/share/opensearch/plugins/opensearch-security/securityconfig
cp -R /usr/share/opensearch/config/opensearch-security/* \
/usr/share/opensearch/plugins/opensearch-security/securityconfig/
cp /usr/share/opensearch/config/certs/internal_users.yml \
/usr/share/opensearch/plugins/opensearch-security/securityconfig/internal_users.yml
echo "Successfully build security config!"
echo "Running securityadmin.sh..."
/usr/share/opensearch/plugins/opensearch-security/tools/securityadmin.sh \
-cd /usr/share/opensearch/plugins/opensearch-security/securityconfig/ \
-icl \
-nhnv \
-cacert /usr/share/opensearch/config/certs/CAs/rootCA.pem \
-cert /usr/share/opensearch/config/certs/opensearch-cert.pem \
-key /usr/share/opensearch/config/certs/opensearch-key.pem \
-h opensearch2.services-dev1
echo "Security initialized successfully!"
sleep 1000000
volumeMounts:
- name: certs
mountPath: /usr/share/opensearch/config/certs
{{- end }}
31 changes: 31 additions & 0 deletions e2e/helm/templates/teraslice.yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,29 @@ terafoundation:
default:
node:
{{- if eq (.Values | get "teraslice.stateCluster" "none") "opensearch2" }}
{{- if eq (.Values | get "opensearch2.ssl.enabled" false) true}}
- "https://opensearch2.services-dev1:9200"
{{- else}}
- "http://opensearch2.services-dev1:9200"
{{- end }}
{{- else if eq (.Values | get "teraslice.stateCluster" "none") "opensearch1" }}
- "http://opensearch1.services-dev1:9200"
{{- else if eq (.Values | get "teraslice.stateCluster" "none") "elasticsearch6" }}
- "http://elasticsearch6-master.services-dev1:9200"
{{- else if eq (.Values | get "teraslice.stateCluster" "none") "elasticsearch7" }}
- "http://elasticsearch7-master.services-dev1:9200"
{{- end }}
{{- if eq (.Values | get "opensearch2.ssl.enabled" false) true}}
username: admin
password: "passwordsufhbivbU123%$"

caCertificate: "{{- if .Values.opensearch2.ssl.caCert -}}
{{ .Values.opensearch2.ssl.caCert }}
{{- else -}}
{{ fail "opensearch2.ssl.caCert MUST be provided so teraslice can get the rootCA" }}
{{- end }}"

{{- end }}
{{- if eq (.Values | get "opensearch1.enabled" false) true }}
os1:
node:
Expand All @@ -35,7 +50,23 @@ terafoundation:
{{- if eq (.Values | get "opensearch2.enabled" false) true }}
os2:
node:
{{- if eq (.Values | get "opensearch2.ssl.enabled" false) true}}
- "https://opensearch2.services-dev1:9200"
{{- else }}
- "http://opensearch2.services-dev1:9200"
{{- end }}

{{- if eq (.Values | get "opensearch2.ssl.enabled" false) true}}
username: admin
password: "passwordsufhbivbU123%$"

caCertificate: "{{- if .Values.opensearch2.ssl.caCert -}}
{{ .Values.opensearch2.ssl.caCert }}
{{- else -}}
{{ fail "opensearch2.ssl.caCert MUST be provided so teraslice can get the rootCA" }}
{{- end }}"

{{- end }}
{{- end }}
{{- if eq (.Values | get "elasticsearch6.enabled" false) true }}
es6:
Expand Down
22 changes: 20 additions & 2 deletions e2e/helm/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,24 @@ opensearch1:
opensearch2:
# If false, opensearch2 will be excluded on helmfile sync
enabled: true

ssl:
# If true, "caCert" and "admin_dn" need to be set
enabled: false

# CA certificate in a single-line string format with "\\n" as line breaks
# Use the following command to convert a rootCA PEM file to the correct format:
# awk '{printf "%s\\\\n", $0}' <path-to-pem-file> | pbcopy
# This is so teraslice can get the rootCA for it's client validation
caCert: null

# The distinguished name (DN) of the OpenSearch admin user
# Required when SSL is enabled
# Retrieve this using the following command:
# openssl x509 -in <path-to-cert> -noout -subject | awk '{print substr($0,9)}'
# Example output: 'O=mkcert development certificate, OU=local'
# FIXME: This needs to be auto generated in e2e
admin_dn: ""
version: 2.15.0
esJavaOpts: -Xmx512M -Xms512M
memoryLimit: 100Mi
Expand Down Expand Up @@ -59,7 +77,7 @@ minio:

kafka:
# If false, kafka will be excluded on helmfile sync
enabled: true
enabled: false
version: 7.7.1
brokers: 1
offsets:
Expand All @@ -69,7 +87,7 @@ kafka:

zookeeper:
# If false, zookeeper will be excluded on helmfile sync
enabled: true
enabled: false
version: 7.7.1
instances: 1

Expand Down
1 change: 1 addition & 0 deletions e2e/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"test:k8sNoBuild": "SKIP_DOCKER_BUILD_IN_E2E='true' TEST_ELASTICSEARCH='true' ELASTICSEARCH_VERSION='7.9.3' TEST_KAFKA='true' TEST_PLATFORM='kubernetes' ts-scripts test --suite e2e --",
"test:k8sV2": "TEST_ELASTICSEARCH='true' ELASTICSEARCH_VERSION='7.9.3' TEST_KAFKA='true' TEST_PLATFORM='kubernetesV2' ts-scripts test --suite e2e --",
"test:k8sV2Helmfile": "TEST_OPENSEARCH='true' OPENSEARCH_VERSION='2.15.0' TEST_KAFKA='true' TEST_PLATFORM='kubernetesV2' USE_HELMFILE='true' ts-scripts test --suite e2e --",
"test:k8sV2HelmfileEncrypted": "TEST_OPENSEARCH='true' OPENSEARCH_VERSION='2.15.0' ENCRYPT_OPENSEARCH='true' OPENSEARCH_PASSWORD='passwordsufhbivbU123%$' TEST_KAFKA='true' TEST_PLATFORM='kubernetesV2' USE_HELMFILE='true' ts-scripts test --suite e2e --debug=true --",
"test:opensearch1": "TEST_OPENSEARCH='true' TEST_KAFKA='true' ts-scripts test --suite e2e --",
"test:opensearch2": "TEST_OPENSEARCH='true' OPENSEARCH_VERSION='2.15.0' TEST_KAFKA='true' ts-scripts test --suite e2e --",
"test:s3AssetStorage": "TEST_OPENSEARCH='true' TEST_KAFKA='true' TEST_MINIO='true' ASSET_STORAGE_CONNECTION_TYPE='s3' ASSET_STORAGE_CONNECTION='default' ts-scripts test --suite e2e --",
Expand Down
14 changes: 12 additions & 2 deletions e2e/test/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ const {
ELASTICSEARCH_HOST,
ELASTICSEARCH_VERSION,
OPENSEARCH_HOST,
OPENSEARCH_SSL_HOST,
OPENSEARCH_VERSION,
OPENSEARCH_USER,
OPENSEARCH_PASSWORD
} = ElasticsearchTestHelpers;

const filePath = fileURLToPath(new URL(import.meta.url));
Expand Down Expand Up @@ -55,12 +58,16 @@ const {
ASSET_STORAGE_CONNECTION_TYPE = 'elasticsearch-next',
ASSET_STORAGE_CONNECTION = 'default',
ENCRYPT_MINIO = false,
ENCRYPT_OPENSEARCH = false,
MINIO_HOST = 'http://127.0.0.1:49000',
MINIO_ACCESS_KEY = 'minioadmin',
MINIO_SECRET_KEY = 'minioadmin'
} = process.env;

const TEST_HOST = TEST_OPENSEARCH ? OPENSEARCH_HOST : ELASTICSEARCH_HOST;
const TEST_HOST = TEST_OPENSEARCH
? ENCRYPT_OPENSEARCH ? OPENSEARCH_SSL_HOST : OPENSEARCH_HOST
: ELASTICSEARCH_HOST;

const USE_HELMFILE = toBoolean(process.env.USE_HELMFILE) || false;

function newId(prefix?: string, lowerCase = false, length = 15) {
Expand Down Expand Up @@ -113,7 +120,10 @@ export {
MINIO_ACCESS_KEY,
MINIO_SECRET_KEY,
ENCRYPT_MINIO,
ENCRYPT_OPENSEARCH,
ROOT_CERT_PATH,
TEST_OPENSEARCH,
USE_HELMFILE
USE_HELMFILE,
OPENSEARCH_USER,
OPENSEARCH_PASSWORD
};
5 changes: 3 additions & 2 deletions e2e/test/teardown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { helmfileDelete, K8s } from '@terascope/scripts';
import fse from 'fs-extra';
import {
KEEP_OPEN, CONFIG_PATH, ASSETS_PATH, TEST_INDEX_PREFIX,
TEST_PLATFORM, TERASLICE_PORT, KIND_CLUSTER, USE_HELMFILE
TEST_PLATFORM, TERASLICE_PORT, KIND_CLUSTER, USE_HELMFILE,
ROOT_CERT_PATH
} from './config.js';
import { tearDown } from './docker-helpers.js';
import signale from './signale.js';
Expand All @@ -12,7 +13,7 @@ const { cleanupIndex, makeClient } = ElasticsearchTestHelpers;

async function getClient(client?: Client) {
if (client) return client;
return makeClient();
return makeClient(ROOT_CERT_PATH);
}

export async function teardown(testClient?: Client) {
Expand Down
15 changes: 12 additions & 3 deletions e2e/test/teraslice-harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import {
} from '@terascope/utils';
import { showState } from '@terascope/scripts';
import { JobConfig, Teraslice } from '@terascope/types';
import { createClient, ElasticsearchTestHelpers, Client } from 'elasticsearch-store';
import { createClient, ElasticsearchTestHelpers, Client, ClientConfig } from 'elasticsearch-store';
import { TerasliceClient } from 'teraslice-client-js';
import fse from 'fs-extra';
import {
TEST_HOST, HOST_IP, SPEC_INDEX_PREFIX,
DEFAULT_NODES, newId, DEFAULT_WORKERS, GENERATE_ONLY,
EXAMPLE_INDEX_SIZES, EXAMPLE_INDEX_PREFIX, TEST_PLATFORM, TERASLICE_PORT,
LOG_PATH
LOG_PATH, ENCRYPT_OPENSEARCH, OPENSEARCH_USER, OPENSEARCH_PASSWORD, ROOT_CERT_PATH
} from './config.js';
import { scaleWorkers, getElapsed } from './docker-helpers.js';
import signale from './signale.js';
Expand Down Expand Up @@ -65,7 +65,16 @@ export class TerasliceHarness {
teraslice!: TerasliceClient;

async init() {
const { client } = await createClient({ node: TEST_HOST });
const esConfig: ClientConfig = { node: TEST_HOST };
if (ENCRYPT_OPENSEARCH) {
esConfig.username = OPENSEARCH_USER;
esConfig.password = OPENSEARCH_PASSWORD;
esConfig.caCertificate = fse.readFileSync(ROOT_CERT_PATH, 'utf8');
}
// I should be able to not do this if I add a probe to os2
const { client } = await pRetry(async () => {
return await createClient(esConfig);
});
this.client = client;
this.teraslice = new TerasliceClient({
host: `http://${HOST_IP}:${TERASLICE_PORT}`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,17 @@ export async function createClient(
config: ClientConfig,
logger = debugLogger('elasticsearch-client')
): Promise<{ log: () => Logger; client: Client }> {
if (config.caCertificate) {
config.ssl = {
ca: config.caCertificate
};
if (config.username && config.password) {
config.auth = {
username: config.username,
password: config.password
};
}
}
const distributionMetadata = await getDBMetadata(config, logger);

const baseClient = await getBaseClient(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ interface ClientOptions {
export interface ClientConfig extends ClientOptions {
password?: string;
username?: string;
caCertificate?: string;
}

export interface ClientOnlyParams {
Expand Down
6 changes: 5 additions & 1 deletion packages/elasticsearch-store/src/test-helpers/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const {
OPENSEARCH_PASSWORD = 'admin',
OPENSEARCH_VERSION = '1.3.0',
OPENSEARCH_HOST = `http://${OPENSEARCH_USER}:${OPENSEARCH_PASSWORD}@${OPENSEARCH_HOSTNAME}`,
OPENSEARCH_SSL_HOST = `https://${OPENSEARCH_HOSTNAME}:${OPENSEARCH_PORT}`,
RESTRAINED_OPENSEARCH_PORT = process.env.RESTRAINED_OPENSEARCH_PORT || '49206',
RESTRAINED_OPENSEARCH_HOST = `http://${OPENSEARCH_USER}:${OPENSEARCH_PASSWORD}@localhost:${RESTRAINED_OPENSEARCH_PORT}`,
} = process.env;
Expand All @@ -17,6 +18,9 @@ export {
ELASTICSEARCH_HOST,
ELASTICSEARCH_VERSION,
OPENSEARCH_HOST,
OPENSEARCH_SSL_HOST,
OPENSEARCH_VERSION,
RESTRAINED_OPENSEARCH_HOST
RESTRAINED_OPENSEARCH_HOST,
OPENSEARCH_USER,
OPENSEARCH_PASSWORD
};
Loading
Loading