@dga-itc/aws-cdk-constructs 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +219 -0
- package/dist/aws-cdk/constructs/acm.d.ts +28 -0
- package/dist/aws-cdk/constructs/acm.js +239 -0
- package/dist/aws-cdk/constructs/alb.d.ts +28 -0
- package/dist/aws-cdk/constructs/alb.js +304 -0
- package/dist/aws-cdk/constructs/bastion.d.ts +46 -0
- package/dist/aws-cdk/constructs/bastion.js +332 -0
- package/dist/aws-cdk/constructs/cloudfront.d.ts +45 -0
- package/dist/aws-cdk/constructs/cloudfront.js +261 -0
- package/dist/aws-cdk/constructs/ecr.d.ts +17 -0
- package/dist/aws-cdk/constructs/ecr.js +143 -0
- package/dist/aws-cdk/constructs/ecs-cluster.d.ts +21 -0
- package/dist/aws-cdk/constructs/ecs-cluster.js +124 -0
- package/dist/aws-cdk/constructs/ecs-service.d.ts +72 -0
- package/dist/aws-cdk/constructs/ecs-service.js +682 -0
- package/dist/aws-cdk/constructs/efs.d.ts +31 -0
- package/dist/aws-cdk/constructs/efs.js +241 -0
- package/dist/aws-cdk/constructs/elasticache.d.ts +35 -0
- package/dist/aws-cdk/constructs/elasticache.js +210 -0
- package/dist/aws-cdk/constructs/nacl.d.ts +37 -0
- package/dist/aws-cdk/constructs/nacl.js +88 -0
- package/dist/aws-cdk/constructs/nlb.d.ts +39 -0
- package/dist/aws-cdk/constructs/nlb.js +276 -0
- package/dist/aws-cdk/constructs/rds.d.ts +40 -0
- package/dist/aws-cdk/constructs/rds.js +320 -0
- package/dist/aws-cdk/constructs/self-signed-cert.d.ts +83 -0
- package/dist/aws-cdk/constructs/self-signed-cert.js +215 -0
- package/dist/aws-cdk/constructs/sqs.d.ts +30 -0
- package/dist/aws-cdk/constructs/sqs.js +268 -0
- package/dist/aws-cdk/constructs/vpc.d.ts +30 -0
- package/dist/aws-cdk/constructs/vpc.js +423 -0
- package/dist/aws-cdk/constructs/waf.d.ts +37 -0
- package/dist/aws-cdk/constructs/waf.js +350 -0
- package/dist/aws-cdk/interfaces/account-config.d.ts +18 -0
- package/dist/aws-cdk/interfaces/account-config.js +2 -0
- package/dist/aws-cdk/interfaces/acm-config.d.ts +94 -0
- package/dist/aws-cdk/interfaces/acm-config.js +14 -0
- package/dist/aws-cdk/interfaces/alb-config.d.ts +72 -0
- package/dist/aws-cdk/interfaces/alb-config.js +2 -0
- package/dist/aws-cdk/interfaces/bastion-config.d.ts +77 -0
- package/dist/aws-cdk/interfaces/bastion-config.js +10 -0
- package/dist/aws-cdk/interfaces/cloudfront-config.d.ts +154 -0
- package/dist/aws-cdk/interfaces/cloudfront-config.js +15 -0
- package/dist/aws-cdk/interfaces/ecr-config.d.ts +40 -0
- package/dist/aws-cdk/interfaces/ecr-config.js +2 -0
- package/dist/aws-cdk/interfaces/ecs-cluster-config.d.ts +30 -0
- package/dist/aws-cdk/interfaces/ecs-cluster-config.js +2 -0
- package/dist/aws-cdk/interfaces/ecs-service-config.d.ts +237 -0
- package/dist/aws-cdk/interfaces/ecs-service-config.js +2 -0
- package/dist/aws-cdk/interfaces/efs-config.d.ts +56 -0
- package/dist/aws-cdk/interfaces/efs-config.js +7 -0
- package/dist/aws-cdk/interfaces/elasticache-config.d.ts +56 -0
- package/dist/aws-cdk/interfaces/elasticache-config.js +7 -0
- package/dist/aws-cdk/interfaces/nacl-config.d.ts +1 -0
- package/dist/aws-cdk/interfaces/nacl-config.js +3 -0
- package/dist/aws-cdk/interfaces/nlb-config.d.ts +69 -0
- package/dist/aws-cdk/interfaces/nlb-config.js +2 -0
- package/dist/aws-cdk/interfaces/rds-config.d.ts +84 -0
- package/dist/aws-cdk/interfaces/rds-config.js +7 -0
- package/dist/aws-cdk/interfaces/sqs-config.d.ts +145 -0
- package/dist/aws-cdk/interfaces/sqs-config.js +12 -0
- package/dist/aws-cdk/interfaces/tag-config.d.ts +18 -0
- package/dist/aws-cdk/interfaces/tag-config.js +2 -0
- package/dist/aws-cdk/interfaces/vpc-config.d.ts +72 -0
- package/dist/aws-cdk/interfaces/vpc-config.js +2 -0
- package/dist/aws-cdk/interfaces/waf-config.d.ts +180 -0
- package/dist/aws-cdk/interfaces/waf-config.js +2 -0
- package/dist/aws-cdk/utils/priority-tracker.d.ts +60 -0
- package/dist/aws-cdk/utils/priority-tracker.js +131 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +55 -0
- package/dist/terraform-cdk/constructs/alb-listener-rule.d.ts +33 -0
- package/dist/terraform-cdk/constructs/alb-listener-rule.js +81 -0
- package/dist/terraform-cdk/constructs/ecs-service.d.ts +29 -0
- package/dist/terraform-cdk/constructs/ecs-service.js +238 -0
- package/dist/terraform-cdk/interfaces/ecs-service-config.d.ts +53 -0
- package/dist/terraform-cdk/interfaces/ecs-service-config.js +25 -0
- package/dist/terraform-cdk/interfaces/infrastructure-refs.d.ts +16 -0
- package/dist/terraform-cdk/interfaces/infrastructure-refs.js +8 -0
- package/dist/terraform-cdk/utils/priority-tracker.d.ts +60 -0
- package/dist/terraform-cdk/utils/priority-tracker.js +131 -0
- package/package.json +46 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Construct } from 'constructs';
|
|
2
|
+
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
|
|
3
|
+
import { CloudFrontConfig } from '../interfaces/cloudfront-config';
|
|
4
|
+
import { VpcConstruct } from './vpc';
|
|
5
|
+
import { AlbConstruct } from './alb';
|
|
6
|
+
import { AcmConstruct } from './acm';
|
|
7
|
+
export interface CloudFrontConstructProps {
|
|
8
|
+
config: CloudFrontConfig;
|
|
9
|
+
/** VpcConstruct from NetworkStack */
|
|
10
|
+
vpcConstruct: VpcConstruct;
|
|
11
|
+
/** AlbConstruct from AlbStack — origin target */
|
|
12
|
+
albConstruct: AlbConstruct;
|
|
13
|
+
/** AcmConstruct from AcmStack — certificate สำหรับ CloudFront (us-east-1) */
|
|
14
|
+
acmConstruct?: AcmConstruct;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* CloudFront + VPC Origin Construct
|
|
18
|
+
*
|
|
19
|
+
* สร้าง:
|
|
20
|
+
* 1. CloudFront VPC Origin — เชื่อมต่อ ALB private ผ่าน AWS backbone
|
|
21
|
+
* 2. CloudFront Distribution — CDN ด้านหน้า
|
|
22
|
+
* 3. (Optional) ALB SG rule — allow CloudFront traffic
|
|
23
|
+
*
|
|
24
|
+
* Architecture:
|
|
25
|
+
* Client → CloudFront Edge → VPC Origin → Private ALB → ECS
|
|
26
|
+
*/
|
|
27
|
+
export declare class CloudFrontConstruct extends Construct {
|
|
28
|
+
readonly distribution: cloudfront.CfnDistribution;
|
|
29
|
+
readonly vpcOrigin: cloudfront.CfnVpcOrigin;
|
|
30
|
+
readonly distributionDomainName: string;
|
|
31
|
+
readonly distributionId: string;
|
|
32
|
+
readonly vpcOriginId: string;
|
|
33
|
+
private readonly removalPolicy;
|
|
34
|
+
constructor(scope: Construct, id: string, props: CloudFrontConstructProps);
|
|
35
|
+
private createVpcOrigin;
|
|
36
|
+
private createDistribution;
|
|
37
|
+
/**
|
|
38
|
+
* เพิ่ม inbound rule ให้ ALB SG เพื่อรับ traffic จาก CloudFront VPC Origin
|
|
39
|
+
*
|
|
40
|
+
* ถ้ามี cloudFrontPrefixListId → ใช้ managed prefix list (recommended สำหรับ production)
|
|
41
|
+
* ถ้าไม่มี → allow จาก 0.0.0.0/0 (ALB เป็น internal อยู่แล้ว ปลอดภัยในระดับหนึ่ง)
|
|
42
|
+
*/
|
|
43
|
+
private addAlbSecurityGroupRule;
|
|
44
|
+
private createOutputs;
|
|
45
|
+
}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.CloudFrontConstruct = void 0;
|
|
37
|
+
const constructs_1 = require("constructs");
|
|
38
|
+
const cdk = __importStar(require("aws-cdk-lib"));
|
|
39
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
40
|
+
const cloudfront = __importStar(require("aws-cdk-lib/aws-cloudfront"));
|
|
41
|
+
const ec2 = __importStar(require("aws-cdk-lib/aws-ec2"));
|
|
42
|
+
/**
|
|
43
|
+
* CloudFront + VPC Origin Construct
|
|
44
|
+
*
|
|
45
|
+
* สร้าง:
|
|
46
|
+
* 1. CloudFront VPC Origin — เชื่อมต่อ ALB private ผ่าน AWS backbone
|
|
47
|
+
* 2. CloudFront Distribution — CDN ด้านหน้า
|
|
48
|
+
* 3. (Optional) ALB SG rule — allow CloudFront traffic
|
|
49
|
+
*
|
|
50
|
+
* Architecture:
|
|
51
|
+
* Client → CloudFront Edge → VPC Origin → Private ALB → ECS
|
|
52
|
+
*/
|
|
53
|
+
class CloudFrontConstruct extends constructs_1.Construct {
|
|
54
|
+
constructor(scope, id, props) {
|
|
55
|
+
super(scope, id);
|
|
56
|
+
const { config, vpcConstruct, albConstruct, acmConstruct } = props;
|
|
57
|
+
this.removalPolicy = config.removalPolicy === 'retain'
|
|
58
|
+
? aws_cdk_lib_1.RemovalPolicy.RETAIN
|
|
59
|
+
: aws_cdk_lib_1.RemovalPolicy.DESTROY;
|
|
60
|
+
// ------------------------------------------
|
|
61
|
+
// A. Create VPC Origin
|
|
62
|
+
// ------------------------------------------
|
|
63
|
+
this.vpcOrigin = this.createVpcOrigin(config, albConstruct);
|
|
64
|
+
// ------------------------------------------
|
|
65
|
+
// B. Create CloudFront Distribution
|
|
66
|
+
// ------------------------------------------
|
|
67
|
+
this.distribution = this.createDistribution(config, albConstruct, acmConstruct);
|
|
68
|
+
// ------------------------------------------
|
|
69
|
+
// C. (Optional) Update ALB Security Group
|
|
70
|
+
// ------------------------------------------
|
|
71
|
+
if (config.updateAlbSecurityGroup !== false) {
|
|
72
|
+
this.addAlbSecurityGroupRule(config, albConstruct);
|
|
73
|
+
}
|
|
74
|
+
// ------------------------------------------
|
|
75
|
+
// D. Apply Removal Policy
|
|
76
|
+
// ------------------------------------------
|
|
77
|
+
this.vpcOrigin.applyRemovalPolicy(this.removalPolicy);
|
|
78
|
+
this.distribution.applyRemovalPolicy(this.removalPolicy);
|
|
79
|
+
// ------------------------------------------
|
|
80
|
+
// E. Expose Attributes
|
|
81
|
+
// ------------------------------------------
|
|
82
|
+
this.distributionDomainName = this.distribution.attrDomainName;
|
|
83
|
+
this.distributionId = this.distribution.ref;
|
|
84
|
+
this.vpcOriginId = this.vpcOrigin.attrId;
|
|
85
|
+
// ------------------------------------------
|
|
86
|
+
// F. Outputs
|
|
87
|
+
// ------------------------------------------
|
|
88
|
+
this.createOutputs(config);
|
|
89
|
+
}
|
|
90
|
+
// ==========================================
|
|
91
|
+
// A. VPC Origin
|
|
92
|
+
// ==========================================
|
|
93
|
+
createVpcOrigin(config, albConstruct) {
|
|
94
|
+
const vo = config.vpcOrigin;
|
|
95
|
+
return new cloudfront.CfnVpcOrigin(this, 'VpcOrigin', {
|
|
96
|
+
vpcOriginEndpointConfig: {
|
|
97
|
+
arn: albConstruct.alb.loadBalancerArn,
|
|
98
|
+
httpPort: vo.httpPort ?? 80,
|
|
99
|
+
httpsPort: vo.httpsPort ?? 443,
|
|
100
|
+
name: vo.name,
|
|
101
|
+
originProtocolPolicy: vo.originProtocolPolicy ?? 'https-only',
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
// ==========================================
|
|
106
|
+
// B. Distribution
|
|
107
|
+
// ==========================================
|
|
108
|
+
createDistribution(config, albConstruct, acmConstruct) {
|
|
109
|
+
const originId = 'vpc-alb-origin';
|
|
110
|
+
const voConfig = config.vpcOrigin;
|
|
111
|
+
const defaultBehavior = config.defaultCacheBehavior ?? {};
|
|
112
|
+
// --- Viewer Certificate ---
|
|
113
|
+
const certArn = acmConstruct?.certificateArn ?? config.certificateArn;
|
|
114
|
+
let viewerCertificate;
|
|
115
|
+
if (certArn && config.domainNames && config.domainNames.length > 0) {
|
|
116
|
+
viewerCertificate = {
|
|
117
|
+
acmCertificateArn: certArn,
|
|
118
|
+
minimumProtocolVersion: config.minimumProtocolVersion ?? 'TLSv1.2_2021',
|
|
119
|
+
sslSupportMethod: 'sni-only',
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
viewerCertificate = {
|
|
124
|
+
cloudFrontDefaultCertificate: true,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
// --- Default Cache Behavior ---
|
|
128
|
+
const defaultCacheBehavior = {
|
|
129
|
+
targetOriginId: originId,
|
|
130
|
+
viewerProtocolPolicy: defaultBehavior.viewerProtocolPolicy ?? 'redirect-to-https',
|
|
131
|
+
allowedMethods: defaultBehavior.allowedMethods
|
|
132
|
+
?? ['GET', 'HEAD', 'OPTIONS', 'PUT', 'POST', 'PATCH', 'DELETE'],
|
|
133
|
+
cachedMethods: defaultBehavior.cachedMethods ?? ['GET', 'HEAD'],
|
|
134
|
+
// Default: CachingDisabled — เหมาะกับ dynamic content (ALB → ECS)
|
|
135
|
+
cachePolicyId: defaultBehavior.cachePolicyId
|
|
136
|
+
?? '4135ea2d-6df8-44a3-9df3-4b5a84be39ad',
|
|
137
|
+
// Default: AllViewer — forward ทุก header ไป origin
|
|
138
|
+
originRequestPolicyId: defaultBehavior.originRequestPolicyId
|
|
139
|
+
?? '216adef6-5c7f-47e4-b989-5492eafa07d3',
|
|
140
|
+
compress: defaultBehavior.compress ?? true,
|
|
141
|
+
responseHeadersPolicyId: defaultBehavior.responseHeadersPolicyId,
|
|
142
|
+
};
|
|
143
|
+
// --- Additional Cache Behaviors ---
|
|
144
|
+
const cacheBehaviors = config.additionalBehaviors?.map((ab) => ({
|
|
145
|
+
pathPattern: ab.pathPattern,
|
|
146
|
+
targetOriginId: originId,
|
|
147
|
+
viewerProtocolPolicy: ab.behavior.viewerProtocolPolicy ?? 'redirect-to-https',
|
|
148
|
+
allowedMethods: ab.behavior.allowedMethods ?? ['GET', 'HEAD'],
|
|
149
|
+
cachedMethods: ab.behavior.cachedMethods ?? ['GET', 'HEAD'],
|
|
150
|
+
// Default: CachingOptimized — เหมาะกับ static content
|
|
151
|
+
cachePolicyId: ab.behavior.cachePolicyId
|
|
152
|
+
?? '658327ea-f89d-4fab-a63d-7e88639e58f6',
|
|
153
|
+
originRequestPolicyId: ab.behavior.originRequestPolicyId,
|
|
154
|
+
compress: ab.behavior.compress ?? true,
|
|
155
|
+
responseHeadersPolicyId: ab.behavior.responseHeadersPolicyId,
|
|
156
|
+
}));
|
|
157
|
+
// --- Custom Error Responses ---
|
|
158
|
+
const customErrorResponses = config.customErrorResponses?.map((err) => ({
|
|
159
|
+
errorCode: err.errorCode,
|
|
160
|
+
responseCode: err.responseCode,
|
|
161
|
+
responsePagePath: err.responsePagePath,
|
|
162
|
+
errorCachingMinTtl: err.errorCachingMinTtl,
|
|
163
|
+
}));
|
|
164
|
+
// --- Create Distribution ---
|
|
165
|
+
const distribution = new cloudfront.CfnDistribution(this, 'Distribution', {
|
|
166
|
+
distributionConfig: {
|
|
167
|
+
enabled: config.enabled ?? true,
|
|
168
|
+
comment: config.distributionComment
|
|
169
|
+
?? `${config.stackName} — CloudFront + VPC Origin → Private ALB`,
|
|
170
|
+
httpVersion: config.httpVersion ?? 'http2and3',
|
|
171
|
+
priceClass: config.priceClass ?? 'PriceClass_200',
|
|
172
|
+
// Origin: ALB via VPC Origin
|
|
173
|
+
origins: [{
|
|
174
|
+
domainName: albConstruct.alb.loadBalancerDnsName,
|
|
175
|
+
id: originId,
|
|
176
|
+
// VPC Origin Config จะถูก add ผ่าน escape hatch ด้านล่าง
|
|
177
|
+
}],
|
|
178
|
+
defaultCacheBehavior,
|
|
179
|
+
cacheBehaviors,
|
|
180
|
+
viewerCertificate,
|
|
181
|
+
aliases: config.domainNames,
|
|
182
|
+
webAclId: config.webAclId,
|
|
183
|
+
customErrorResponses,
|
|
184
|
+
},
|
|
185
|
+
});
|
|
186
|
+
// --- Add VpcOriginConfig via escape hatch ---
|
|
187
|
+
// ใช้ addPropertyOverride เพื่อความเข้ากันได้กับ CDK ทุกเวอร์ชัน
|
|
188
|
+
distribution.addPropertyOverride('DistributionConfig.Origins.0.VpcOriginConfig', {
|
|
189
|
+
VpcOriginId: this.vpcOrigin.attrId,
|
|
190
|
+
OriginReadTimeout: voConfig.originReadTimeout ?? 30,
|
|
191
|
+
OriginKeepaliveTimeout: voConfig.originKeepaliveTimeout ?? 5,
|
|
192
|
+
});
|
|
193
|
+
// ลบ customOriginConfig / s3OriginConfig ที่อาจถูก generate อัตโนมัติ
|
|
194
|
+
distribution.addPropertyDeletionOverride('DistributionConfig.Origins.0.S3OriginConfig');
|
|
195
|
+
return distribution;
|
|
196
|
+
}
|
|
197
|
+
// ==========================================
|
|
198
|
+
// C. ALB Security Group Rule
|
|
199
|
+
// ==========================================
|
|
200
|
+
/**
|
|
201
|
+
* เพิ่ม inbound rule ให้ ALB SG เพื่อรับ traffic จาก CloudFront VPC Origin
|
|
202
|
+
*
|
|
203
|
+
* ถ้ามี cloudFrontPrefixListId → ใช้ managed prefix list (recommended สำหรับ production)
|
|
204
|
+
* ถ้าไม่มี → allow จาก 0.0.0.0/0 (ALB เป็น internal อยู่แล้ว ปลอดภัยในระดับหนึ่ง)
|
|
205
|
+
*/
|
|
206
|
+
addAlbSecurityGroupRule(config, albConstruct) {
|
|
207
|
+
const httpsPort = config.vpcOrigin.httpsPort ?? 443;
|
|
208
|
+
const httpPort = config.vpcOrigin.httpPort ?? 80;
|
|
209
|
+
if (config.cloudFrontPrefixListId) {
|
|
210
|
+
// Use managed prefix list (more restrictive)
|
|
211
|
+
albConstruct.securityGroup.addIngressRule(ec2.Peer.prefixList(config.cloudFrontPrefixListId), ec2.Port.tcp(httpsPort), 'Allow HTTPS from CloudFront VPC Origin (managed prefix list)');
|
|
212
|
+
if (config.vpcOrigin.originProtocolPolicy === 'http-only') {
|
|
213
|
+
albConstruct.securityGroup.addIngressRule(ec2.Peer.prefixList(config.cloudFrontPrefixListId), ec2.Port.tcp(httpPort), 'Allow HTTP from CloudFront VPC Origin (managed prefix list)');
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
// Fallback: allow from anywhere
|
|
218
|
+
// ⚠️ ALB เป็น internal (private subnets) จึงยังปลอดภัย
|
|
219
|
+
// สำหรับ production ควรระบุ cloudFrontPrefixListId
|
|
220
|
+
albConstruct.securityGroup.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(httpsPort), 'Allow HTTPS from CloudFront VPC Origin');
|
|
221
|
+
if (config.vpcOrigin.originProtocolPolicy === 'http-only') {
|
|
222
|
+
albConstruct.securityGroup.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(httpPort), 'Allow HTTP from CloudFront VPC Origin');
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
// ==========================================
|
|
227
|
+
// F. Outputs
|
|
228
|
+
// ==========================================
|
|
229
|
+
createOutputs(config) {
|
|
230
|
+
const stack = cdk.Stack.of(this);
|
|
231
|
+
const prefix = config.stackName;
|
|
232
|
+
new cdk.CfnOutput(stack, 'DistributionId', {
|
|
233
|
+
value: this.distribution.ref,
|
|
234
|
+
description: 'CloudFront Distribution ID',
|
|
235
|
+
exportName: `${prefix}-CF-DistributionId`,
|
|
236
|
+
});
|
|
237
|
+
new cdk.CfnOutput(stack, 'DistributionDomainName', {
|
|
238
|
+
value: this.distribution.attrDomainName,
|
|
239
|
+
description: 'CloudFront Distribution Domain Name (*.cloudfront.net)',
|
|
240
|
+
exportName: `${prefix}-CF-DomainName`,
|
|
241
|
+
});
|
|
242
|
+
new cdk.CfnOutput(stack, 'VpcOriginId', {
|
|
243
|
+
value: this.vpcOrigin.attrId,
|
|
244
|
+
description: 'CloudFront VPC Origin ID',
|
|
245
|
+
exportName: `${prefix}-CF-VpcOriginId`,
|
|
246
|
+
});
|
|
247
|
+
new cdk.CfnOutput(stack, 'VpcOriginArn', {
|
|
248
|
+
value: this.vpcOrigin.attrArn,
|
|
249
|
+
description: 'CloudFront VPC Origin ARN',
|
|
250
|
+
exportName: `${prefix}-CF-VpcOriginArn`,
|
|
251
|
+
});
|
|
252
|
+
if (config.domainNames && config.domainNames.length > 0) {
|
|
253
|
+
new cdk.CfnOutput(stack, 'Aliases', {
|
|
254
|
+
value: config.domainNames.join(', '),
|
|
255
|
+
description: 'CloudFront Domain Aliases',
|
|
256
|
+
exportName: `${prefix}-CF-Aliases`,
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
exports.CloudFrontConstruct = CloudFrontConstruct;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Construct } from 'constructs';
|
|
2
|
+
import * as ecr from 'aws-cdk-lib/aws-ecr';
|
|
3
|
+
import { EcrConfig } from '../interfaces/ecr-config';
|
|
4
|
+
export interface EcrConstructProps {
|
|
5
|
+
config: EcrConfig;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* ECR Construct - สร้าง ECR Repository + Lifecycle Rules
|
|
9
|
+
*/
|
|
10
|
+
export declare class EcrConstruct extends Construct {
|
|
11
|
+
readonly repository: ecr.Repository;
|
|
12
|
+
private readonly removalPolicy;
|
|
13
|
+
constructor(scope: Construct, id: string, props: EcrConstructProps);
|
|
14
|
+
private createRepository;
|
|
15
|
+
private addLifecycleRules;
|
|
16
|
+
private createOutputs;
|
|
17
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.EcrConstruct = void 0;
|
|
37
|
+
const constructs_1 = require("constructs");
|
|
38
|
+
const cdk = __importStar(require("aws-cdk-lib"));
|
|
39
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
40
|
+
const ecr = __importStar(require("aws-cdk-lib/aws-ecr"));
|
|
41
|
+
/**
|
|
42
|
+
* ECR Construct - สร้าง ECR Repository + Lifecycle Rules
|
|
43
|
+
*/
|
|
44
|
+
class EcrConstruct extends constructs_1.Construct {
|
|
45
|
+
constructor(scope, id, props) {
|
|
46
|
+
super(scope, id);
|
|
47
|
+
const { config } = props;
|
|
48
|
+
this.removalPolicy = config.removalPolicy === 'retain'
|
|
49
|
+
? aws_cdk_lib_1.RemovalPolicy.RETAIN
|
|
50
|
+
: aws_cdk_lib_1.RemovalPolicy.DESTROY;
|
|
51
|
+
// A. Create Repository
|
|
52
|
+
this.repository = this.createRepository(config);
|
|
53
|
+
// B. Add Lifecycle Rules
|
|
54
|
+
this.addLifecycleRules(config);
|
|
55
|
+
// C. Apply Removal Policy
|
|
56
|
+
this.repository.applyRemovalPolicy(this.removalPolicy);
|
|
57
|
+
// D. Outputs
|
|
58
|
+
this.createOutputs(config);
|
|
59
|
+
}
|
|
60
|
+
// ==========================================
|
|
61
|
+
// Create Repository
|
|
62
|
+
// ==========================================
|
|
63
|
+
createRepository(config) {
|
|
64
|
+
const isDestroy = config.removalPolicy !== 'retain';
|
|
65
|
+
return new ecr.Repository(this, 'EcrRepository', {
|
|
66
|
+
repositoryName: config.repositoryName,
|
|
67
|
+
imageTagMutability: config.imageTagMutability === 'IMMUTABLE'
|
|
68
|
+
? ecr.TagMutability.IMMUTABLE
|
|
69
|
+
: ecr.TagMutability.MUTABLE,
|
|
70
|
+
imageScanOnPush: config.scanOnPush ?? true,
|
|
71
|
+
removalPolicy: this.removalPolicy,
|
|
72
|
+
emptyOnDelete: config.emptyOnDelete ?? isDestroy,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
// ==========================================
|
|
76
|
+
// Add Lifecycle Rules
|
|
77
|
+
// ==========================================
|
|
78
|
+
addLifecycleRules(config) {
|
|
79
|
+
// ถ้ามี lifecycleRules แบบ custom ใช้ตัวนั้น
|
|
80
|
+
if (config.lifecycleRules && config.lifecycleRules.length > 0) {
|
|
81
|
+
config.lifecycleRules.forEach((rule) => {
|
|
82
|
+
this.repository.addLifecycleRule({
|
|
83
|
+
rulePriority: rule.rulePriority,
|
|
84
|
+
description: rule.description,
|
|
85
|
+
tagStatus: rule.tagStatus === 'tagged'
|
|
86
|
+
? ecr.TagStatus.TAGGED
|
|
87
|
+
: rule.tagStatus === 'untagged'
|
|
88
|
+
? ecr.TagStatus.UNTAGGED
|
|
89
|
+
: ecr.TagStatus.ANY,
|
|
90
|
+
tagPrefixList: rule.tagPrefixList,
|
|
91
|
+
maxImageCount: rule.maxImageCount,
|
|
92
|
+
maxImageAge: rule.maxImageAgeDays
|
|
93
|
+
? cdk.Duration.days(rule.maxImageAgeDays)
|
|
94
|
+
: undefined,
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
// ถ้าไม่มี lifecycleRules ใช้ shorthand
|
|
100
|
+
const maxImages = config.lifecycleMaxImages ?? 30;
|
|
101
|
+
const daysUntagged = config.lifecycleDaysUntagged ?? 14;
|
|
102
|
+
// Rule 1: Keep last N tagged images
|
|
103
|
+
this.repository.addLifecycleRule({
|
|
104
|
+
rulePriority: 1,
|
|
105
|
+
description: `Keep last ${maxImages} tagged images`,
|
|
106
|
+
tagStatus: ecr.TagStatus.TAGGED,
|
|
107
|
+
tagPrefixList: ['v', 'latest', 'main', 'dev', 'prod', 'uat', 'pre-prod'],
|
|
108
|
+
maxImageCount: maxImages,
|
|
109
|
+
});
|
|
110
|
+
// Rule 2: Delete old untagged images
|
|
111
|
+
this.repository.addLifecycleRule({
|
|
112
|
+
rulePriority: 2,
|
|
113
|
+
description: `Delete untagged images older than ${daysUntagged} days`,
|
|
114
|
+
tagStatus: ecr.TagStatus.UNTAGGED,
|
|
115
|
+
maxImageAge: cdk.Duration.days(daysUntagged),
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
// ==========================================
|
|
119
|
+
// Outputs
|
|
120
|
+
// ==========================================
|
|
121
|
+
createOutputs(config) {
|
|
122
|
+
const stack = cdk.Stack.of(this);
|
|
123
|
+
const prefix = config.stackName;
|
|
124
|
+
// Use sanitized repo name for unique output IDs within same stack
|
|
125
|
+
const repoShort = config.repositoryName.replace(/[^a-zA-Z0-9]/g, '');
|
|
126
|
+
new cdk.CfnOutput(stack, `${repoShort}EcrRepositoryUri`, {
|
|
127
|
+
value: this.repository.repositoryUri,
|
|
128
|
+
description: `ECR Repository URI (${config.repositoryName})`,
|
|
129
|
+
exportName: `${prefix}-ECR-Uri`,
|
|
130
|
+
});
|
|
131
|
+
new cdk.CfnOutput(stack, `${repoShort}EcrRepositoryArn`, {
|
|
132
|
+
value: this.repository.repositoryArn,
|
|
133
|
+
description: `ECR Repository ARN (${config.repositoryName})`,
|
|
134
|
+
exportName: `${prefix}-ECR-Arn`,
|
|
135
|
+
});
|
|
136
|
+
new cdk.CfnOutput(stack, `${repoShort}EcrRepositoryName`, {
|
|
137
|
+
value: this.repository.repositoryName,
|
|
138
|
+
description: `ECR Repository Name (${config.repositoryName})`,
|
|
139
|
+
exportName: `${prefix}-ECR-Name`,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
exports.EcrConstruct = EcrConstruct;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Construct } from 'constructs';
|
|
2
|
+
import * as ecs from 'aws-cdk-lib/aws-ecs';
|
|
3
|
+
import { EcsClusterConfig } from '../interfaces/ecs-cluster-config';
|
|
4
|
+
import { VpcConstruct } from './vpc';
|
|
5
|
+
export interface EcsClusterConstructProps {
|
|
6
|
+
config: EcsClusterConfig;
|
|
7
|
+
vpcConstruct: VpcConstruct;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* ECS Cluster Construct - สร้าง ECS Cluster + Container Insights
|
|
11
|
+
*
|
|
12
|
+
* อ้างอิง VpcConstruct จาก NetworkStack เพื่อดึง VPC
|
|
13
|
+
*/
|
|
14
|
+
export declare class EcsClusterConstruct extends Construct {
|
|
15
|
+
readonly cluster: ecs.Cluster;
|
|
16
|
+
private readonly removalPolicy;
|
|
17
|
+
constructor(scope: Construct, id: string, props: EcsClusterConstructProps);
|
|
18
|
+
private resolveVpc;
|
|
19
|
+
private createCluster;
|
|
20
|
+
private createOutputs;
|
|
21
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.EcsClusterConstruct = void 0;
|
|
37
|
+
const constructs_1 = require("constructs");
|
|
38
|
+
const cdk = __importStar(require("aws-cdk-lib"));
|
|
39
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
40
|
+
const ec2 = __importStar(require("aws-cdk-lib/aws-ec2"));
|
|
41
|
+
const ecs = __importStar(require("aws-cdk-lib/aws-ecs"));
|
|
42
|
+
/**
|
|
43
|
+
* ECS Cluster Construct - สร้าง ECS Cluster + Container Insights
|
|
44
|
+
*
|
|
45
|
+
* อ้างอิง VpcConstruct จาก NetworkStack เพื่อดึง VPC
|
|
46
|
+
*/
|
|
47
|
+
class EcsClusterConstruct extends constructs_1.Construct {
|
|
48
|
+
constructor(scope, id, props) {
|
|
49
|
+
super(scope, id);
|
|
50
|
+
const { config, vpcConstruct } = props;
|
|
51
|
+
this.removalPolicy = config.removalPolicy === 'retain'
|
|
52
|
+
? aws_cdk_lib_1.RemovalPolicy.RETAIN
|
|
53
|
+
: aws_cdk_lib_1.RemovalPolicy.DESTROY;
|
|
54
|
+
// A. Resolve VPC
|
|
55
|
+
const vpc = this.resolveVpc(vpcConstruct);
|
|
56
|
+
// B. Create Cluster
|
|
57
|
+
this.cluster = this.createCluster(config, vpc);
|
|
58
|
+
// C. Apply Removal Policy
|
|
59
|
+
this.cluster.applyRemovalPolicy(this.removalPolicy);
|
|
60
|
+
// D. Outputs
|
|
61
|
+
this.createOutputs(config);
|
|
62
|
+
}
|
|
63
|
+
// ==========================================
|
|
64
|
+
// Resolve VPC
|
|
65
|
+
// ==========================================
|
|
66
|
+
resolveVpc(vpcConstruct) {
|
|
67
|
+
// ดึง AZ จาก subnets ทั้งหมด
|
|
68
|
+
const allAzs = new Set();
|
|
69
|
+
vpcConstruct.subnetsByName.forEach((subnets) => {
|
|
70
|
+
subnets.forEach((s) => {
|
|
71
|
+
if (s.availabilityZone)
|
|
72
|
+
allAzs.add(s.availabilityZone);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
return ec2.Vpc.fromVpcAttributes(this, 'Vpc', {
|
|
76
|
+
vpcId: vpcConstruct.vpc.ref,
|
|
77
|
+
availabilityZones: Array.from(allAzs),
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
// ==========================================
|
|
81
|
+
// Create Cluster
|
|
82
|
+
// ==========================================
|
|
83
|
+
createCluster(config, vpc) {
|
|
84
|
+
const insightsEnabled = config.containerInsightsEnabled ?? true;
|
|
85
|
+
const cluster = new ecs.Cluster(this, 'EcsCluster', {
|
|
86
|
+
vpc,
|
|
87
|
+
clusterName: config.clusterName,
|
|
88
|
+
containerInsightsV2: insightsEnabled
|
|
89
|
+
? ecs.ContainerInsights.ENHANCED
|
|
90
|
+
: ecs.ContainerInsights.DISABLED,
|
|
91
|
+
enableFargateCapacityProviders: true,
|
|
92
|
+
executeCommandConfiguration: config.enableExecuteCommand
|
|
93
|
+
? { logging: ecs.ExecuteCommandLogging.DEFAULT }
|
|
94
|
+
: undefined,
|
|
95
|
+
});
|
|
96
|
+
// Default capacity provider strategy (ต้องส่ง array ทั้งหมดในครั้งเดียว)
|
|
97
|
+
if (config.defaultCapacityProviderStrategy && config.defaultCapacityProviderStrategy.length > 0) {
|
|
98
|
+
cluster.addDefaultCapacityProviderStrategy(config.defaultCapacityProviderStrategy.map((strategy) => ({
|
|
99
|
+
capacityProvider: strategy.capacityProvider,
|
|
100
|
+
weight: strategy.weight,
|
|
101
|
+
base: strategy.base,
|
|
102
|
+
})));
|
|
103
|
+
}
|
|
104
|
+
return cluster;
|
|
105
|
+
}
|
|
106
|
+
// ==========================================
|
|
107
|
+
// Outputs
|
|
108
|
+
// ==========================================
|
|
109
|
+
createOutputs(config) {
|
|
110
|
+
const stack = cdk.Stack.of(this);
|
|
111
|
+
const prefix = config.stackName;
|
|
112
|
+
new cdk.CfnOutput(stack, 'EcsClusterName', {
|
|
113
|
+
value: this.cluster.clusterName,
|
|
114
|
+
description: 'ECS Cluster Name',
|
|
115
|
+
exportName: `${prefix}-ECS-ClusterName`,
|
|
116
|
+
});
|
|
117
|
+
new cdk.CfnOutput(stack, 'EcsClusterArn', {
|
|
118
|
+
value: this.cluster.clusterArn,
|
|
119
|
+
description: 'ECS Cluster ARN',
|
|
120
|
+
exportName: `${prefix}-ECS-ClusterArn`,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
exports.EcsClusterConstruct = EcsClusterConstruct;
|