Skip to content

Commit

Permalink
Add feature to support customized config files to the cluster (#82)
Browse files Browse the repository at this point in the history
Signed-off-by: Sayali Gaikawad <[email protected]>
  • Loading branch information
gaiksaya authored Dec 4, 2023
1 parent 521aeb5 commit 68679fc
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 10 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ In order to deploy both the stacks the user needs to provide a set of required a
| enableRemoteStore | Optional | boolean | Boolean flag to enable Remote Store feature e.g., `--context enableRemoteStore=true`. See [Enable Remote Store Feature](#enable-remote-store-feature) for more details. Defaults to false |
| storageVolumeType | Optional | string | EBS volume type for all the nodes (data, ml, cluster manager). Defaults to gp2. See `lib/opensearch-config/node-config.ts` for available options. E.g., `-c storageVolumeType=gp3`. For SSD based instance (i.e. i3 family), it is used for root volume configuration. |
| customRoleArn | Optional | string | User provided IAM role arn to be used as ec2 instance profile. `-c customRoleArn=arn:aws:iam::<AWS_ACCOUNT_ID>:role/<ROLE_NAME>` |
| customConfigFiles | Optional | string | You can provide an entire config file to be overwritten or added to OpenSearch and OpenSearch Dashboards. Pass string in the form of JSON with key as local path to the config file to read from and value as file on the server to overwrite/add. Note that the values in the JSON needs to have prefix of `opensearch` or `opensearch-dashboards`. Example: `-c customConfigFiles='{"opensearch-config/config.yml": "opensearch/config/opensearch-security/config.yml", "opensearch-config/role_mapping.yml":"opensearch/config/opensearch-security/roles_mapping.yml", "/roles.yml": "opensearch/config/opensearch-security/roles.yml"}'` |

* Before starting this step, ensure that your AWS CLI is correctly configured with access credentials.
* Also ensure that you're running these commands in the current directory
Expand Down Expand Up @@ -98,7 +99,7 @@ cdk synth "*" --context securityDisabled=false \
--context distVersion=2.3.0 --context serverAccessType=ipv4 --context restrictServerAccessTo=10.10.10.10/32
```

#### Sample command to set up multi-node cluster with security disabled on x64 AL2 machine
#### Sample command to set up multi-node cluster with security enabled on x64 AL2 machine

Please note that as of now we only support instances backed by Amazon Linux-2 amis.

Expand Down
31 changes: 25 additions & 6 deletions lib/infra/infra-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,17 @@ export interface infraProps extends StackProps {
readonly mlNodeCount: number,
readonly dataNodeStorage: number,
readonly mlNodeStorage: number,
readonly jvmSysPropsString?: string,
readonly additionalConfig?: string,
readonly additionalOsdConfig?: string,
readonly dataEc2InstanceType: InstanceType,
readonly mlEc2InstanceType: InstanceType,
readonly use50PercentHeap: boolean,
readonly isInternal: boolean,
readonly enableRemoteStore: boolean,
readonly storageVolumeType: EbsDeviceVolumeType,
readonly customRoleArn: string
readonly customRoleArn: string,
readonly jvmSysPropsString?: string,
readonly additionalConfig?: string,
readonly additionalOsdConfig?: string,
readonly customConfigFiles?: string,
}

export class InfraStack extends Stack {
Expand Down Expand Up @@ -585,7 +586,25 @@ export class InfraStack extends Stack {
}));
}

// // Startinng OpenSearch based on whether the distribution type is min or bundle
if (props.customConfigFiles !== 'undefined') {
try {
// @ts-ignore
const jsonObj = JSON.parse(props.customConfigFiles);
Object.keys(jsonObj).forEach((localFileName) => {
const getConfig = load(readFileSync(localFileName, 'utf-8'));
const remoteConfigLocation = jsonObj[localFileName];
cfnInitConfig.push(InitCommand.shellCommand(`set -ex; echo "${dump(getConfig)}" > ${remoteConfigLocation}`,
{
cwd: '/home/ec2-user',
ignoreErrors: false,
}));
});
} catch (e) {
throw new Error(`Encountered following error while parsing customConfigFiles json parameter: ${e}`);
}
}

// Starting OpenSearch based on whether the distribution type is min or bundle
if (props.minDistribution) { // using (stackProps.minDistribution) condition is not working when false value is being sent
cfnInitConfig.push(InitCommand.shellCommand('set -ex;cd opensearch; sudo -u ec2-user nohup ./bin/opensearch >> install.log 2>&1 &',
{
Expand Down Expand Up @@ -635,7 +654,7 @@ export class InfraStack extends Stack {
}));
}

// Startinng OpenSearch-Dashboards
// Starting OpenSearch-Dashboards
cfnInitConfig.push(InitCommand.shellCommand('set -ex;cd opensearch-dashboards;'
+ 'sudo -u ec2-user nohup ./bin/opensearch-dashboards > dashboard_install.log 2>&1 &', {
cwd: '/home/ec2-user',
Expand Down
10 changes: 7 additions & 3 deletions lib/os-cluster-entrypoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export class OsClusterEntrypoint {
let dataEc2InstanceType: InstanceType;
let mlEc2InstanceType: InstanceType;
let volumeType: EbsDeviceVolumeType;
let customConfigFiles: string = 'undefined';

const x64InstanceTypes: string[] = Object.keys(x64Ec2InstanceType);
const arm64InstanceTypes: string[] = Object.keys(arm64Ec2InstanceType);
Expand Down Expand Up @@ -202,6 +203,8 @@ export class OsClusterEntrypoint {
}
}

customConfigFiles = `${scope.node.tryGetContext('customConfigFiles')}`;

const suffix = `${scope.node.tryGetContext('suffix')}`;
const networkStackSuffix = `${scope.node.tryGetContext('networkStackSuffix')}`;

Expand Down Expand Up @@ -265,14 +268,15 @@ export class OsClusterEntrypoint {
singleNodeCluster: isSingleNode,
dataNodeStorage,
mlNodeStorage,
jvmSysPropsString: jvmSysProps,
additionalConfig: ymlConfig,
additionalOsdConfig: osdYmlConfig,
use50PercentHeap,
isInternal,
enableRemoteStore,
storageVolumeType: volumeType,
customRoleArn,
jvmSysPropsString: jvmSysProps,
additionalConfig: ymlConfig,
additionalOsdConfig: osdYmlConfig,
customConfigFiles,
...props,
});

Expand Down
23 changes: 23 additions & 0 deletions test/data/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
_meta:
type: "allowlist"
config_version: 2

# Description:
# enabled - feature flag.
# if enabled is false, all endpoints are accessible.
# if enabled is true, all users except the SuperAdmin can only submit the allowed requests to the specified endpoints.
# SuperAdmin can access all APIs.
# SuperAdmin is defined by the SuperAdmin certificate, which is configured with the opensearch.yml setting plugins.security.authcz.admin_dn:
# Refer to the example setting in opensearch.yml to learn more about configuring SuperAdmin.
#
# requests - map of allow listed endpoints and HTTP requests

#this name must be config
config:
enabled: true
requests:
/_cluster/settings:
- GET
/_cat/nodes:
- GET
27 changes: 27 additions & 0 deletions test/data/roles.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
complex-role:
reserved: false
hidden: false
cluster_permissions:
- "read"
- "cluster:monitor/nodes/stats"
- "cluster:monitor/task/get"
index_permissions:
- index_patterns:
- "opensearch_dashboards_sample_data_*"
dls: "{\"match\": {\"FlightDelay\": true}}"
fls:
- "~FlightNum"
masked_fields:
- "Carrier"
allowed_actions:
- "read"
tenant_permissions:
- tenant_patterns:
- "analyst_*"
allowed_actions:
- "kibana_all_write"
static: false
_meta:
type: "roles"
config_version: 2
35 changes: 35 additions & 0 deletions test/os-cluster.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ test('Test Resources with security disabled multi-node default instance types',
restrictServerAccessTo: 'all',
additionalConfig: '{ "name": "John Doe", "age": 30, "email": "[email protected]" }',
additionalOsdConfig: '{ "something.enabled": "true", "something_else.enabled": "false" }',
// eslint-disable-next-line max-len
customConfigFiles: '{"test/data/config.yml": "opensearch/config/opensearch-security/config.yml", "test/data/roles.yml": "opensearch/config/opensearch-security/roles.yml"}',
},
});

Expand Down Expand Up @@ -489,3 +491,36 @@ test('Test multi-node cluster with custom IAM Role', () => {
Roles: ['customRoleName'],
});
});

test('Throw error on incorrect JSON', () => {
const app = new App({
context: {
securityDisabled: true,
minDistribution: false,
distributionUrl: 'www.example.com',
cpuArch: 'x64',
singleNodeCluster: false,
dashboardsUrl: 'www.example.com',
distVersion: '1.0.0',
serverAccessType: 'ipv4',
restrictServerAccessTo: 'all',
additionalConfig: '{ "name": "John Doe", "age": 30, "email": "[email protected]" }',
additionalOsdConfig: '{ "something.enabled": "true", "something_else.enabled": "false" }',
// eslint-disable-next-line max-len
customConfigFiles: '{"test/data/config.yml": opensearch/config/opensearch-security/config.yml"}',
},
});
// WHEN
try {
const testStack = new OsClusterEntrypoint(app, {
env: { account: 'test-account', region: 'us-east-1' },
});

// eslint-disable-next-line no-undef
fail('Expected an error to be thrown');
} catch (error) {
expect(error).toBeInstanceOf(Error);
// eslint-disable-next-line max-len
expect(error.message).toEqual('Encountered following error while parsing customConfigFiles json parameter: SyntaxError: Unexpected token o in JSON at position 25');
}
});

0 comments on commit 68679fc

Please sign in to comment.