@stacksjs/ts-cloud-core 0.1.1
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/LICENSE.md +21 -0
- package/README.md +321 -0
- package/package.json +31 -0
- package/src/advanced-features.test.ts +465 -0
- package/src/aws/cloudformation.ts +421 -0
- package/src/aws/cloudfront.ts +158 -0
- package/src/aws/credentials.test.ts +132 -0
- package/src/aws/credentials.ts +545 -0
- package/src/aws/index.ts +87 -0
- package/src/aws/s3.test.ts +188 -0
- package/src/aws/s3.ts +1088 -0
- package/src/aws/signature.test.ts +670 -0
- package/src/aws/signature.ts +1155 -0
- package/src/backup/disaster-recovery.test.ts +726 -0
- package/src/backup/disaster-recovery.ts +500 -0
- package/src/backup/index.ts +34 -0
- package/src/backup/manager.test.ts +498 -0
- package/src/backup/manager.ts +432 -0
- package/src/cicd/circleci.ts +430 -0
- package/src/cicd/github-actions.ts +424 -0
- package/src/cicd/gitlab-ci.ts +255 -0
- package/src/cicd/index.ts +8 -0
- package/src/cli/history.ts +396 -0
- package/src/cli/index.ts +10 -0
- package/src/cli/progress.ts +458 -0
- package/src/cli/repl.ts +454 -0
- package/src/cli/suggestions.ts +327 -0
- package/src/cli/table.test.ts +319 -0
- package/src/cli/table.ts +332 -0
- package/src/cloudformation/builder.test.ts +327 -0
- package/src/cloudformation/builder.ts +378 -0
- package/src/cloudformation/builders/api-gateway.ts +449 -0
- package/src/cloudformation/builders/cache.ts +334 -0
- package/src/cloudformation/builders/cdn.ts +278 -0
- package/src/cloudformation/builders/compute.ts +485 -0
- package/src/cloudformation/builders/database.ts +392 -0
- package/src/cloudformation/builders/functions.ts +343 -0
- package/src/cloudformation/builders/messaging.ts +140 -0
- package/src/cloudformation/builders/monitoring.ts +300 -0
- package/src/cloudformation/builders/network.ts +264 -0
- package/src/cloudformation/builders/queue.ts +147 -0
- package/src/cloudformation/builders/security.ts +399 -0
- package/src/cloudformation/builders/storage.ts +285 -0
- package/src/cloudformation/index.ts +30 -0
- package/src/cloudformation/types.ts +173 -0
- package/src/compliance/aws-config.ts +543 -0
- package/src/compliance/cloudtrail.ts +376 -0
- package/src/compliance/compliance.test.ts +423 -0
- package/src/compliance/guardduty.ts +446 -0
- package/src/compliance/index.ts +66 -0
- package/src/compliance/security-hub.ts +456 -0
- package/src/containers/build-optimization.ts +416 -0
- package/src/containers/containers.test.ts +508 -0
- package/src/containers/image-scanning.ts +360 -0
- package/src/containers/index.ts +9 -0
- package/src/containers/registry.ts +293 -0
- package/src/containers/service-mesh.ts +520 -0
- package/src/database/database.test.ts +762 -0
- package/src/database/index.ts +9 -0
- package/src/database/migrations.ts +444 -0
- package/src/database/performance.ts +528 -0
- package/src/database/replicas.ts +534 -0
- package/src/database/users.ts +494 -0
- package/src/dependency-graph.ts +143 -0
- package/src/deployment/ab-testing.ts +582 -0
- package/src/deployment/blue-green.ts +452 -0
- package/src/deployment/canary.ts +500 -0
- package/src/deployment/deployment.test.ts +526 -0
- package/src/deployment/index.ts +61 -0
- package/src/deployment/progressive.ts +62 -0
- package/src/dns/dns.test.ts +641 -0
- package/src/dns/dnssec.ts +315 -0
- package/src/dns/index.ts +8 -0
- package/src/dns/resolver.ts +496 -0
- package/src/dns/routing.ts +593 -0
- package/src/email/advanced/analytics.ts +445 -0
- package/src/email/advanced/index.ts +11 -0
- package/src/email/advanced/rules.ts +465 -0
- package/src/email/advanced/scheduling.ts +352 -0
- package/src/email/advanced/search.ts +412 -0
- package/src/email/advanced/shared-mailboxes.ts +404 -0
- package/src/email/advanced/templates.ts +455 -0
- package/src/email/advanced/threading.ts +281 -0
- package/src/email/analytics.ts +467 -0
- package/src/email/bounce-handling.ts +425 -0
- package/src/email/email.test.ts +431 -0
- package/src/email/handlers/__tests__/inbound.test.ts +38 -0
- package/src/email/handlers/__tests__/outbound.test.ts +37 -0
- package/src/email/handlers/converter.ts +227 -0
- package/src/email/handlers/feedback.ts +228 -0
- package/src/email/handlers/inbound.ts +169 -0
- package/src/email/handlers/outbound.ts +178 -0
- package/src/email/index.ts +15 -0
- package/src/email/reputation.ts +303 -0
- package/src/email/templates.ts +352 -0
- package/src/errors/index.test.ts +434 -0
- package/src/errors/index.ts +416 -0
- package/src/health-checks/index.ts +40 -0
- package/src/index.ts +360 -0
- package/src/intrinsic-functions.ts +118 -0
- package/src/lambda/concurrency.ts +330 -0
- package/src/lambda/destinations.ts +345 -0
- package/src/lambda/dlq.ts +425 -0
- package/src/lambda/index.ts +11 -0
- package/src/lambda/lambda.test.ts +840 -0
- package/src/lambda/layers.ts +263 -0
- package/src/lambda/versions.ts +376 -0
- package/src/lambda/vpc.ts +399 -0
- package/src/local/config.ts +114 -0
- package/src/local/index.ts +6 -0
- package/src/local/mock-aws.ts +351 -0
- package/src/modules/ai.ts +340 -0
- package/src/modules/api.ts +478 -0
- package/src/modules/auth.ts +805 -0
- package/src/modules/cache.ts +417 -0
- package/src/modules/cdn.ts +1062 -0
- package/src/modules/communication.ts +1094 -0
- package/src/modules/compute.ts +3348 -0
- package/src/modules/database.ts +554 -0
- package/src/modules/deployment.ts +1079 -0
- package/src/modules/dns.ts +337 -0
- package/src/modules/email.ts +1538 -0
- package/src/modules/filesystem.ts +515 -0
- package/src/modules/index.ts +32 -0
- package/src/modules/messaging.ts +486 -0
- package/src/modules/monitoring.ts +2086 -0
- package/src/modules/network.ts +664 -0
- package/src/modules/parameter-store.ts +325 -0
- package/src/modules/permissions.ts +1081 -0
- package/src/modules/phone.ts +494 -0
- package/src/modules/queue.ts +1260 -0
- package/src/modules/redirects.ts +464 -0
- package/src/modules/registry.ts +699 -0
- package/src/modules/search.ts +401 -0
- package/src/modules/secrets.ts +416 -0
- package/src/modules/security.ts +731 -0
- package/src/modules/sms.ts +389 -0
- package/src/modules/storage.ts +1120 -0
- package/src/modules/workflow.ts +680 -0
- package/src/multi-account/config.ts +521 -0
- package/src/multi-account/index.ts +7 -0
- package/src/multi-account/manager.ts +427 -0
- package/src/multi-region/cross-region.ts +410 -0
- package/src/multi-region/index.ts +8 -0
- package/src/multi-region/manager.ts +483 -0
- package/src/multi-region/regions.ts +435 -0
- package/src/network-security/index.ts +48 -0
- package/src/observability/index.ts +9 -0
- package/src/observability/logs.ts +522 -0
- package/src/observability/metrics.ts +460 -0
- package/src/observability/observability.test.ts +782 -0
- package/src/observability/synthetics.ts +568 -0
- package/src/observability/xray.ts +358 -0
- package/src/phone/advanced/analytics.ts +349 -0
- package/src/phone/advanced/callbacks.ts +428 -0
- package/src/phone/advanced/index.ts +8 -0
- package/src/phone/advanced/ivr-builder.ts +504 -0
- package/src/phone/advanced/recording.ts +310 -0
- package/src/phone/handlers/__tests__/incoming-call.test.ts +40 -0
- package/src/phone/handlers/incoming-call.ts +117 -0
- package/src/phone/handlers/missed-call.ts +116 -0
- package/src/phone/handlers/voicemail.ts +179 -0
- package/src/phone/index.ts +9 -0
- package/src/presets/api-backend.ts +134 -0
- package/src/presets/data-pipeline.ts +204 -0
- package/src/presets/extend.test.ts +295 -0
- package/src/presets/extend.ts +297 -0
- package/src/presets/fullstack-app.ts +144 -0
- package/src/presets/index.ts +27 -0
- package/src/presets/jamstack.ts +135 -0
- package/src/presets/microservices.ts +167 -0
- package/src/presets/ml-api.ts +208 -0
- package/src/presets/nodejs-server.ts +104 -0
- package/src/presets/nodejs-serverless.ts +114 -0
- package/src/presets/realtime-app.ts +184 -0
- package/src/presets/static-site.ts +64 -0
- package/src/presets/traditional-web-app.ts +339 -0
- package/src/presets/wordpress.ts +138 -0
- package/src/preview/github.test.ts +249 -0
- package/src/preview/github.ts +297 -0
- package/src/preview/index.ts +37 -0
- package/src/preview/manager.test.ts +440 -0
- package/src/preview/manager.ts +326 -0
- package/src/preview/notifications.test.ts +582 -0
- package/src/preview/notifications.ts +341 -0
- package/src/queue/batch-processing.ts +402 -0
- package/src/queue/dlq-monitoring.ts +402 -0
- package/src/queue/fifo.ts +342 -0
- package/src/queue/index.ts +9 -0
- package/src/queue/management.ts +428 -0
- package/src/queue/queue.test.ts +429 -0
- package/src/resource-mgmt/index.ts +39 -0
- package/src/resource-naming.ts +62 -0
- package/src/s3/index.ts +523 -0
- package/src/schema/cloud-config.schema.json +554 -0
- package/src/schema/index.ts +68 -0
- package/src/security/certificate-manager.ts +492 -0
- package/src/security/index.ts +9 -0
- package/src/security/scanning.ts +545 -0
- package/src/security/secrets-manager.ts +476 -0
- package/src/security/secrets-rotation.ts +456 -0
- package/src/security/security.test.ts +738 -0
- package/src/sms/advanced/ab-testing.ts +389 -0
- package/src/sms/advanced/analytics.ts +336 -0
- package/src/sms/advanced/campaigns.ts +523 -0
- package/src/sms/advanced/chatbot.ts +224 -0
- package/src/sms/advanced/index.ts +10 -0
- package/src/sms/advanced/link-tracking.ts +248 -0
- package/src/sms/advanced/mms.ts +308 -0
- package/src/sms/handlers/__tests__/send.test.ts +40 -0
- package/src/sms/handlers/delivery-status.ts +133 -0
- package/src/sms/handlers/receive.ts +162 -0
- package/src/sms/handlers/send.ts +174 -0
- package/src/sms/index.ts +9 -0
- package/src/stack-diff.ts +389 -0
- package/src/static-site/index.ts +85 -0
- package/src/template-builder.ts +110 -0
- package/src/template-validator.ts +574 -0
- package/src/utils/cache.ts +291 -0
- package/src/utils/diff.ts +269 -0
- package/src/utils/hash.ts +227 -0
- package/src/utils/index.ts +8 -0
- package/src/utils/parallel.ts +294 -0
- package/src/validators/credentials.test.ts +274 -0
- package/src/validators/credentials.ts +233 -0
- package/src/validators/quotas.test.ts +434 -0
- package/src/validators/quotas.ts +217 -0
- package/test/ai.test.ts +327 -0
- package/test/api.test.ts +511 -0
- package/test/auth.test.ts +632 -0
- package/test/cache.test.ts +406 -0
- package/test/cdn.test.ts +247 -0
- package/test/compute.test.ts +861 -0
- package/test/database.test.ts +523 -0
- package/test/deployment.test.ts +499 -0
- package/test/dns.test.ts +270 -0
- package/test/email.test.ts +439 -0
- package/test/filesystem.test.ts +382 -0
- package/test/integration.test.ts +350 -0
- package/test/messaging.test.ts +514 -0
- package/test/monitoring.test.ts +634 -0
- package/test/network.test.ts +425 -0
- package/test/permissions.test.ts +488 -0
- package/test/queue.test.ts +484 -0
- package/test/registry.test.ts +306 -0
- package/test/security.test.ts +462 -0
- package/test/storage.test.ts +463 -0
- package/test/template-validator.test.ts +559 -0
- package/test/workflow.test.ts +592 -0
- package/tsconfig.json +16 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,492 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Certificate Lifecycle Management
|
|
3
|
+
* Automated certificate provisioning, renewal, and monitoring
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface Certificate {
|
|
7
|
+
id: string
|
|
8
|
+
arn: string
|
|
9
|
+
domainName: string
|
|
10
|
+
subjectAlternativeNames?: string[]
|
|
11
|
+
validationMethod: 'DNS' | 'EMAIL'
|
|
12
|
+
status: CertificateStatus
|
|
13
|
+
issuer?: string
|
|
14
|
+
issuedAt?: Date
|
|
15
|
+
expiresAt?: Date
|
|
16
|
+
renewalEligibility?: boolean
|
|
17
|
+
inUseBy?: string[] // Resource ARNs
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type CertificateStatus =
|
|
21
|
+
| 'PENDING_VALIDATION'
|
|
22
|
+
| 'ISSUED'
|
|
23
|
+
| 'INACTIVE'
|
|
24
|
+
| 'EXPIRED'
|
|
25
|
+
| 'VALIDATION_TIMED_OUT'
|
|
26
|
+
| 'REVOKED'
|
|
27
|
+
| 'FAILED'
|
|
28
|
+
|
|
29
|
+
export interface CertificateRenewal {
|
|
30
|
+
id: string
|
|
31
|
+
certificateArn: string
|
|
32
|
+
autoRenew: boolean
|
|
33
|
+
renewBeforeDays: number // Renew X days before expiration
|
|
34
|
+
lastRenewal?: Date
|
|
35
|
+
nextRenewal?: Date
|
|
36
|
+
renewalStatus?: 'success' | 'pending' | 'failed'
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface CertificateValidation {
|
|
40
|
+
domainName: string
|
|
41
|
+
validationMethod: 'DNS' | 'EMAIL'
|
|
42
|
+
validationStatus: 'PENDING' | 'SUCCESS' | 'FAILED'
|
|
43
|
+
resourceRecords?: DnsRecord[]
|
|
44
|
+
validationEmails?: string[]
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface DnsRecord {
|
|
48
|
+
name: string
|
|
49
|
+
type: 'CNAME' | 'A' | 'AAAA' | 'TXT'
|
|
50
|
+
value: string
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface CertificateMonitor {
|
|
54
|
+
id: string
|
|
55
|
+
name: string
|
|
56
|
+
certificates: string[] // Certificate ARNs
|
|
57
|
+
expirationThreshold: number // days
|
|
58
|
+
alertEnabled: boolean
|
|
59
|
+
snsTopicArn?: string
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface CertificateAlert {
|
|
63
|
+
id: string
|
|
64
|
+
certificateArn: string
|
|
65
|
+
alertType: 'expiring_soon' | 'expired' | 'renewal_failed' | 'validation_failed'
|
|
66
|
+
severity: 'critical' | 'warning' | 'info'
|
|
67
|
+
message: string
|
|
68
|
+
timestamp: Date
|
|
69
|
+
acknowledged?: boolean
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Certificate manager
|
|
74
|
+
*/
|
|
75
|
+
export class CertificateManager {
|
|
76
|
+
private certificates: Map<string, Certificate> = new Map()
|
|
77
|
+
private renewals: Map<string, CertificateRenewal> = new Map()
|
|
78
|
+
private validations: Map<string, CertificateValidation> = new Map()
|
|
79
|
+
private monitors: Map<string, CertificateMonitor> = new Map()
|
|
80
|
+
private alerts: Map<string, CertificateAlert> = new Map()
|
|
81
|
+
private certificateCounter = 0
|
|
82
|
+
private renewalCounter = 0
|
|
83
|
+
private validationCounter = 0
|
|
84
|
+
private monitorCounter = 0
|
|
85
|
+
private alertCounter = 0
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Request certificate
|
|
89
|
+
*/
|
|
90
|
+
requestCertificate(options: {
|
|
91
|
+
domainName: string
|
|
92
|
+
subjectAlternativeNames?: string[]
|
|
93
|
+
validationMethod?: 'DNS' | 'EMAIL'
|
|
94
|
+
}): Certificate {
|
|
95
|
+
const id = `cert-${Date.now()}-${this.certificateCounter++}`
|
|
96
|
+
const arn = `arn:aws:acm:us-east-1:123456789012:certificate/${id}`
|
|
97
|
+
|
|
98
|
+
const certificate: Certificate = {
|
|
99
|
+
id,
|
|
100
|
+
arn,
|
|
101
|
+
domainName: options.domainName,
|
|
102
|
+
subjectAlternativeNames: options.subjectAlternativeNames,
|
|
103
|
+
validationMethod: options.validationMethod || 'DNS',
|
|
104
|
+
status: 'PENDING_VALIDATION',
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
this.certificates.set(id, certificate)
|
|
108
|
+
|
|
109
|
+
// Create validation record
|
|
110
|
+
this.createValidation(certificate)
|
|
111
|
+
|
|
112
|
+
return certificate
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Request wildcard certificate
|
|
117
|
+
*/
|
|
118
|
+
requestWildcardCertificate(options: {
|
|
119
|
+
domainName: string
|
|
120
|
+
includeApex?: boolean
|
|
121
|
+
}): Certificate {
|
|
122
|
+
const sans: string[] = []
|
|
123
|
+
|
|
124
|
+
if (options.includeApex) {
|
|
125
|
+
sans.push(options.domainName.replace('*.', ''))
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return this.requestCertificate({
|
|
129
|
+
domainName: options.domainName,
|
|
130
|
+
subjectAlternativeNames: sans.length > 0 ? sans : undefined,
|
|
131
|
+
validationMethod: 'DNS',
|
|
132
|
+
})
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Request multi-domain certificate
|
|
137
|
+
*/
|
|
138
|
+
requestMultiDomainCertificate(options: {
|
|
139
|
+
primaryDomain: string
|
|
140
|
+
additionalDomains: string[]
|
|
141
|
+
validationMethod?: 'DNS' | 'EMAIL'
|
|
142
|
+
}): Certificate {
|
|
143
|
+
return this.requestCertificate({
|
|
144
|
+
domainName: options.primaryDomain,
|
|
145
|
+
subjectAlternativeNames: options.additionalDomains,
|
|
146
|
+
validationMethod: options.validationMethod || 'DNS',
|
|
147
|
+
})
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Create certificate validation
|
|
152
|
+
*/
|
|
153
|
+
private createValidation(certificate: Certificate): CertificateValidation {
|
|
154
|
+
const validation: CertificateValidation = {
|
|
155
|
+
domainName: certificate.domainName,
|
|
156
|
+
validationMethod: certificate.validationMethod,
|
|
157
|
+
validationStatus: 'PENDING',
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (certificate.validationMethod === 'DNS') {
|
|
161
|
+
validation.resourceRecords = [
|
|
162
|
+
{
|
|
163
|
+
name: `_${Math.random().toString(36).slice(2)}.${certificate.domainName}`,
|
|
164
|
+
type: 'CNAME',
|
|
165
|
+
value: `_${Math.random().toString(36).slice(2)}.acm-validations.aws.`,
|
|
166
|
+
},
|
|
167
|
+
]
|
|
168
|
+
} else {
|
|
169
|
+
validation.validationEmails = [
|
|
170
|
+
`admin@${certificate.domainName}`,
|
|
171
|
+
`administrator@${certificate.domainName}`,
|
|
172
|
+
`hostmaster@${certificate.domainName}`,
|
|
173
|
+
]
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
this.validations.set(certificate.id, validation)
|
|
177
|
+
|
|
178
|
+
return validation
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Validate certificate
|
|
183
|
+
*/
|
|
184
|
+
validateCertificate(certificateId: string): { success: boolean; message: string } {
|
|
185
|
+
const certificate = this.certificates.get(certificateId)
|
|
186
|
+
const validation = this.validations.get(certificateId)
|
|
187
|
+
|
|
188
|
+
if (!certificate || !validation) {
|
|
189
|
+
return { success: false, message: 'Certificate or validation not found' }
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Simulate validation
|
|
193
|
+
validation.validationStatus = 'SUCCESS'
|
|
194
|
+
certificate.status = 'ISSUED'
|
|
195
|
+
certificate.issuedAt = new Date()
|
|
196
|
+
certificate.expiresAt = new Date(Date.now() + 365 * 24 * 60 * 60 * 1000) // 1 year
|
|
197
|
+
certificate.renewalEligibility = true
|
|
198
|
+
certificate.issuer = 'Amazon'
|
|
199
|
+
|
|
200
|
+
return { success: true, message: 'Certificate validated and issued successfully' }
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Enable auto-renewal
|
|
205
|
+
*/
|
|
206
|
+
enableAutoRenewal(options: {
|
|
207
|
+
certificateArn: string
|
|
208
|
+
renewBeforeDays?: number
|
|
209
|
+
}): CertificateRenewal {
|
|
210
|
+
const id = `renewal-${Date.now()}-${this.renewalCounter++}`
|
|
211
|
+
|
|
212
|
+
const renewal: CertificateRenewal = {
|
|
213
|
+
id,
|
|
214
|
+
certificateArn: options.certificateArn,
|
|
215
|
+
autoRenew: true,
|
|
216
|
+
renewBeforeDays: options.renewBeforeDays || 30,
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
this.renewals.set(id, renewal)
|
|
220
|
+
|
|
221
|
+
return renewal
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Renew certificate
|
|
226
|
+
*/
|
|
227
|
+
async renewCertificate(renewalId: string): Promise<{ success: boolean; message: string }> {
|
|
228
|
+
const renewal = this.renewals.get(renewalId)
|
|
229
|
+
|
|
230
|
+
if (!renewal) {
|
|
231
|
+
return { success: false, message: 'Renewal configuration not found' }
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const certificate = Array.from(this.certificates.values()).find(
|
|
235
|
+
c => c.arn === renewal.certificateArn
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
if (!certificate) {
|
|
239
|
+
return { success: false, message: 'Certificate not found' }
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
console.log(`\nRenewing certificate: ${certificate.domainName}`)
|
|
243
|
+
console.log(`Certificate ARN: ${certificate.arn}`)
|
|
244
|
+
|
|
245
|
+
try {
|
|
246
|
+
console.log('\n1. Requesting new certificate...')
|
|
247
|
+
console.log('2. Validating domain ownership...')
|
|
248
|
+
console.log('3. Issuing renewed certificate...')
|
|
249
|
+
console.log('4. Updating resource associations...')
|
|
250
|
+
|
|
251
|
+
// Update certificate
|
|
252
|
+
certificate.issuedAt = new Date()
|
|
253
|
+
certificate.expiresAt = new Date(Date.now() + 365 * 24 * 60 * 60 * 1000)
|
|
254
|
+
|
|
255
|
+
// Update renewal record
|
|
256
|
+
renewal.lastRenewal = new Date()
|
|
257
|
+
renewal.renewalStatus = 'success'
|
|
258
|
+
renewal.nextRenewal = new Date(
|
|
259
|
+
certificate.expiresAt.getTime() - renewal.renewBeforeDays * 24 * 60 * 60 * 1000
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
console.log('\n✓ Certificate renewed successfully')
|
|
263
|
+
console.log(` New expiration: ${certificate.expiresAt.toISOString()}`)
|
|
264
|
+
console.log(` Next renewal: ${renewal.nextRenewal.toISOString()}`)
|
|
265
|
+
|
|
266
|
+
return { success: true, message: 'Certificate renewed successfully' }
|
|
267
|
+
} catch (error) {
|
|
268
|
+
renewal.renewalStatus = 'failed'
|
|
269
|
+
this.createAlert({
|
|
270
|
+
certificateArn: certificate.arn,
|
|
271
|
+
alertType: 'renewal_failed',
|
|
272
|
+
severity: 'critical',
|
|
273
|
+
message: `Certificate renewal failed: ${error}`,
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
return {
|
|
277
|
+
success: false,
|
|
278
|
+
message: error instanceof Error ? error.message : String(error),
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Create certificate monitor
|
|
285
|
+
*/
|
|
286
|
+
createMonitor(monitor: Omit<CertificateMonitor, 'id'>): CertificateMonitor {
|
|
287
|
+
const id = `monitor-${Date.now()}-${this.monitorCounter++}`
|
|
288
|
+
|
|
289
|
+
const certificateMonitor: CertificateMonitor = {
|
|
290
|
+
id,
|
|
291
|
+
...monitor,
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
this.monitors.set(id, certificateMonitor)
|
|
295
|
+
|
|
296
|
+
return certificateMonitor
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Check certificate expiration
|
|
301
|
+
*/
|
|
302
|
+
checkExpiration(): CertificateAlert[] {
|
|
303
|
+
const alerts: CertificateAlert[] = []
|
|
304
|
+
const now = Date.now()
|
|
305
|
+
|
|
306
|
+
for (const certificate of this.certificates.values()) {
|
|
307
|
+
if (!certificate.expiresAt) continue
|
|
308
|
+
|
|
309
|
+
const daysUntilExpiration =
|
|
310
|
+
(certificate.expiresAt.getTime() - now) / (1000 * 60 * 60 * 24)
|
|
311
|
+
|
|
312
|
+
// Check if expired
|
|
313
|
+
if (daysUntilExpiration < 0) {
|
|
314
|
+
alerts.push(
|
|
315
|
+
this.createAlert({
|
|
316
|
+
certificateArn: certificate.arn,
|
|
317
|
+
alertType: 'expired',
|
|
318
|
+
severity: 'critical',
|
|
319
|
+
message: `Certificate has expired for ${certificate.domainName}`,
|
|
320
|
+
})
|
|
321
|
+
)
|
|
322
|
+
}
|
|
323
|
+
// Check if expiring soon (within 30 days)
|
|
324
|
+
else if (daysUntilExpiration < 30) {
|
|
325
|
+
alerts.push(
|
|
326
|
+
this.createAlert({
|
|
327
|
+
certificateArn: certificate.arn,
|
|
328
|
+
alertType: 'expiring_soon',
|
|
329
|
+
severity: daysUntilExpiration < 7 ? 'critical' : 'warning',
|
|
330
|
+
message: `Certificate expiring in ${Math.floor(daysUntilExpiration)} days for ${certificate.domainName}`,
|
|
331
|
+
})
|
|
332
|
+
)
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
return alerts
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Create alert
|
|
341
|
+
*/
|
|
342
|
+
createAlert(alert: Omit<CertificateAlert, 'id' | 'timestamp' | 'acknowledged'>): CertificateAlert {
|
|
343
|
+
const id = `alert-${Date.now()}-${this.alertCounter++}`
|
|
344
|
+
|
|
345
|
+
const certificateAlert: CertificateAlert = {
|
|
346
|
+
id,
|
|
347
|
+
timestamp: new Date(),
|
|
348
|
+
acknowledged: false,
|
|
349
|
+
...alert,
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
this.alerts.set(id, certificateAlert)
|
|
353
|
+
|
|
354
|
+
return certificateAlert
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Acknowledge alert
|
|
359
|
+
*/
|
|
360
|
+
acknowledgeAlert(alertId: string): void {
|
|
361
|
+
const alert = this.alerts.get(alertId)
|
|
362
|
+
if (alert) {
|
|
363
|
+
alert.acknowledged = true
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Get certificate
|
|
369
|
+
*/
|
|
370
|
+
getCertificate(id: string): Certificate | undefined {
|
|
371
|
+
return this.certificates.get(id)
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* List certificates
|
|
376
|
+
*/
|
|
377
|
+
listCertificates(): Certificate[] {
|
|
378
|
+
return Array.from(this.certificates.values())
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Get expiring certificates
|
|
383
|
+
*/
|
|
384
|
+
getExpiringCertificates(days: number = 30): Certificate[] {
|
|
385
|
+
const cutoffTime = Date.now() + days * 24 * 60 * 60 * 1000
|
|
386
|
+
|
|
387
|
+
return Array.from(this.certificates.values()).filter(
|
|
388
|
+
cert => cert.expiresAt && cert.expiresAt.getTime() < cutoffTime
|
|
389
|
+
)
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Get validation
|
|
394
|
+
*/
|
|
395
|
+
getValidation(certificateId: string): CertificateValidation | undefined {
|
|
396
|
+
return this.validations.get(certificateId)
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Get renewal
|
|
401
|
+
*/
|
|
402
|
+
getRenewal(id: string): CertificateRenewal | undefined {
|
|
403
|
+
return this.renewals.get(id)
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* List renewals
|
|
408
|
+
*/
|
|
409
|
+
listRenewals(): CertificateRenewal[] {
|
|
410
|
+
return Array.from(this.renewals.values())
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* List alerts
|
|
415
|
+
*/
|
|
416
|
+
listAlerts(acknowledged: boolean = false): CertificateAlert[] {
|
|
417
|
+
return Array.from(this.alerts.values()).filter(
|
|
418
|
+
alert => alert.acknowledged === acknowledged
|
|
419
|
+
)
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Generate CloudFormation for certificate
|
|
424
|
+
*/
|
|
425
|
+
generateCertificateCF(certificate: Certificate): any {
|
|
426
|
+
return {
|
|
427
|
+
Type: 'AWS::CertificateManager::Certificate',
|
|
428
|
+
Properties: {
|
|
429
|
+
DomainName: certificate.domainName,
|
|
430
|
+
...(certificate.subjectAlternativeNames && {
|
|
431
|
+
SubjectAlternativeNames: certificate.subjectAlternativeNames,
|
|
432
|
+
}),
|
|
433
|
+
ValidationMethod: certificate.validationMethod,
|
|
434
|
+
},
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Generate CloudWatch alarm for expiration
|
|
440
|
+
*/
|
|
441
|
+
generateExpirationAlarmCF(options: {
|
|
442
|
+
alarmName: string
|
|
443
|
+
certificateArn: string
|
|
444
|
+
daysBeforeExpiration: number
|
|
445
|
+
snsTopicArn?: string
|
|
446
|
+
}): any {
|
|
447
|
+
return {
|
|
448
|
+
Type: 'AWS::CloudWatch::Alarm',
|
|
449
|
+
Properties: {
|
|
450
|
+
AlarmName: options.alarmName,
|
|
451
|
+
AlarmDescription: `Certificate expiring in ${options.daysBeforeExpiration} days`,
|
|
452
|
+
MetricName: 'DaysToExpiry',
|
|
453
|
+
Namespace: 'AWS/CertificateManager',
|
|
454
|
+
Statistic: 'Minimum',
|
|
455
|
+
Period: 86400, // 1 day
|
|
456
|
+
EvaluationPeriods: 1,
|
|
457
|
+
Threshold: options.daysBeforeExpiration,
|
|
458
|
+
ComparisonOperator: 'LessThanThreshold',
|
|
459
|
+
Dimensions: [
|
|
460
|
+
{
|
|
461
|
+
Name: 'CertificateArn',
|
|
462
|
+
Value: options.certificateArn,
|
|
463
|
+
},
|
|
464
|
+
],
|
|
465
|
+
...(options.snsTopicArn && {
|
|
466
|
+
AlarmActions: [options.snsTopicArn],
|
|
467
|
+
}),
|
|
468
|
+
},
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Clear all data
|
|
474
|
+
*/
|
|
475
|
+
clear(): void {
|
|
476
|
+
this.certificates.clear()
|
|
477
|
+
this.renewals.clear()
|
|
478
|
+
this.validations.clear()
|
|
479
|
+
this.monitors.clear()
|
|
480
|
+
this.alerts.clear()
|
|
481
|
+
this.certificateCounter = 0
|
|
482
|
+
this.renewalCounter = 0
|
|
483
|
+
this.validationCounter = 0
|
|
484
|
+
this.monitorCounter = 0
|
|
485
|
+
this.alertCounter = 0
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* Global certificate manager instance
|
|
491
|
+
*/
|
|
492
|
+
export const certificateManager: CertificateManager = new CertificateManager()
|