Skip to content

Commit 16f3174

Browse files
authored
feat: Add vpc to all lambdas, allow users to self manage install bucket assets (#15)
* feat: Add vpc to all lambdas, allow users to self manage installastion bucket assets * docs: Update readme for selfManageInstallationBucketAssets config
1 parent 9364a57 commit 16f3174

11 files changed

+113
-49
lines changed

README.md

+17
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,23 @@ The Federal Information Processing Standard ([FIPS](https://aws.amazon.com/compl
235235
"useFipsEndpoint": true,
236236
```
237237
238+
**Self-managed druid installation bucket asset (optional)**
239+
240+
By default, the solution will upload druid binary, extension, config and scripts to s3 bucket automatically, optionally you can manage these assets yourself by using below configuration
241+
242+
```
243+
"selfManageInstallationBucketAssets": true,
244+
```
245+
When this option is enabled, you will need to manually upload assets in the following folders to s3 bucket after you `npm run build`
246+
```
247+
source/lib/uploads/scripts/ -> bootstrap-s3-bucket-installation/scripts/
248+
source/lib/docker/extensions/ -> bootstrap-s3-bucket-installation/extensions/
249+
source/lib/uploads/config/ -> bootstrap-s3-bucket-installation/config/
250+
source/lib/docker/ca-certs/ -> bootstrap-s3-bucket-installation/ca-certs/
251+
source/druid-bin/ -> bootstrap-s3-bucket-installation/druid-images/
252+
source/zookeeper-bin/ -> bootstrap-s3-bucket-installation/zookeeper-images/
253+
```
254+
238255
**Identity provider configuration (optional)**
239256
The default setup of this solution activates basic authentication, enabling access to the Druid web console and API through a username and password. Additionally, you have the option to enable user access federation through a third-party identity provider (IdP) that supports OpenID Connect authentication. If you have an existing enterprise Identity Provider, you can seamlessly integrate it using the CDK configuration outlined below.
240257

source/bin/druid-infra.ts

+2
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ const contextKeys: (keyof DruidConfig)[] = [
8484
'druidInstanceIamPolicyArns',
8585
'tags',
8686
'additionalTags',
87+
'selfManageInstallationBucketAssets',
8788
];
8889

8990
const configMap: Record<string, unknown> = {};
@@ -171,6 +172,7 @@ const commonStackProps = {
171172
customAmi: druidConfig.customAmi,
172173
subnetMappings: druidConfig.subnetMappings,
173174
enableVulnerabilityScanJob: druidConfig.enableVulnerabilityScanJob ?? false,
175+
selfManageInstallationBucketAssets: druidConfig.selfManageInstallationBucketAssets ?? false,
174176
...(!druidConfig.environmentAgnostic && { env: { account, region } }),
175177
};
176178

source/lib/constructs/appRegistryAspect.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import * as appInsights from 'aws-cdk-lib/aws-applicationinsights';
1717
import * as appRegistry from '@aws-cdk/aws-servicecatalogappregistry-alpha';
1818
import * as cdk from 'aws-cdk-lib';
1919
import * as cr from 'aws-cdk-lib/custom-resources';
20+
import * as ec2 from 'aws-cdk-lib/aws-ec2';
2021
import * as iam from 'aws-cdk-lib/aws-iam';
2122
import * as lambda from 'aws-cdk-lib/aws-lambda';
2223
import * as path from 'path';
@@ -32,6 +33,7 @@ const DEFAULT_APPLICATION_RESOURCE_GROUP_STATE_QUERY_TIMEOUT = cdk.Duration.minu
3233
const DEFAULT_APPLICATION_RESOURCE_GROUP_STATE_QUERY_INTERVAL = cdk.Duration.seconds(1);
3334

3435
interface AppRegistryProps {
36+
vpc: ec2.IVpc;
3537
solutionName: string;
3638
solutionId: string;
3739
solutionVersion: string;
@@ -52,7 +54,7 @@ export class AppRegistry extends Construct implements cdk.IAspect {
5254
this.application = this.createAppForAppRegistry();
5355
this.createAttributeGroup(this.application);
5456
this.addTagsforApplication(this.application);
55-
const waiter = this.waitForResourceGroupCreated(this.application);
57+
const waiter = this.waitForResourceGroupCreated(this.application, props.vpc);
5658

5759
this.createAppForAppInsights(this.application, waiter);
5860
}
@@ -102,7 +104,8 @@ export class AppRegistry extends Construct implements cdk.IAspect {
102104
// The Application does not expose the resource group instance that we can use to set dependency which will cause the intermittent failure in AppInsight Application provision.
103105
// Add a waiter customer resource to ensure the Resource Group is CREATED.
104106
private waitForResourceGroupCreated(
105-
application: appRegistry.Application
107+
application: appRegistry.Application,
108+
vpc: ec2.IVpc,
106109
): cdk.CustomResource {
107110
const lambdaPolicyStatement = new iam.PolicyStatement({
108111
actions: ['servicecatalog:GetApplication'],
@@ -120,6 +123,8 @@ export class AppRegistry extends Construct implements cdk.IAspect {
120123
});
121124

122125
const eventHandlerLambda = new NodejsFunction(this, 'event-handler-lambda', {
126+
vpc: vpc,
127+
vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS },
123128
entry: path.join(__dirname, '../lambdas/appRegistryWaiterLambda.ts'),
124129
handler: 'handler',
125130
description:

source/lib/constructs/baseInfrastructure.ts

+50-42
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export interface BaseInfrastructureProps {
4141
readonly vpcCidr?: string;
4242
readonly initBastion?: boolean;
4343
readonly initInstallationBucket?: boolean;
44+
readonly selfManageInstallationBucketAssets?: boolean;
4445
readonly druidClusterName: string;
4546
readonly druidDeepStorageConfig?: DruidDeepStorageConfig;
4647
readonly oidcIdpConfig?: OidcIdpConfig;
@@ -122,54 +123,61 @@ export class BaseInfrastructure extends Construct {
122123
}
123124
);
124125

125-
new BucketDeployment(this, 'bucket-deployment-scripts', {
126-
sources: [Source.asset('lib/uploads/scripts')],
127-
destinationBucket: this.installationBucket,
128-
destinationKeyPrefix: SCRIPTS_FOLDER,
129-
});
130-
131-
new BucketDeployment(this, 'bucket-deployment-extensions', {
132-
sources: [Source.asset(`lib/docker/extensions`)],
133-
destinationBucket: this.installationBucket,
134-
destinationKeyPrefix: EXTENSIONS_FOLDER,
135-
exclude: ['.gitkeep'],
136-
});
137-
138-
new BucketDeployment(this, 'bucket-deployment-config', {
139-
sources: [Source.asset('lib/uploads/config')],
140-
destinationBucket: this.installationBucket,
141-
destinationKeyPrefix: CONFIG_FOLDER,
142-
exclude: ['*_version.txt'],
143-
});
126+
if (!props.selfManageInstallationBucketAssets) {
127+
new BucketDeployment(this, 'bucket-deployment-scripts', {
128+
sources: [Source.asset('lib/uploads/scripts')],
129+
destinationBucket: this.installationBucket,
130+
destinationKeyPrefix: SCRIPTS_FOLDER,
131+
vpc: this.vpc,
132+
});
144133

145-
new BucketDeployment(this, 'bucket-deployment-rds-ca-bundle', {
146-
sources: [Source.asset('lib/docker/ca-certs')],
147-
destinationBucket: this.installationBucket,
148-
destinationKeyPrefix: 'ca-certs',
149-
});
134+
new BucketDeployment(this, 'bucket-deployment-extensions', {
135+
sources: [Source.asset(`lib/docker/extensions`)],
136+
destinationBucket: this.installationBucket,
137+
destinationKeyPrefix: EXTENSIONS_FOLDER,
138+
exclude: ['.gitkeep'],
139+
vpc: this.vpc,
140+
});
150141

151-
this.druidImageDeployment = new BucketDeployment(
152-
this,
153-
'bucket-deployment-druid-image',
154-
{
155-
sources: [Source.asset('druid-bin/')],
142+
new BucketDeployment(this, 'bucket-deployment-config', {
143+
sources: [Source.asset('lib/uploads/config')],
156144
destinationBucket: this.installationBucket,
157-
destinationKeyPrefix: DRUID_IMAGE_FOLDER,
158-
memoryLimit: 4096,
159-
useEfs: true,
145+
destinationKeyPrefix: CONFIG_FOLDER,
146+
exclude: ['*_version.txt'],
160147
vpc: this.vpc,
161-
}
162-
);
148+
});
163149

164-
this.zookeeperImageDeployment = new BucketDeployment(
165-
this,
166-
'bucket-deployment-zookeeper-image',
167-
{
168-
sources: [Source.asset('zookeeper-bin/')],
150+
new BucketDeployment(this, 'bucket-deployment-rds-ca-bundle', {
151+
sources: [Source.asset('lib/docker/ca-certs')],
169152
destinationBucket: this.installationBucket,
170-
destinationKeyPrefix: ZOOKEEPER_IMAGE_FOLDER,
171-
}
172-
);
153+
destinationKeyPrefix: 'ca-certs',
154+
vpc: this.vpc,
155+
});
156+
157+
this.druidImageDeployment = new BucketDeployment(
158+
this,
159+
'bucket-deployment-druid-image',
160+
{
161+
sources: [Source.asset('druid-bin/')],
162+
destinationBucket: this.installationBucket,
163+
destinationKeyPrefix: DRUID_IMAGE_FOLDER,
164+
memoryLimit: 4096,
165+
useEfs: true,
166+
vpc: this.vpc,
167+
}
168+
);
169+
170+
this.zookeeperImageDeployment = new BucketDeployment(
171+
this,
172+
'bucket-deployment-zookeeper-image',
173+
{
174+
sources: [Source.asset('zookeeper-bin/')],
175+
destinationBucket: this.installationBucket,
176+
destinationKeyPrefix: ZOOKEEPER_IMAGE_FOLDER,
177+
vpc: this.vpc,
178+
}
179+
);
180+
}
173181
}
174182

175183
if (props.initBastion) {

source/lib/constructs/configScheme.ts

+6
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,12 @@ export const configScheme = {
275275
$id: '#/properties/enableVulnerabilityScanJob',
276276
description: 'Whether to enable vulnerability scan job.',
277277
},
278+
selfManageInstallationBucketAssets: {
279+
type: 'boolean',
280+
title: 'Enable self management for installation bucket assets',
281+
$id: '#/properties/selfManageInstallationBucketAssets',
282+
description: 'Whether to enable self management for installation bucket assets.',
283+
},
278284
environmentAgnostic: {
279285
type: 'boolean',
280286
title: 'Environment Agnostic',

source/lib/constructs/internalCertificateAuthority.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import * as cdk from 'aws-cdk-lib';
1919
import * as cr from 'aws-cdk-lib/custom-resources';
20+
import * as ec2 from 'aws-cdk-lib/aws-ec2';
2021
import * as kms from 'aws-cdk-lib/aws-kms';
2122
import * as lambda from 'aws-cdk-lib/aws-lambda';
2223
import * as lambdaNodejs from 'aws-cdk-lib/aws-lambda-nodejs';
@@ -25,10 +26,14 @@ import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
2526

2627
import { Construct } from 'constructs';
2728

29+
export interface InternalCertificateAuthorityProps {
30+
vpc: ec2.IVpc;
31+
}
32+
2833
export class InternalCertificateAuthority extends Construct {
2934
public readonly TlsCertificate: secretsmanager.ISecret;
3035

31-
public constructor(scope: Construct, id: string) {
36+
public constructor(scope: Construct, id: string, props: InternalCertificateAuthorityProps) {
3237
super(scope, id);
3338

3439
this.TlsCertificate = new secretsmanager.Secret(this, 'tls-certificate', {
@@ -44,6 +49,10 @@ export class InternalCertificateAuthority extends Construct {
4449
this,
4550
'tls-generator-handler',
4651
{
52+
vpc: props.vpc,
53+
vpcSubnets: {
54+
subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
55+
},
4756
entry: path.join(__dirname, '../lambdas/certificateGenerator.ts'),
4857
handler: 'onEventHandler',
4958
runtime: lambda.Runtime.NODEJS_LATEST,

source/lib/constructs/operationalMetricCollection.ts

+6
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
import * as cdk from 'aws-cdk-lib';
1717
import * as cr from 'aws-cdk-lib/custom-resources';
18+
import * as ec2 from 'aws-cdk-lib/aws-ec2';
1819
import * as lambda from 'aws-cdk-lib/aws-lambda';
1920
import * as path from 'path';
2021

@@ -24,6 +25,7 @@ import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs';
2425
import { addCfnNagSuppression } from './cfnNagSuppression';
2526

2627
export interface OperationalMetricsCollectionProps {
28+
vpc: ec2.IVpc;
2729
awsSolutionId: string;
2830
awsSolutionVersion: string;
2931
retainData: boolean;
@@ -44,6 +46,10 @@ export class OperationalMetricsCollection extends Construct {
4446
super(scope, id);
4547

4648
const fn = new NodejsFunction(this, 'operational-metrics-handler', {
49+
vpc: props.vpc,
50+
vpcSubnets: {
51+
subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
52+
},
4753
entry: path.join(__dirname, './operationMetricCollectionLambda.ts'),
4854
handler: 'handler',
4955
description: 'Lambda for Operational Metrics collection',

source/lib/stacks/druidEc2Stack.ts

+10-4
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,10 @@ export class DruidEc2Stack extends DruidStack {
8282

8383
const certificateGenerator = new InternalCertificateAuthority(
8484
this,
85-
'internal-certificate-authority'
85+
'internal-certificate-authority',
86+
{
87+
vpc: this.baseInfra.vpc,
88+
}
8689
);
8790

8891
const ec2Config = props.clusterParams.hostingConfig as Ec2Config;
@@ -197,9 +200,11 @@ export class DruidEc2Stack extends DruidStack {
197200
// create data tiers
198201
const dataAsgList = this.createDataTiers(asgContext);
199202
dataAsgList.forEach((dataAsg) => {
200-
dataAsg.autoScalingGroup.node.addDependency(
201-
this.baseInfra.druidImageDeployment!
202-
);
203+
if (this.baseInfra.druidImageDeployment) {
204+
dataAsg.autoScalingGroup.node.addDependency(
205+
this.baseInfra.druidImageDeployment!,
206+
);
207+
}
203208
dataAsg.autoScalingGroup.node.addDependency(
204209
zookeeper.zookeeperASGs[zookeeper.zookeeperASGs.length - 1]
205210
);
@@ -223,6 +228,7 @@ export class DruidEc2Stack extends DruidStack {
223228
});
224229

225230
new OperationalMetricsCollection(this, 'metrics-collection', {
231+
vpc: this.baseInfra.vpc,
226232
awsSolutionId: props.solutionId,
227233
awsSolutionVersion: props.solutionVersion,
228234
druidVersion: props.clusterParams.druidVersion,

source/lib/stacks/druidEksStack.ts

+1
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ export class DruidEksStack extends DruidStack {
8787
}
8888

8989
new OperationalMetricsCollection(this, 'metrics-collection', {
90+
vpc: this.baseInfra.vpc,
9091
awsSolutionId: props.solutionId,
9192
awsSolutionVersion: props.solutionVersion,
9293
druidVersion: props.clusterParams.druidVersion,

source/lib/stacks/druidStack.ts

+2
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ export abstract class DruidStack extends cdk.Stack {
4646
vpcCidr: props.vpcId ? undefined : props.vpcCidr, // don't set cidr for byo vpc
4747
initBastion: props.initBastion,
4848
initInstallationBucket: props.initInstallationBucket,
49+
selfManageInstallationBucketAssets: props.selfManageInstallationBucketAssets,
4950
druidClusterName: props.clusterParams.druidClusterName,
5051
druidDeepStorageConfig: props.clusterParams.druidDeepStorageConfig,
5152
oidcIdpConfig: props.clusterParams.oidcIdpConfig,
@@ -111,6 +112,7 @@ export abstract class DruidStack extends cdk.Stack {
111112

112113
cdk.Aspects.of(this).add(
113114
new AppRegistry(this, 'app-registry-aspect', {
115+
vpc: this.baseInfra.vpc,
114116
solutionId: props.solutionId,
115117
solutionVersion: props.solutionVersion,
116118
solutionName: props.solutionName,

source/lib/utils/types.ts

+2
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ export interface DruidConfig {
7070
readonly retainData?: boolean;
7171
readonly enableVulnerabilityScanJob?: boolean;
7272
readonly environmentAgnostic?: boolean;
73+
readonly selfManageInstallationBucketAssets?: boolean;
7374

7475
readonly druidClusterName: string;
7576
readonly druidVersion: string;
@@ -98,6 +99,7 @@ export interface DruidStackProps extends cdk.StackProps {
9899
readonly vpcCidr?: string;
99100
readonly initBastion?: boolean;
100101
readonly initInstallationBucket?: boolean;
102+
readonly selfManageInstallationBucketAssets?: boolean;
101103
readonly route53Params?: {
102104
readonly route53HostedZoneId: string;
103105
readonly route53HostedZoneName: string;

0 commit comments

Comments
 (0)