Skip to content

Commit

Permalink
fix: opensearch api as separate construct
Browse files Browse the repository at this point in the history
  • Loading branch information
Alex Tarasov authored and lmouhib committed Aug 16, 2024
1 parent 1b21b8c commit 2bd8d2e
Show file tree
Hide file tree
Showing 13 changed files with 943 additions and 115 deletions.
390 changes: 390 additions & 0 deletions framework/API.md

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions framework/src/consumption/examples/opensearch-api.lit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,22 @@ class ExampleOpenSearchApiStack extends cdk.Stack {
constructor(scope: Construct, id: string , props:cdk.StackProps) {

super(scope, id, props);
this.node.setContext('@data-solutions-framework-on-aws/removeDataOnDestroy', true);
/// !show
const osCluster = new dsf.consumption.OpenSearchCluster(this, 'MyOpenSearchCluster',{
domainName:"mycluster",
samlEntityId:'<IdpIdentityId>',
samlMetadataContent:'<IdpOpenSearchApplicationMetadataXml>',
samlMetadataContent:'<IdpMetadataXml>',
samlMasterBackendRole:'<IAMIdentityCenterAdminGroupId>',
deployInVpc:false,
dataNodeInstanceType:'t3.small.search',
dataNodeInstanceCount:1,
masterNodeInstanceCount:0
masterNodeInstanceCount:0,
removalPolicy:cdk.RemovalPolicy.DESTROY
});
/// !hide

//Add another admin
const adminCr = osCluster.addRoleMapping('AnotherAdmin', 'all_access','sometestId');
//Overwrite construct-wide removal policy
adminCr.applyRemovalPolicy(cdk.RemovalPolicy.DESTROY);
osCluster.addRoleMapping('AnotherAdmin', 'all_access','sometestId');

const indexTemplateCr = osCluster.callOpenSearchApi('CreateIndexTemplate','_index_template/movies',
{
Expand Down Expand Up @@ -66,6 +65,7 @@ class ExampleOpenSearchApiStack extends cdk.Stack {
add2Cr.node.addDependency(indexTemplateCr);
const add3Cr = osCluster.callOpenSearchApi('AddData4', 'movies-01/_doc',{"title": "The Little Mermaid", "year": 2015}, 'POST');
add3Cr.node.addDependency(indexTemplateCr);
/// !hide

}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ class ExampleDefaultOpenSearchStack extends cdk.Stack {
deployInVpc:true,
vpc:vpcVpn.vpc
});
/// !hide

osCluster.addRoleMapping('DashboardOsUser', 'dashboards_user','<IAMIdentityCenterDashboardUsersGroupId>');
osCluster.addRoleMapping('ReadAllOsRole','readall','<IAMIdentityCenterDashboardUsersGroupId>');
/// !hide

}


Expand Down
4 changes: 3 additions & 1 deletion framework/src/consumption/examples/opensearch-saml.lit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ class ExampleDefaultOpenSearchStack extends cdk.Stack {
deployInVpc:true,
removalPolicy:cdk.RemovalPolicy.DESTROY
});
/// !hide


osCluster.addRoleMapping('DashboardOsUser', 'dashboards_user','<IAMIdentityCenterDashboardUsersGroupId>');
osCluster.addRoleMapping('ReadAllOsRole','readall','<IAMIdentityCenterDashboardUsersGroupId>');
/// !hide
}


Expand Down
2 changes: 2 additions & 0 deletions framework/src/consumption/lib/opensearch/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
export * from './opensearch';
export * from './opensearch-props';
export * from './opensearch-api-props';
export * from './opensearch-api';
67 changes: 67 additions & 0 deletions framework/src/consumption/lib/opensearch/opensearch-api-props.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import { RemovalPolicy } from 'aws-cdk-lib';
import { IVpc, SubnetSelection } from 'aws-cdk-lib/aws-ec2';
import { IRole } from 'aws-cdk-lib/aws-iam';

/**
* Configuration for the OpenSearch API.
*/
export interface OpenSearchApiProps {

/**
* The removal policy when deleting the CDK resource.
* If DESTROY is selected, context value `@data-solutions-framework-on-aws/removeDataOnDestroy` needs to be set to true.
* Otherwise the removalPolicy is reverted to RETAIN.
* @default - The resources are not deleted (`RemovalPolicy.RETAIN`).
*/
readonly removalPolicy?: RemovalPolicy;

/**
* The IAM role to pass to IAM authentication lambda handler
* This role must be able to be assumed with `lambda.amazonaws.com` service principal
* @default - new IAMRole is created.
*/
readonly iamHandlerRole?: IRole;

/**
* Defines the virtual networking environment for this construct.
* Typically should use same VPC as OpenSearch cluster or serverless collection.
* Must have at least 2 subnets in two different AZs.
* @default - no VPC is used.
*/
readonly vpc?: IVpc;

/**
* The subnets where the Custom Resource Lambda Function would be created in.
* Required if vpc parameter is provided.
* @default - One private subnet with egress is used per AZ.
*/
readonly subnets?: SubnetSelection;

/**
* The OpenSearch Cluster or Serverless collection endpoint to connect to.
* if you provisoned your cluster using CDK
* use domainEndpoint property of OpenSearch provisioned cluster or
* attrCollectionEndpoint property of OpenSearch Serverless collection.
*/
readonly openSearchEndpoint : string;

/**
* Type of OpenSearch cluster.
*/
readonly openSearchClusterType : OpenSearchClusterType;

/**
* AWS Region openSearchEndpoint is provisioned in.
* @default - same region as stack.
*/
readonly openSearchEndpointRegion? : string;
}


