Skip to content

Commit

Permalink
fix: remove unnecesary dependencies of opensearch custom resources
Browse files Browse the repository at this point in the history
closes #1
  • Loading branch information
tmokmss committed Mar 26, 2024
1 parent 21aae1c commit 3998ce3
Show file tree
Hide file tree
Showing 8 changed files with 49 additions and 38 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Custom Resources Library for Amazon OpenSearch Service

An AWS CDK construct library to manage OpenSearch resources via CloudFormation custom resource.
An AWS CDK construct library to manage OpenSearch resources via CloudFormation custom resource. This is especially useful if you use fine-grained access control feature on OpenSearch, where you have to create resources such as role or role mapping via OpenSearch REST API.

![architecture](./imgs/architecture.png)

Expand Down Expand Up @@ -64,7 +64,7 @@ Currently this library assumes your OpenSearch domain is configured as:
* Deployed within a VPC
* Use the [`Domain`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_opensearchservice.Domain.html) L2 construct
* The credential for the master user (username and password) is stored in Secret Manager
* [Domain access policy](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/fgac.html#fgac-recommendations) is permissive like below:
* [Domain access policy](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/fgac.html#fgac-recommendations) is permissive enough like below:

```json
{
Expand Down
32 changes: 20 additions & 12 deletions src/custom-resource.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { readFileSync } from 'fs';
import { join } from 'path';
import { Duration, CustomResource, RemovalPolicy, Stack } from 'aws-cdk-lib';
import { IVpc } from 'aws-cdk-lib/aws-ec2';
import { CfnSecurityGroupIngress, IVpc } from 'aws-cdk-lib/aws-ec2';
import { SingletonFunction, Runtime, RuntimeFamily, Code } from 'aws-cdk-lib/aws-lambda';
import { Domain } from 'aws-cdk-lib/aws-opensearchservice';
import { Secret } from 'aws-cdk-lib/aws-secretsmanager';
Expand Down Expand Up @@ -50,17 +50,13 @@ export class OpenSearchCustomResource extends Construct {
runtime: new Runtime('nodejs18.x', RuntimeFamily.NODEJS, { supportsInlineCode: true }),
code: Code.fromInline(readFileSync(join(__dirname, '../', 'lambda', 'dist', 'index.js')).toString()),
handler: 'index.handler',
// We need to create a singleton per VPC
// We need to create a singleton function per VPC
uuid: `d4706ae7-e0a2-4092-a205-7e2d4fb887d4-${vpc.node.addr}`,
lambdaPurpose: 'OpenSearchRestCustomResourceHandler',
timeout: Duration.minutes(3),
vpc,
});

if (vpc != null) {
domain.connections.allowDefaultPortFrom(handler);
}

const masterUserSecret = domain.node.tryFindChild('MasterUser');
if (!(masterUserSecret instanceof Secret)) {
throw new Error(`Cannot find a master user secret for domain ${domain.domainId}`);
Expand Down Expand Up @@ -90,12 +86,24 @@ export class OpenSearchCustomResource extends Construct {
resource.node.addDependency(domainAccessPolicy);
}

const domainSecurityGroup = domain.node.tryFindChild('SecurityGroup');
if (domainSecurityGroup == null) {
throw new Error(`Cannot find a security group for domain ${domain.domainId}`);
}
if (Stack.of(domainSecurityGroup) == Stack.of(resource)) {
resource.node.addDependency(domainSecurityGroup);
const domainSecurityGroup = domain.connections.securityGroups[0];
const handlerSecurityGroup = handler.connections.securityGroups[0];
if (vpc != null && domainSecurityGroup != null && handlerSecurityGroup != null) {
const ruleId = 'IngressFromOpenSearchCustomResource';
let rule = domainSecurityGroup.node.tryFindChild(ruleId);
if (rule == null) {
// We create an L1 resource directly here because it is difficult to
// retrieve backing ingress rule resource from L2 security group construct
rule = new CfnSecurityGroupIngress(domainSecurityGroup, ruleId, {
fromPort: 443,
toPort: 443,
ipProtocol: 'tcp',
groupId: domainSecurityGroup.securityGroupId,
sourceSecurityGroupId: handlerSecurityGroup.securityGroupId,
description: 'Ingress from OpenSearch REST custom resource handler',
});
}
resource.node.addDependency(rule);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@
}
}
},
"f9ef10371a5dae742e435ad5a965e65037d096741a9f6a0926b2bd3f0554bfbf": {
"36c9d4f1a21b0e36b67e90511884634bd8b4a715c5320bb3404484458d73d426": {
"source": {
"path": "OpenSearchRestResourcesIntegTestDefaultTestDeployAssertAA436F18.template.json",
"packaging": "file"
},
"destinations": {
"current_account-current_region": {
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
"objectKey": "f9ef10371a5dae742e435ad5a965e65037d096741a9f6a0926b2bd3f0554bfbf.json",
"objectKey": "36c9d4f1a21b0e36b67e90511884634bd8b4a715c5320bb3404484458d73d426.json",
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
}
},
"flattenResponse": "false",
"salt": "1711282564981"
"salt": "1711456515928"
},
"UpdateReplacePolicy": "Delete",
"DeletionPolicy": "Delete"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,15 @@
}
}
},
"ba0b79304e5acc3b04a3922a50b114146806988393b7866a30977ff533a2c3ee": {
"ffe3eb1a3d0ccb9edc124dc2251f0f0bdeb144153025527303b6022b281e611b": {
"source": {
"path": "OpenSearchRestResourcesStack.template.json",
"packaging": "file"
},
"destinations": {
"current_account-current_region": {
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
"objectKey": "ba0b79304e5acc3b04a3922a50b114146806988393b7866a30977ff533a2c3ee.json",
"objectKey": "ffe3eb1a3d0ccb9edc124dc2251f0f0bdeb144153025527303b6022b281e611b.json",
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -508,10 +508,10 @@
"ToPort": 443
}
},
"DomainSecurityGroupfromOpenSearchRestResourcesStackOpenSearchRestCustomResourceHandlerd4706ae7e0a24092a2057e2d4fb887d4c8e35097ce732b8fe8a8d95ca1c119b98830288f94SecurityGroup19DF8FA44434740CD7E": {
"DomainSecurityGroupIngressFromOpenSearchCustomResource3C2E72A9": {
"Type": "AWS::EC2::SecurityGroupIngress",
"Properties": {
"Description": "from OpenSearchRestResourcesStackOpenSearchRestCustomResourceHandlerd4706ae7e0a24092a2057e2d4fb887d4c8e35097ce732b8fe8a8d95ca1c119b98830288f94SecurityGroup19DF8FA4:443",
"Description": "Ingress from OpenSearch REST custom resource handler",
"FromPort": 443,
"GroupId": {
"Fn::GetAtt": [
Expand Down Expand Up @@ -1088,9 +1088,7 @@
},
"DependsOn": [
"DomainAccessPolicyEE735B04",
"DomainSecurityGroupfromOpenSearchRestResourcesStackOpenSearchRestCustomResourceHandlerd4706ae7e0a24092a2057e2d4fb887d4c8e35097ce732b8fe8a8d95ca1c119b98830288f94SecurityGroup19DF8FA44434740CD7E",
"DomainSecurityGroupfromOpenSearchRestResourcesStackTestHandlerSecurityGroup4A27F912443FFE31955",
"DomainSecurityGroup48AA5FD6"
"DomainSecurityGroupIngressFromOpenSearchCustomResource3C2E72A9"
],
"UpdateReplacePolicy": "Retain",
"DeletionPolicy": "Retain"
Expand Down Expand Up @@ -1278,9 +1276,7 @@
},
"DependsOn": [
"DomainAccessPolicyEE735B04",
"DomainSecurityGroupfromOpenSearchRestResourcesStackOpenSearchRestCustomResourceHandlerd4706ae7e0a24092a2057e2d4fb887d4c8e35097ce732b8fe8a8d95ca1c119b98830288f94SecurityGroup19DF8FA44434740CD7E",
"DomainSecurityGroupfromOpenSearchRestResourcesStackTestHandlerSecurityGroup4A27F912443FFE31955",
"DomainSecurityGroup48AA5FD6",
"DomainSecurityGroupIngressFromOpenSearchCustomResource3C2E72A9",
"Role19E695EAB"
],
"UpdateReplacePolicy": "Delete",
Expand Down Expand Up @@ -1309,9 +1305,7 @@
},
"DependsOn": [
"DomainAccessPolicyEE735B04",
"DomainSecurityGroupfromOpenSearchRestResourcesStackOpenSearchRestCustomResourceHandlerd4706ae7e0a24092a2057e2d4fb887d4c8e35097ce732b8fe8a8d95ca1c119b98830288f94SecurityGroup19DF8FA44434740CD7E",
"DomainSecurityGroupfromOpenSearchRestResourcesStackTestHandlerSecurityGroup4A27F912443FFE31955",
"DomainSecurityGroup48AA5FD6"
"DomainSecurityGroupIngressFromOpenSearchCustomResource3C2E72A9"
],
"UpdateReplacePolicy": "Delete",
"DeletionPolicy": "Delete"
Expand Down
17 changes: 13 additions & 4 deletions test/integ.resources.ts.snapshot/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"validateOnSynth": false,
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}",
"cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}",
"stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/ba0b79304e5acc3b04a3922a50b114146806988393b7866a30977ff533a2c3ee.json",
"stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/ffe3eb1a3d0ccb9edc124dc2251f0f0bdeb144153025527303b6022b281e611b.json",
"requiresBootstrapStackVersion": 6,
"bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version",
"additionalDependencies": [
Expand Down Expand Up @@ -190,10 +190,10 @@
"data": "DomainSecurityGroupfromOpenSearchRestResourcesStackTestHandlerSecurityGroup4A27F912443FFE31955"
}
],
"/OpenSearchRestResourcesStack/Domain/SecurityGroup/from OpenSearchRestResourcesStackOpenSearchRestCustomResourceHandlerd4706ae7e0a24092a2057e2d4fb887d4c8e35097ce732b8fe8a8d95ca1c119b98830288f94SecurityGroup19DF8FA4:443": [
"/OpenSearchRestResourcesStack/Domain/SecurityGroup/IngressFromOpenSearchCustomResource": [
{
"type": "aws:cdk:logicalId",
"data": "DomainSecurityGroupfromOpenSearchRestResourcesStackOpenSearchRestCustomResourceHandlerd4706ae7e0a24092a2057e2d4fb887d4c8e35097ce732b8fe8a8d95ca1c119b98830288f94SecurityGroup19DF8FA44434740CD7E"
"data": "DomainSecurityGroupIngressFromOpenSearchCustomResource3C2E72A9"
}
],
"/OpenSearchRestResourcesStack/Domain/MasterUser/Resource": [
Expand Down Expand Up @@ -357,6 +357,15 @@
"type": "aws:cdk:logicalId",
"data": "CheckBootstrapVersion"
}
],
"DomainSecurityGroupfromOpenSearchRestResourcesStackOpenSearchRestCustomResourceHandlerd4706ae7e0a24092a2057e2d4fb887d4c8e35097ce732b8fe8a8d95ca1c119b98830288f94SecurityGroup19DF8FA44434740CD7E": [
{
"type": "aws:cdk:logicalId",
"data": "DomainSecurityGroupfromOpenSearchRestResourcesStackOpenSearchRestCustomResourceHandlerd4706ae7e0a24092a2057e2d4fb887d4c8e35097ce732b8fe8a8d95ca1c119b98830288f94SecurityGroup19DF8FA44434740CD7E",
"trace": [
"!!DESTRUCTIVE_CHANGES: WILL_DESTROY"
]
}
]
},
"displayName": "OpenSearchRestResourcesStack"
Expand All @@ -378,7 +387,7 @@
"validateOnSynth": false,
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}",
"cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}",
"stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/f9ef10371a5dae742e435ad5a965e65037d096741a9f6a0926b2bd3f0554bfbf.json",
"stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/36c9d4f1a21b0e36b67e90511884634bd8b4a715c5320bb3404484458d73d426.json",
"requiresBootstrapStackVersion": 6,
"bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version",
"additionalDependencies": [
Expand Down
8 changes: 4 additions & 4 deletions test/integ.resources.ts.snapshot/tree.json
Original file line number Diff line number Diff line change
Expand Up @@ -716,13 +716,13 @@
"version": "2.133.0"
}
},
"from OpenSearchRestResourcesStackOpenSearchRestCustomResourceHandlerd4706ae7e0a24092a2057e2d4fb887d4c8e35097ce732b8fe8a8d95ca1c119b98830288f94SecurityGroup19DF8FA4:443": {
"id": "from OpenSearchRestResourcesStackOpenSearchRestCustomResourceHandlerd4706ae7e0a24092a2057e2d4fb887d4c8e35097ce732b8fe8a8d95ca1c119b98830288f94SecurityGroup19DF8FA4:443",
"path": "OpenSearchRestResourcesStack/Domain/SecurityGroup/from OpenSearchRestResourcesStackOpenSearchRestCustomResourceHandlerd4706ae7e0a24092a2057e2d4fb887d4c8e35097ce732b8fe8a8d95ca1c119b98830288f94SecurityGroup19DF8FA4:443",
"IngressFromOpenSearchCustomResource": {
"id": "IngressFromOpenSearchCustomResource",
"path": "OpenSearchRestResourcesStack/Domain/SecurityGroup/IngressFromOpenSearchCustomResource",
"attributes": {
"aws:cdk:cloudformation:type": "AWS::EC2::SecurityGroupIngress",
"aws:cdk:cloudformation:props": {
"description": "from OpenSearchRestResourcesStackOpenSearchRestCustomResourceHandlerd4706ae7e0a24092a2057e2d4fb887d4c8e35097ce732b8fe8a8d95ca1c119b98830288f94SecurityGroup19DF8FA4:443",
"description": "Ingress from OpenSearch REST custom resource handler",
"fromPort": 443,
"groupId": {
"Fn::GetAtt": [
Expand Down

0 comments on commit 3998ce3

Please sign in to comment.