@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
package/README.md
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# AWS Infrastructure Constructs
|
|
2
|
+
|
|
3
|
+
Reusable AWS infrastructure constructs for AWS CDK projects.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This package provides a collection of well-tested, production-ready infrastructure constructs:
|
|
8
|
+
- **VPC**: Multi-AZ VPC with public/private subnets, NAT gateways, flow logs
|
|
9
|
+
- **ALB**: Application Load Balancer with HTTP/HTTPS listeners
|
|
10
|
+
- **NLB**: Network Load Balancer with TCP/TLS listeners
|
|
11
|
+
- **ECS Cluster**: Fargate-enabled cluster with container insights
|
|
12
|
+
- **ECS Service**: Fargate service with ALB integration, auto-scaling support
|
|
13
|
+
- **RDS**: PostgreSQL/MySQL databases with automated backups
|
|
14
|
+
- **ElastiCache**: Redis/Memcached clusters
|
|
15
|
+
- **EFS**: Elastic File System with encryption
|
|
16
|
+
- **Bastion**: EC2 bastion host for secure access
|
|
17
|
+
- **NACL**: Network ACL rules management
|
|
18
|
+
- **ECR**: Container registry with lifecycle policies
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
### Option 1: npm link (Local Development)
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# In the aws-infra-constructs directory
|
|
26
|
+
npm link
|
|
27
|
+
|
|
28
|
+
# In your project directory
|
|
29
|
+
npm link @dga-itc/aws-cdk-constructs
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Option 2: File Path Reference
|
|
33
|
+
|
|
34
|
+
Add to your `package.json`:
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@dga-itc/aws-cdk-constructs": "file:../aws-infra-constructs"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Option 3: GitHub Packages
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npm install @dga-itc/aws-cdk-constructs --registry=https://npm.pkg.github.com
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Option 4: npmjs.org (Public Package)
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npm install @dga-itc/aws-cdk-constructs
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Usage
|
|
57
|
+
|
|
58
|
+
### AWS CDK Example
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
import { Stack, StackProps } from 'aws-cdk-lib';
|
|
62
|
+
import { Construct } from 'constructs';
|
|
63
|
+
import { VpcConstruct, AlbConstruct, EcsClusterConstruct } from '@dga-itc/aws-cdk-constructs';
|
|
64
|
+
|
|
65
|
+
export class MyInfraStack extends Stack {
|
|
66
|
+
constructor(scope: Construct, id: string, props?: StackProps) {
|
|
67
|
+
super(scope, id, props);
|
|
68
|
+
|
|
69
|
+
// Create VPC
|
|
70
|
+
const vpc = new VpcConstruct(this, 'MyVpc', {
|
|
71
|
+
vpcName: 'my-vpc',
|
|
72
|
+
cidr: '10.0.0.0/16',
|
|
73
|
+
maxAzs: 2,
|
|
74
|
+
natGateways: 1,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Create ALB
|
|
78
|
+
const alb = new AlbConstruct(this, 'MyAlb', {
|
|
79
|
+
albName: 'my-alb',
|
|
80
|
+
vpc: vpc.vpc,
|
|
81
|
+
internetFacing: true,
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Create ECS Cluster
|
|
85
|
+
const cluster = new EcsClusterConstruct(this, 'MyCluster', {
|
|
86
|
+
clusterName: 'my-cluster',
|
|
87
|
+
vpc: vpc.vpc,
|
|
88
|
+
containerInsights: true,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Terraform CDK Example
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
import { TerraformStack } from 'cdktf';
|
|
98
|
+
import { Construct } from 'constructs';
|
|
99
|
+
import {
|
|
100
|
+
EcsServiceConstruct,
|
|
101
|
+
AlbListenerRuleConstruct,
|
|
102
|
+
PriorityTracker
|
|
103
|
+
} from '@dga-itc/aws-cdk-constructs';
|
|
104
|
+
|
|
105
|
+
export class MyServiceStack extends TerraformStack {
|
|
106
|
+
constructor(scope: Construct, id: string) {
|
|
107
|
+
super(scope, id);
|
|
108
|
+
|
|
109
|
+
const priorityTracker = new PriorityTracker();
|
|
110
|
+
|
|
111
|
+
// Create ECS Service
|
|
112
|
+
const service = new EcsServiceConstruct(this, 'api-service', {
|
|
113
|
+
serviceName: 'api',
|
|
114
|
+
environment: 'prod',
|
|
115
|
+
region: 'us-east-1',
|
|
116
|
+
accountId: '123456789012',
|
|
117
|
+
vpcId: 'vpc-xxx',
|
|
118
|
+
privateSubnetIds: ['subnet-xxx', 'subnet-yyy'],
|
|
119
|
+
ecsClusterName: 'my-cluster',
|
|
120
|
+
ecsClusterArn: 'arn:aws:ecs:...',
|
|
121
|
+
containerImage: 'nginx:latest',
|
|
122
|
+
containerPort: 80,
|
|
123
|
+
cpu: 256,
|
|
124
|
+
memory: 512,
|
|
125
|
+
desiredCount: 2,
|
|
126
|
+
healthCheckPath: '/health',
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// Create ALB Listener Rule
|
|
130
|
+
const listenerRule = new AlbListenerRuleConstruct(this, 'api-rule', {
|
|
131
|
+
serviceName: 'api',
|
|
132
|
+
environment: 'prod',
|
|
133
|
+
listenerArn: 'arn:aws:elasticloadbalancing:...',
|
|
134
|
+
targetGroupArn: service.targetGroup.arn,
|
|
135
|
+
priority: priorityTracker.getNextPriority('api', '/api/*'),
|
|
136
|
+
pathPattern: '/api/*',
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
priorityTracker.printSummary();
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Available Constructs
|
|
145
|
+
|
|
146
|
+
### AWS CDK Constructs
|
|
147
|
+
|
|
148
|
+
| Construct | Description |
|
|
149
|
+
|-----------|-------------|
|
|
150
|
+
| `VpcConstruct` | VPC with public/private subnets |
|
|
151
|
+
| `AlbConstruct` | Application Load Balancer |
|
|
152
|
+
| `NlbConstruct` | Network Load Balancer |
|
|
153
|
+
| `EcsClusterConstruct` | ECS Cluster with capacity providers |
|
|
154
|
+
| `EcsServiceConstruct` | ECS Service (AWS CDK version) |
|
|
155
|
+
| `RdsConstruct` | RDS Database (PostgreSQL/MySQL) |
|
|
156
|
+
| `ElastiCacheConstruct` | Redis cluster |
|
|
157
|
+
| `EfsConstruct` | Elastic File System |
|
|
158
|
+
| `BastionConstruct` | Bastion host for SSH access |
|
|
159
|
+
| `NaclConstruct` | Network ACL rules |
|
|
160
|
+
| `EcrConstruct` | ECR repository |
|
|
161
|
+
|
|
162
|
+
### Terraform CDK Constructs
|
|
163
|
+
|
|
164
|
+
| Construct | Description |
|
|
165
|
+
|-----------|-------------|
|
|
166
|
+
| `EcsServiceConstruct` | ECS Fargate Service with auto-scaling |
|
|
167
|
+
| `AlbListenerRuleConstruct` | ALB Listener Rule with priority management |
|
|
168
|
+
| `PriorityTracker` | Utility for managing ALB rule priorities |
|
|
169
|
+
|
|
170
|
+
## Development
|
|
171
|
+
|
|
172
|
+
### Build
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
npm run build
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Test
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
npm test
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Publish
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
# To npmjs.org
|
|
188
|
+
npm publish
|
|
189
|
+
|
|
190
|
+
# To GitHub Packages
|
|
191
|
+
npm publish --registry=https://npm.pkg.github.com
|
|
192
|
+
|
|
193
|
+
# To AWS CodeArtifact
|
|
194
|
+
aws codeartifact login --tool npm --domain mycompany --repository npm-private
|
|
195
|
+
npm publish
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## Peer Dependencies
|
|
199
|
+
|
|
200
|
+
This package requires the following peer dependencies:
|
|
201
|
+
|
|
202
|
+
- `aws-cdk-lib`: ^2.0.0
|
|
203
|
+
- `constructs`: ^10.0.0
|
|
204
|
+
- `cdktf`: ^0.20.0
|
|
205
|
+
- `@cdktf/provider-aws`: ^19.0.0
|
|
206
|
+
|
|
207
|
+
Make sure these are installed in your project.
|
|
208
|
+
|
|
209
|
+
## License
|
|
210
|
+
|
|
211
|
+
MIT
|
|
212
|
+
|
|
213
|
+
## Contributing
|
|
214
|
+
|
|
215
|
+
Contributions are welcome! Please open an issue or submit a pull request.
|
|
216
|
+
|
|
217
|
+
## Support
|
|
218
|
+
|
|
219
|
+
For issues and questions, please open an issue on GitHub.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Construct } from 'constructs';
|
|
2
|
+
import * as acm from 'aws-cdk-lib/aws-certificatemanager';
|
|
3
|
+
import { AcmConfig } from '../interfaces/acm-config';
|
|
4
|
+
export interface AcmConstructProps {
|
|
5
|
+
config: AcmConfig;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* ACM Construct - สร้างหรือ import SSL/TLS Certificate
|
|
9
|
+
*
|
|
10
|
+
* Modes:
|
|
11
|
+
* - request: ขอ certificate ใหม่จาก ACM (DNS/Email validation)
|
|
12
|
+
* - import: นำเข้า certificate จาก PEM (ผ่าน SSM/Secrets Manager)
|
|
13
|
+
*/
|
|
14
|
+
export declare class AcmConstruct extends Construct {
|
|
15
|
+
readonly certificate: acm.ICertificate;
|
|
16
|
+
readonly certificateArn: string;
|
|
17
|
+
private readonly removalPolicy;
|
|
18
|
+
constructor(scope: Construct, id: string, props: AcmConstructProps);
|
|
19
|
+
private validateConfig;
|
|
20
|
+
private createRequestCertificate;
|
|
21
|
+
private createImportCertificate;
|
|
22
|
+
/**
|
|
23
|
+
* ถ้า param ขึ้นต้นด้วย 'arn:aws:secretsmanager:' → ดึงจาก Secrets Manager
|
|
24
|
+
* ถ้าไม่ → ดึงจาก SSM Parameter
|
|
25
|
+
*/
|
|
26
|
+
private resolvePrivateKey;
|
|
27
|
+
private createOutputs;
|
|
28
|
+
}
|
|
@@ -0,0 +1,239 @@
|
|
|
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.AcmConstruct = 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 acm = __importStar(require("aws-cdk-lib/aws-certificatemanager"));
|
|
41
|
+
const route53 = __importStar(require("aws-cdk-lib/aws-route53"));
|
|
42
|
+
const ssm = __importStar(require("aws-cdk-lib/aws-ssm"));
|
|
43
|
+
const secretsmanager = __importStar(require("aws-cdk-lib/aws-secretsmanager"));
|
|
44
|
+
const iam = __importStar(require("aws-cdk-lib/aws-iam"));
|
|
45
|
+
const cr = __importStar(require("aws-cdk-lib/custom-resources"));
|
|
46
|
+
/**
|
|
47
|
+
* ACM Construct - สร้างหรือ import SSL/TLS Certificate
|
|
48
|
+
*
|
|
49
|
+
* Modes:
|
|
50
|
+
* - request: ขอ certificate ใหม่จาก ACM (DNS/Email validation)
|
|
51
|
+
* - import: นำเข้า certificate จาก PEM (ผ่าน SSM/Secrets Manager)
|
|
52
|
+
*/
|
|
53
|
+
class AcmConstruct extends constructs_1.Construct {
|
|
54
|
+
constructor(scope, id, props) {
|
|
55
|
+
super(scope, id);
|
|
56
|
+
const { config } = props;
|
|
57
|
+
this.removalPolicy = config.removalPolicy === 'retain'
|
|
58
|
+
? aws_cdk_lib_1.RemovalPolicy.RETAIN
|
|
59
|
+
: aws_cdk_lib_1.RemovalPolicy.DESTROY;
|
|
60
|
+
// Validate config
|
|
61
|
+
this.validateConfig(config);
|
|
62
|
+
// Create or Import certificate based on mode
|
|
63
|
+
if (config.mode === 'request') {
|
|
64
|
+
this.certificate = this.createRequestCertificate(config);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
this.certificate = this.createImportCertificate(config);
|
|
68
|
+
}
|
|
69
|
+
this.certificateArn = this.certificate.certificateArn;
|
|
70
|
+
// Outputs
|
|
71
|
+
this.createOutputs(config);
|
|
72
|
+
}
|
|
73
|
+
// ==========================================
|
|
74
|
+
// Validation
|
|
75
|
+
// ==========================================
|
|
76
|
+
validateConfig(config) {
|
|
77
|
+
if (config.mode === 'request') {
|
|
78
|
+
if (!config.request) {
|
|
79
|
+
throw new Error(`ACM "${config.stackName}": mode is 'request' but 'request' config is not provided.`);
|
|
80
|
+
}
|
|
81
|
+
if (!config.request.domainName) {
|
|
82
|
+
throw new Error(`ACM "${config.stackName}": request mode requires 'domainName'.`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (config.mode === 'import') {
|
|
86
|
+
if (!config.import) {
|
|
87
|
+
throw new Error(`ACM "${config.stackName}": mode is 'import' but 'import' config is not provided.`);
|
|
88
|
+
}
|
|
89
|
+
if (!config.import.certificateBodyParam || !config.import.privateKeyParam) {
|
|
90
|
+
throw new Error(`ACM "${config.stackName}": import mode requires 'certificateBodyParam' and 'privateKeyParam'.`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// ==========================================
|
|
95
|
+
// Request Mode — ขอ certificate ใหม่จาก ACM
|
|
96
|
+
// ==========================================
|
|
97
|
+
createRequestCertificate(config) {
|
|
98
|
+
const requestConfig = config.request;
|
|
99
|
+
// Resolve validation method
|
|
100
|
+
let validation;
|
|
101
|
+
const validationMethod = requestConfig.validationMethod ?? 'DNS';
|
|
102
|
+
if (validationMethod === 'DNS' && requestConfig.hostedZoneId && requestConfig.hostedZoneName) {
|
|
103
|
+
// Auto DNS validation with Route53
|
|
104
|
+
const hostedZone = route53.HostedZone.fromHostedZoneAttributes(this, 'HostedZone', {
|
|
105
|
+
hostedZoneId: requestConfig.hostedZoneId,
|
|
106
|
+
zoneName: requestConfig.hostedZoneName,
|
|
107
|
+
});
|
|
108
|
+
validation = acm.CertificateValidation.fromDns(hostedZone);
|
|
109
|
+
}
|
|
110
|
+
else if (validationMethod === 'DNS') {
|
|
111
|
+
// DNS validation without auto-creation (manual DNS record)
|
|
112
|
+
validation = acm.CertificateValidation.fromDns();
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
// Email validation
|
|
116
|
+
validation = acm.CertificateValidation.fromEmail();
|
|
117
|
+
}
|
|
118
|
+
// Resolve key algorithm
|
|
119
|
+
let keyAlgorithm;
|
|
120
|
+
if (requestConfig.keyAlgorithm) {
|
|
121
|
+
switch (requestConfig.keyAlgorithm) {
|
|
122
|
+
case 'RSA_2048':
|
|
123
|
+
keyAlgorithm = acm.KeyAlgorithm.RSA_2048;
|
|
124
|
+
break;
|
|
125
|
+
case 'EC_prime256v1':
|
|
126
|
+
keyAlgorithm = acm.KeyAlgorithm.EC_PRIME256V1;
|
|
127
|
+
break;
|
|
128
|
+
case 'EC_secp384r1':
|
|
129
|
+
keyAlgorithm = acm.KeyAlgorithm.EC_SECP384R1;
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
const cert = new acm.Certificate(this, 'Certificate', {
|
|
134
|
+
domainName: requestConfig.domainName,
|
|
135
|
+
subjectAlternativeNames: requestConfig.subjectAlternativeNames,
|
|
136
|
+
validation,
|
|
137
|
+
keyAlgorithm,
|
|
138
|
+
transparencyLoggingEnabled: requestConfig.transparencyLoggingEnabled ?? true,
|
|
139
|
+
});
|
|
140
|
+
cert.applyRemovalPolicy(this.removalPolicy);
|
|
141
|
+
return cert;
|
|
142
|
+
}
|
|
143
|
+
// ==========================================
|
|
144
|
+
// Import Mode — นำเข้า certificate จาก PEM
|
|
145
|
+
// ==========================================
|
|
146
|
+
createImportCertificate(config) {
|
|
147
|
+
const importConfig = config.import;
|
|
148
|
+
// ใช้ AwsCustomResource เพราะ CloudFormation ไม่มี native import certificate
|
|
149
|
+
// Custom Resource จะเรียก ACM ImportCertificate API โดยตรง
|
|
150
|
+
const importParams = {
|
|
151
|
+
'Certificate': ssm.StringParameter.valueForStringParameter(this, importConfig.certificateBodyParam),
|
|
152
|
+
'PrivateKey': this.resolvePrivateKey(importConfig.privateKeyParam),
|
|
153
|
+
};
|
|
154
|
+
if (importConfig.certificateChainParam) {
|
|
155
|
+
importParams['CertificateChain'] = ssm.StringParameter.valueForStringParameter(this, importConfig.certificateChainParam);
|
|
156
|
+
}
|
|
157
|
+
const importCert = new cr.AwsCustomResource(this, 'ImportCertificate', {
|
|
158
|
+
onCreate: {
|
|
159
|
+
service: 'ACM',
|
|
160
|
+
action: 'importCertificate',
|
|
161
|
+
parameters: importParams,
|
|
162
|
+
physicalResourceId: cr.PhysicalResourceId.fromResponse('CertificateArn'),
|
|
163
|
+
},
|
|
164
|
+
onUpdate: {
|
|
165
|
+
service: 'ACM',
|
|
166
|
+
action: 'importCertificate',
|
|
167
|
+
parameters: importParams,
|
|
168
|
+
physicalResourceId: cr.PhysicalResourceId.fromResponse('CertificateArn'),
|
|
169
|
+
},
|
|
170
|
+
onDelete: {
|
|
171
|
+
service: 'ACM',
|
|
172
|
+
action: 'deleteCertificate',
|
|
173
|
+
parameters: {
|
|
174
|
+
CertificateArn: new cr.PhysicalResourceIdReference(),
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
policy: cr.AwsCustomResourcePolicy.fromStatements([
|
|
178
|
+
new iam.PolicyStatement({
|
|
179
|
+
actions: [
|
|
180
|
+
'acm:ImportCertificate',
|
|
181
|
+
'acm:DeleteCertificate',
|
|
182
|
+
'acm:DescribeCertificate',
|
|
183
|
+
],
|
|
184
|
+
resources: ['*'],
|
|
185
|
+
}),
|
|
186
|
+
new iam.PolicyStatement({
|
|
187
|
+
actions: [
|
|
188
|
+
'ssm:GetParameter',
|
|
189
|
+
],
|
|
190
|
+
resources: ['*'],
|
|
191
|
+
}),
|
|
192
|
+
new iam.PolicyStatement({
|
|
193
|
+
actions: [
|
|
194
|
+
'secretsmanager:GetSecretValue',
|
|
195
|
+
],
|
|
196
|
+
resources: ['*'],
|
|
197
|
+
}),
|
|
198
|
+
]),
|
|
199
|
+
});
|
|
200
|
+
const certArn = importCert.getResponseField('CertificateArn');
|
|
201
|
+
return acm.Certificate.fromCertificateArn(this, 'ImportedCertificateRef', certArn);
|
|
202
|
+
}
|
|
203
|
+
// ==========================================
|
|
204
|
+
// Helper: Resolve Private Key
|
|
205
|
+
// ==========================================
|
|
206
|
+
/**
|
|
207
|
+
* ถ้า param ขึ้นต้นด้วย 'arn:aws:secretsmanager:' → ดึงจาก Secrets Manager
|
|
208
|
+
* ถ้าไม่ → ดึงจาก SSM Parameter
|
|
209
|
+
*/
|
|
210
|
+
resolvePrivateKey(param) {
|
|
211
|
+
if (param.startsWith('arn:aws:secretsmanager:')) {
|
|
212
|
+
const secret = secretsmanager.Secret.fromSecretCompleteArn(this, 'PrivateKeySecret', param);
|
|
213
|
+
return secret.secretValue.unsafeUnwrap();
|
|
214
|
+
}
|
|
215
|
+
return ssm.StringParameter.valueForStringParameter(this, param);
|
|
216
|
+
}
|
|
217
|
+
// ==========================================
|
|
218
|
+
// Outputs
|
|
219
|
+
// ==========================================
|
|
220
|
+
createOutputs(config) {
|
|
221
|
+
if (config.enableExport === false)
|
|
222
|
+
return;
|
|
223
|
+
const stack = cdk.Stack.of(this);
|
|
224
|
+
const prefix = config.stackName;
|
|
225
|
+
new cdk.CfnOutput(stack, 'AcmCertificateArn', {
|
|
226
|
+
value: this.certificateArn,
|
|
227
|
+
description: `ACM Certificate ARN (${config.mode} mode)`,
|
|
228
|
+
exportName: `${prefix}-ACM-CertificateArn`,
|
|
229
|
+
});
|
|
230
|
+
if (config.mode === 'request' && config.request) {
|
|
231
|
+
new cdk.CfnOutput(stack, 'AcmDomainName', {
|
|
232
|
+
value: config.request.domainName,
|
|
233
|
+
description: 'ACM Certificate Domain Name',
|
|
234
|
+
exportName: `${prefix}-ACM-DomainName`,
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
exports.AcmConstruct = AcmConstruct;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Construct } from 'constructs';
|
|
2
|
+
import * as ec2 from 'aws-cdk-lib/aws-ec2';
|
|
3
|
+
import * as elbv2 from 'aws-cdk-lib/aws-elasticloadbalancingv2';
|
|
4
|
+
import { AlbConfig } from '../interfaces/alb-config';
|
|
5
|
+
import { VpcConstruct } from './vpc';
|
|
6
|
+
export interface AlbConstructProps {
|
|
7
|
+
config: AlbConfig;
|
|
8
|
+
/** VpcConstruct from NetworkStack */
|
|
9
|
+
vpcConstruct: VpcConstruct;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* ALB Construct - สร้าง ALB + Security Group + Listeners
|
|
13
|
+
*
|
|
14
|
+
* อ้างอิง VpcConstruct จาก NetworkStack เพื่อดึง VPC + Subnets
|
|
15
|
+
*/
|
|
16
|
+
export declare class AlbConstruct extends Construct {
|
|
17
|
+
readonly alb: elbv2.ApplicationLoadBalancer;
|
|
18
|
+
readonly securityGroup: ec2.SecurityGroup;
|
|
19
|
+
readonly httpListener?: elbv2.ApplicationListener;
|
|
20
|
+
readonly httpsListener?: elbv2.ApplicationListener;
|
|
21
|
+
private readonly removalPolicy;
|
|
22
|
+
constructor(scope: Construct, id: string, props: AlbConstructProps);
|
|
23
|
+
private resolveVpc;
|
|
24
|
+
private createSecurityGroup;
|
|
25
|
+
private createAlb;
|
|
26
|
+
private createListeners;
|
|
27
|
+
private createOutputs;
|
|
28
|
+
}
|