export enum OpenSearchClusterType {
PROVISIONED = 'provisioned',
SERVERLESS = 'serverless'
}
126 changes: 126 additions & 0 deletions framework/src/consumption/lib/opensearch/opensearch-api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import * as path from 'path';
import { CustomResource, Stack } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { OpenSearchApiProps } from './opensearch-api-props';
import { Context, TrackedConstruct, TrackedConstructProps } from '../../../utils';
import { DsfProvider } from '../../../utils/lib/dsf-provider';

/**
* A construct to create an OpenSearch API client
*/
export class OpenSearchApi extends TrackedConstruct {

/**
* Custom resource provider for the OpenSearch API client
*/
private apiProvider: DsfProvider;

/**
* The removal policy when deleting the CDK resources.
* If DESTROY is selected, the context value '@data-solutions-framework-on-aws/removeDataOnDestroy'
* in the 'cdk.json' or 'cdk.context.json' must be set to true
* @default - The resources are not deleted (`RemovalPolicy.RETAIN`).
*/
private removalPolicy: any;

/**
* Internal property to keep persistent IAM roles to prevent them from being overwritten
* in subsequent API calls
*/
private persistentRoles: {[key:string]:string[]} = {};

/**
* Constructs a new instance of the OpenSearch API construct.
* @param scope Construct
* @param id unique ID for the construct
* @param props @see OpenSearchApiProps
*/
constructor(scope: Construct, id: string, props: OpenSearchApiProps) {

const trackedConstructProps: TrackedConstructProps = {
trackingTag: OpenSearchApi.name,
};

super(scope, id, trackedConstructProps);


this.removalPolicy = Context.revertRemovalPolicy(this, props.removalPolicy);

this.apiProvider = new DsfProvider(this, 'Provider', {
providerName: 'opensearchApiProvider',
onEventHandlerDefinition: {
iamRole: props.iamHandlerRole,
handler: 'handler',
depsLockFilePath: path.join(__dirname, './resources/lambda/opensearch-api/package-lock.json'),
entryFile: path.join(__dirname, './resources/lambda/opensearch-api/opensearch-api.mjs'),
environment: {
REGION: props.openSearchEndpointRegion ?? Stack.of(this).region,
ENDPOINT: props.openSearchEndpoint,
},
bundling: {
nodeModules: [
'@aws-crypto/sha256-js',
'@aws-crypto/client-node',
'@aws-sdk/client-secrets-manager',
'@aws-sdk/node-http-handler',
'@aws-sdk/protocol-http',
'@aws-sdk/signature-v4',
],
},
},
vpc: props.vpc,
subnets: props.subnets,
removalPolicy: this.removalPolicy,
});
}


/**
* Calls OpenSearch API using custom resource.
* @param id The CDK resource ID
* @param apiPath OpenSearch API path
* @param body OpenSearch API request body
* @param method Opensearch API method, @default PUT
* @returns CustomResource object.
*/

public callOpenSearchApi(id: string, apiPath: string, body: any, method?: string) : CustomResource {
const cr = new CustomResource(this, id, {
serviceToken: this.apiProvider.serviceToken,
resourceType: 'Custom::OpenSearchAPI',
properties: {
path: apiPath,
body,
method: method ?? 'PUT',
},
removalPolicy: this.removalPolicy,
});
cr.node.addDependency(this.apiProvider);

return cr;
}

/**
* @public
* Add a new role mapping to the cluster.
* This method is used to add a role mapping to the Amazon OpenSearch cluster
* @param id The CDK resource ID
* @param name OpenSearch role name @see https://opensearch.org/docs/2.9/security/access-control/users-roles/#predefined-roles
* @param role list of IAM roles. For IAM Identity center provide SAML group Id as a role
* @param persist Set to true if you want to prevent the roles to be ovewritten by subsequent PUT API calls. Default false.
* @returns CustomResource object.
*/
public addRoleMapping(id: string, name: string, role: string, persist:boolean=false) : CustomResource {
const persistentRoles = this.persistentRoles[name] || [];
const rolesToPersist = persistentRoles.concat([role]);
if (persist) {
this.persistentRoles[name] = rolesToPersist;
}
return this.callOpenSearchApi(id, '_plugins/_security/api/rolesmapping/' + name, {
backend_roles: rolesToPersist,
});
}
}
Loading

0 comments on commit 2bd8d2e

Please sign in to comment.