terruvim-core-test 0.0.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.
Files changed (199) hide show
  1. package/dist/src/core/config.js +2 -0
  2. package/dist/src/core/configMerge.js +266 -0
  3. package/dist/src/core/configUtils.js +72 -0
  4. package/dist/src/core/dependencyResolver.js +17 -0
  5. package/dist/src/core/deployUtils.js +73 -0
  6. package/dist/src/core/dynamicResourceManager.js +709 -0
  7. package/dist/src/core/entrypoint.js +56 -0
  8. package/dist/src/core/generateFinalConfig.js +45 -0
  9. package/dist/src/core/index.js +24 -0
  10. package/dist/src/core/resourceMap.js +99 -0
  11. package/dist/src/factories/accountPermissions.js +134 -0
  12. package/dist/src/factories/acmFactory.js +30 -0
  13. package/dist/src/factories/albFactory.js +331 -0
  14. package/dist/src/factories/attachSecretAccessPolicy.js +56 -0
  15. package/dist/src/factories/auroraFactory.js +619 -0
  16. package/dist/src/factories/backupPolicy.js +152 -0
  17. package/dist/src/factories/bastionFactory.js +91 -0
  18. package/dist/src/factories/bedrockFactory.js +334 -0
  19. package/dist/src/factories/budgetFactory.js +64 -0
  20. package/dist/src/factories/buildAlbCloudWatchAlarmsHelper.js +79 -0
  21. package/dist/src/factories/buildAlbCloudWatchDashboardHelper.js +106 -0
  22. package/dist/src/factories/buildAlbListenerRulesHelper.js +45 -0
  23. package/dist/src/factories/buildAlbListenersHelper.js +64 -0
  24. package/dist/src/factories/buildAlbResourceHelper.js +54 -0
  25. package/dist/src/factories/buildAlbRoute53RecordHelper.js +49 -0
  26. package/dist/src/factories/buildAlbTargetGroupsHelper.js +47 -0
  27. package/dist/src/factories/buildAlbWafAssociationHelper.js +43 -0
  28. package/dist/src/factories/buildAndPushDockerImage.js +57 -0
  29. package/dist/src/factories/buildAwsCloudWatchAlarmsHelper.js +118 -0
  30. package/dist/src/factories/buildCloudFrontRoute53RecordHelper.js +49 -0
  31. package/dist/src/factories/buildEcsClusterArgs.js +32 -0
  32. package/dist/src/factories/buildEcsSecrets.js +48 -0
  33. package/dist/src/factories/buildForceRedeployEnv.js +8 -0
  34. package/dist/src/factories/buildResourceOptions.js +11 -0
  35. package/dist/src/factories/buildS3StaticHostingCicdHelper.js +142 -0
  36. package/dist/src/factories/buildS3StaticHostingCloudWatchDashboardHelper.js +122 -0
  37. package/dist/src/factories/cloudTrailFactory.js +22 -0
  38. package/dist/src/factories/cloudWatchCompositeAlarmFactory.js +91 -0
  39. package/dist/src/factories/cloudWatchInsightsQueryFactory.js +83 -0
  40. package/dist/src/factories/cloudWatchLogGroupFactory.js +84 -0
  41. package/dist/src/factories/cloudfrontCodePipelineFactory.js +357 -0
  42. package/dist/src/factories/cloudwatchAlarmsFactory.js +121 -0
  43. package/dist/src/factories/codePipelineNotificationFactory.js +193 -0
  44. package/dist/src/factories/codePipelineNotificationRulesFactory.js +117 -0
  45. package/dist/src/factories/codeStarConnectionFactory.js +56 -0
  46. package/dist/src/factories/collectSecretKeys.js +18 -0
  47. package/dist/src/factories/comprehensiveNotificationFactory.js +250 -0
  48. package/dist/src/factories/costAndUsageReportFactory.js +32 -0
  49. package/dist/src/factories/createAwsAcmCertificate.js +40 -0
  50. package/dist/src/factories/createAwsBudget.js +40 -0
  51. package/dist/src/factories/createAwsCloudTrail.js +59 -0
  52. package/dist/src/factories/createAwsCloudwatchDashboard.js +59 -0
  53. package/dist/src/factories/createAwsEc2Instance.js +40 -0
  54. package/dist/src/factories/createAwsEventBridgeEventBus.js +40 -0
  55. package/dist/src/factories/createAwsGuardDutyDetector.js +40 -0
  56. package/dist/src/factories/createAwsGuardDutyDetectorFeature.js +45 -0
  57. package/dist/src/factories/createAwsGuardDutyFilter.js +46 -0
  58. package/dist/src/factories/createAwsGuardDutyPublishingDestination.js +50 -0
  59. package/dist/src/factories/createAwsHostedZone.js +40 -0
  60. package/dist/src/factories/createAwsIamRole.js +49 -0
  61. package/dist/src/factories/createAwsIamRoleInlinePolicies.js +48 -0
  62. package/dist/src/factories/createAwsIdentitystoreGroup.js +44 -0
  63. package/dist/src/factories/createAwsIdentitystoreGroupMembership.js +56 -0
  64. package/dist/src/factories/createAwsIdentitystoreUser.js +47 -0
  65. package/dist/src/factories/createAwsInspectorAssessmentTarget.js +47 -0
  66. package/dist/src/factories/createAwsInspectorDelegatedAdminAccount.js +47 -0
  67. package/dist/src/factories/createAwsInspectorEnabler.js +49 -0
  68. package/dist/src/factories/createAwsInspectorOrganizationConfiguration.js +55 -0
  69. package/dist/src/factories/createAwsKmsAliases.js +47 -0
  70. package/dist/src/factories/createAwsKmsKey.js +51 -0
  71. package/dist/src/factories/createAwsMacieAccount.js +45 -0
  72. package/dist/src/factories/createAwsMacieClassificationJob.js +53 -0
  73. package/dist/src/factories/createAwsMacieMember.js +49 -0
  74. package/dist/src/factories/createAwsMacieOrganizationConfiguration.js +44 -0
  75. package/dist/src/factories/createAwsRdsCluster.js +40 -0
  76. package/dist/src/factories/createAwsRdsClusterInstance.js +40 -0
  77. package/dist/src/factories/createAwsRdsInstance.js +40 -0
  78. package/dist/src/factories/createAwsRdsSubnetGroup.js +40 -0
  79. package/dist/src/factories/createAwsRoute53Record.js +40 -0
  80. package/dist/src/factories/createAwsSecret.js +40 -0
  81. package/dist/src/factories/createAwsSecretRotation.js +40 -0
  82. package/dist/src/factories/createAwsSecretVersion.js +40 -0
  83. package/dist/src/factories/createAwsSecurityGroup.js +40 -0
  84. package/dist/src/factories/createAwsSecurityGroupRule.js +40 -0
  85. package/dist/src/factories/createAwsSecurityHubAccount.js +40 -0
  86. package/dist/src/factories/createAwsSecurityHubAutomationRule.js +48 -0
  87. package/dist/src/factories/createAwsSecurityHubStandardsControl.js +44 -0
  88. package/dist/src/factories/createAwsSecurityHubStandardsSubscription.js +42 -0
  89. package/dist/src/factories/createAwsSesDomainDkim.js +40 -0
  90. package/dist/src/factories/createAwsSesDomainIdentity.js +40 -0
  91. package/dist/src/factories/createAwsSesEmailIdentity.js +40 -0
  92. package/dist/src/factories/createAwsSnsSubscription.js +62 -0
  93. package/dist/src/factories/createAwsSnsTopic.js +41 -0
  94. package/dist/src/factories/createAwsSqsQueue.js +40 -0
  95. package/dist/src/factories/createAwsSsmParameters.js +66 -0
  96. package/dist/src/factories/createAwsSsoAccountAssignment.js +66 -0
  97. package/dist/src/factories/createAwsSsoPermissionSet.js +64 -0
  98. package/dist/src/factories/createAwsStepFunctionsStateMachine.js +40 -0
  99. package/dist/src/factories/createBudget.js +56 -0
  100. package/dist/src/factories/createBudgetWithSnsAlert.js +79 -0
  101. package/dist/src/factories/createCostAndUsageReport.js +40 -0
  102. package/dist/src/factories/createEcrRepo.js +69 -0
  103. package/dist/src/factories/createEcsRolesAndPolicies.js +84 -0
  104. package/dist/src/factories/createEcsService.js +71 -0
  105. package/dist/src/factories/createEnvSecret.js +60 -0
  106. package/dist/src/factories/createGithubCodeStarConnection.js +44 -0
  107. package/dist/src/factories/createIamUserWithAccessKey.js +44 -0
  108. package/dist/src/factories/createLambdaFunction.js +89 -0
  109. package/dist/src/factories/createLambdaPermission.js +57 -0
  110. package/dist/src/factories/createListenerRule.js +68 -0
  111. package/dist/src/factories/createLogGroup.js +44 -0
  112. package/dist/src/factories/createSlackChannelConfiguration.js +49 -0
  113. package/dist/src/factories/createTargetGroup.js +50 -0
  114. package/dist/src/factories/createTaskDefinition.js +49 -0
  115. package/dist/src/factories/createVpcEndpoint.js +49 -0
  116. package/dist/src/factories/dashboardFactory.js +94 -0
  117. package/dist/src/factories/dataProtectionPolicyBuilder.js +103 -0
  118. package/dist/src/factories/ec2Factory.js +67 -0
  119. package/dist/src/factories/ecsClusterFactory.js +90 -0
  120. package/dist/src/factories/ecsCodePipelineFactory.js +308 -0
  121. package/dist/src/factories/ecsServiceFactory.js +350 -0
  122. package/dist/src/factories/enhancedCloudFrontCodePipelineFactory.js +205 -0
  123. package/dist/src/factories/enhancedEcsCodePipelineFactory.js +189 -0
  124. package/dist/src/factories/eventBridgeBusFactory.js +84 -0
  125. package/dist/src/factories/eventBridgeFactory.js +26 -0
  126. package/dist/src/factories/eventBridgeRuleFactory.js +114 -0
  127. package/dist/src/factories/fetchAllSecrets.js +51 -0
  128. package/dist/src/factories/getDeterministicPriority.js +13 -0
  129. package/dist/src/factories/getOrCreateSshKeyPair.js +57 -0
  130. package/dist/src/factories/guardDutyFactory.js +151 -0
  131. package/dist/src/factories/hostedZoneFactory.js +30 -0
  132. package/dist/src/factories/iamRoleFactory.js +29 -0
  133. package/dist/src/factories/inspectorFactory.js +109 -0
  134. package/dist/src/factories/kmsKeyFactory.js +32 -0
  135. package/dist/src/factories/lambdaFactory.js +133 -0
  136. package/dist/src/factories/lambdaPermissionFactory.js +32 -0
  137. package/dist/src/factories/logDataProtectionPolicyFactory.js +81 -0
  138. package/dist/src/factories/macieFactory.js +85 -0
  139. package/dist/src/factories/networkingFactory.js +429 -0
  140. package/dist/src/factories/opensearchCollectionFactory.js +109 -0
  141. package/dist/src/factories/organizationFactory.js +221 -0
  142. package/dist/src/factories/processReservedInstances.js +6 -0
  143. package/dist/src/factories/processSavingsPlans.js +43 -0
  144. package/dist/src/factories/rdsFactory.js +40 -0
  145. package/dist/src/factories/recordFactory.js +36 -0
  146. package/dist/src/factories/resolveEnvSecrets.js +14 -0
  147. package/dist/src/factories/resourceFactory.js +12 -0
  148. package/dist/src/factories/s3Factory.js +262 -0
  149. package/dist/src/factories/s3StaticHostingFactory.backup.js +424 -0
  150. package/dist/src/factories/s3StaticHostingFactory.js +348 -0
  151. package/dist/src/factories/s3StaticHostingFactory.refactored.js +334 -0
  152. package/dist/src/factories/savingsPlanFactory.js +26 -0
  153. package/dist/src/factories/secretsManagerFactory.js +107 -0
  154. package/dist/src/factories/securityGroupFactory.js +28 -0
  155. package/dist/src/factories/securityGroupRuleFactory.js +43 -0
  156. package/dist/src/factories/securityHubFactory.js +96 -0
  157. package/dist/src/factories/sesDomainDkimFactory.js +25 -0
  158. package/dist/src/factories/sesFactory.js +25 -0
  159. package/dist/src/factories/sesIdentitiesFactory.js +134 -0
  160. package/dist/src/factories/simpleNotificationFactory.js +112 -0
  161. package/dist/src/factories/smtpUserFactory.js +108 -0
  162. package/dist/src/factories/snsFactory.js +87 -0
  163. package/dist/src/factories/sqsFactory.js +41 -0
  164. package/dist/src/factories/ssmParameterFactory.js +67 -0
  165. package/dist/src/factories/ssoFactory.js +32 -0
  166. package/dist/src/factories/ssoGroupFactory.js +41 -0
  167. package/dist/src/factories/ssoPermissionSetFactory.js +29 -0
  168. package/dist/src/factories/ssoUserFactory.js +30 -0
  169. package/dist/src/factories/stepFunctionsFactory.js +32 -0
  170. package/dist/src/factories/tagPolicies.js +99 -0
  171. package/dist/src/factories/transformBudgetCostFilters.js +8 -0
  172. package/dist/src/factories/transformBudgetNotifications.js +12 -0
  173. package/dist/src/factories/transformBudgetPlannedLimits.js +8 -0
  174. package/dist/src/factories/types.js +2 -0
  175. package/dist/src/factories/validateAcmConfig.js +26 -0
  176. package/dist/src/factories/validateAuroraConfig.js +8 -0
  177. package/dist/src/factories/validateBedrockConfig.js +124 -0
  178. package/dist/src/factories/validateDashboardConfig.js +28 -0
  179. package/dist/src/factories/validateEventBridgeConfig.js +14 -0
  180. package/dist/src/factories/validateHostedZoneConfig.js +26 -0
  181. package/dist/src/factories/validateIamRoleConfig.js +8 -0
  182. package/dist/src/factories/validateKmsKeyConfig.js +8 -0
  183. package/dist/src/factories/validateRdsConfig.js +17 -0
  184. package/dist/src/factories/validateRoute53RecordConfig.js +41 -0
  185. package/dist/src/factories/validateS3Config.js +8 -0
  186. package/dist/src/factories/validateSecretsManagerConfig.js +8 -0
  187. package/dist/src/factories/validateSecurityGroupConfig.js +8 -0
  188. package/dist/src/factories/validateSecurityGroupRuleConfig.js +8 -0
  189. package/dist/src/factories/validateSesDomainDkimConfig.js +8 -0
  190. package/dist/src/factories/validateSesDomainIdentityConfig.js +8 -0
  191. package/dist/src/factories/validateSesIdentitiesConfig.js +40 -0
  192. package/dist/src/factories/validateSnsConfig.js +11 -0
  193. package/dist/src/factories/validateSqsConfig.js +11 -0
  194. package/dist/src/factories/validateSsmParameterFactoryConfig.js +9 -0
  195. package/dist/src/factories/validateStepFunctionsConfig.js +8 -0
  196. package/dist/src/factories/vpcEndpointFactory.js +98 -0
  197. package/dist/src/factories/wafFactory.js +499 -0
  198. package/package.json +71 -0
  199. package/scripts/copy-assets.js +136 -0
@@ -0,0 +1,619 @@
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.AuroraFactory = void 0;
37
+ const aws = __importStar(require("@pulumi/aws"));
38
+ const pulumi = __importStar(require("@pulumi/pulumi"));
39
+ const resourceFactory_1 = require("./resourceFactory");
40
+ const validateAuroraConfig_1 = require("./validateAuroraConfig");
41
+ const createAwsRdsSubnetGroup_1 = require("./createAwsRdsSubnetGroup");
42
+ const createAwsRdsCluster_1 = require("./createAwsRdsCluster");
43
+ const createAwsRdsClusterInstance_1 = require("./createAwsRdsClusterInstance");
44
+ const dataProtectionPolicyBuilder_1 = require("./dataProtectionPolicyBuilder");
45
+ class AuroraFactory extends resourceFactory_1.ResourceFactory {
46
+ async createResource(config, provider) {
47
+ (0, validateAuroraConfig_1.validateAuroraConfig)(config);
48
+ if (!config.inputs.sgId) {
49
+ throw new Error("AuroraFactory: sgId must be provided in inputs (create security group separately)");
50
+ }
51
+ const monitoringRole = this.createMonitoringRole(config, provider);
52
+ const subnetGroup = (0, createAwsRdsSubnetGroup_1.createAwsRdsSubnetGroup)(`${config.meta.environment}-${config.id}-subnet-group`, {
53
+ subnetIds: config.inputs.subnetIds || [],
54
+ description: `Subnet group for ${config.id}`,
55
+ }, provider ? { provider } : undefined);
56
+ const isServerlessV2 = !!config.configuration.serverlessV2ScalingConfiguration;
57
+ const securityConfig = {
58
+ storageEncrypted: config.configuration.storageEncrypted ?? true,
59
+ kmsKeyId: config.configuration.kmsKeyId,
60
+ deletionProtection: config.configuration.deletionProtection ?? true,
61
+ iamDatabaseAuthenticationEnabled: config.configuration.enableIAMDatabaseAuthentication ?? true,
62
+ copyTagsToSnapshot: config.configuration.copyTagsToSnapshot ?? true,
63
+ skipFinalSnapshot: config.configuration.skipFinalSnapshot ?? false,
64
+ finalSnapshotIdentifier: config.configuration.finalSnapshotIdentifier,
65
+ allowMajorVersionUpgrade: config.configuration.allowMajorVersionUpgrade ?? false,
66
+ performanceInsightsEnabled: config.configuration.performanceInsightsEnabled ?? true,
67
+ performanceInsightsKmsKeyId: config.configuration.performanceInsightsKmsKeyId,
68
+ performanceInsightsRetentionPeriod: config.configuration.performanceInsightsRetentionPeriod ?? 7,
69
+ monitoringInterval: config.configuration.monitoringInterval ?? 60,
70
+ monitoringRoleArn: monitoringRole?.arn || config.configuration.monitoringRoleArn,
71
+ backupRetentionPeriod: config.configuration.backupRetentionPeriod ?? 35,
72
+ preferredBackupWindow: config.configuration.preferredBackupWindow ?? "03:00-04:00",
73
+ preferredMaintenanceWindow: config.configuration.preferredMaintenanceWindow ?? "sun:04:00-sun:05:00",
74
+ enabledCloudwatchLogsExports: config.configuration.enabledCloudwatchLogsExports ?? ["postgresql"],
75
+ networkType: config.configuration.networkType ?? "IPV4",
76
+ dbClusterParameterGroupName: config.configuration.dbClusterParameterGroupName,
77
+ enableHttpEndpoint: config.configuration.enableHttpEndpoint ?? false,
78
+ enableGlobalWriteForwarding: config.configuration.enableGlobalWriteForwarding ?? false,
79
+ };
80
+ const clusterConfig = {
81
+ engine: config.configuration.engine,
82
+ engineMode: isServerlessV2 ? "provisioned" : config.configuration.engineMode,
83
+ engineVersion: config.configuration.engineVersion,
84
+ databaseName: config.configuration.dbName,
85
+ masterUsername: config.configuration.username,
86
+ masterPassword: config.configuration.password,
87
+ vpcSecurityGroupIds: [config.inputs.sgId],
88
+ dbSubnetGroupName: subnetGroup.name,
89
+ tags: config.configuration.tags,
90
+ ...securityConfig,
91
+ };
92
+ if (isServerlessV2) {
93
+ clusterConfig.serverlessv2ScalingConfiguration = config.configuration.serverlessV2ScalingConfiguration;
94
+ }
95
+ const cluster = (0, createAwsRdsCluster_1.createAwsRdsCluster)(`${config.meta.environment}-${config.id}`, clusterConfig, provider ? { provider } : undefined);
96
+ if (isServerlessV2) {
97
+ (0, createAwsRdsClusterInstance_1.createAwsRdsClusterInstance)(`${config.meta.environment}-${config.id}-instance`, {
98
+ identifier: `${config.meta.environment}-${config.id}-aurora-cluster-instance`,
99
+ clusterIdentifier: cluster.id,
100
+ instanceClass: "db.serverless",
101
+ engine: config.configuration.engine,
102
+ engineVersion: config.configuration.engineVersion,
103
+ performanceInsightsEnabled: securityConfig.performanceInsightsEnabled,
104
+ performanceInsightsKmsKeyId: securityConfig.performanceInsightsKmsKeyId,
105
+ performanceInsightsRetentionPeriod: securityConfig.performanceInsightsRetentionPeriod,
106
+ monitoringInterval: securityConfig.monitoringInterval,
107
+ monitoringRoleArn: monitoringRole?.arn || securityConfig.monitoringRoleArn,
108
+ tags: config.configuration.tags,
109
+ }, provider ? { provider } : undefined);
110
+ }
111
+ else if (config.configuration.engineMode !== "serverless" && !isServerlessV2) {
112
+ const timestamp = Date.now().toString().slice(-8);
113
+ (0, createAwsRdsClusterInstance_1.createAwsRdsClusterInstance)(`${config.meta.environment}-${config.id}-instance`, {
114
+ identifier: `${config.meta.environment}-${config.id}-aurora-instance-${timestamp}`,
115
+ clusterIdentifier: cluster.id,
116
+ instanceClass: config.configuration.instanceClass,
117
+ engine: config.configuration.engine,
118
+ engineVersion: config.configuration.engineVersion,
119
+ performanceInsightsEnabled: securityConfig.performanceInsightsEnabled,
120
+ performanceInsightsKmsKeyId: securityConfig.performanceInsightsKmsKeyId,
121
+ performanceInsightsRetentionPeriod: securityConfig.performanceInsightsRetentionPeriod,
122
+ monitoringInterval: securityConfig.monitoringInterval,
123
+ monitoringRoleArn: monitoringRole?.arn || securityConfig.monitoringRoleArn,
124
+ tags: config.configuration.tags,
125
+ }, provider ? { provider } : undefined);
126
+ }
127
+ this.createAuroraAutoScaling(config, cluster, provider);
128
+ if (config.crossRegionBackup?.enabled) {
129
+ await this.createCrossRegionBackup(config, cluster, provider);
130
+ }
131
+ if (config.configuration.cloudwatchLogsDataProtection?.enabled) {
132
+ const enabledLogs = config.configuration.enabledCloudwatchLogsExports || ["postgresql"];
133
+ for (const logType of enabledLogs) {
134
+ const logGroupName = `/aws/rds/cluster/${config.meta.environment}-${config.id}/${logType}`;
135
+ const logGroup = new aws.cloudwatch.LogGroup(`${config.meta.environment}-${config.id}-${logType}-log-group`, {
136
+ name: logGroupName,
137
+ retentionInDays: 365,
138
+ tags: config.configuration.tags,
139
+ }, {
140
+ provider: provider,
141
+ dependsOn: [cluster]
142
+ });
143
+ const dataProtectionPolicy = this.buildDataProtectionPolicy(config.configuration.cloudwatchLogsDataProtection, logGroupName);
144
+ new aws.cloudwatch.LogDataProtectionPolicy(`${config.meta.environment}-${config.id}-${logType}-data-protection`, {
145
+ logGroupName: logGroupName,
146
+ policyDocument: JSON.stringify(dataProtectionPolicy),
147
+ }, {
148
+ provider: provider,
149
+ dependsOn: [cluster, logGroup]
150
+ });
151
+ }
152
+ }
153
+ return cluster;
154
+ }
155
+ createMonitoringRole(config, provider) {
156
+ const monitoringInterval = config.configuration.monitoringInterval;
157
+ if (!monitoringInterval || monitoringInterval === 0) {
158
+ return undefined;
159
+ }
160
+ const monitoringRole = new aws.iam.Role(`${config.meta.environment}-${config.id}-monitoring-role`, {
161
+ assumeRolePolicy: JSON.stringify({
162
+ Version: "2012-10-17",
163
+ Statement: [
164
+ {
165
+ Action: "sts:AssumeRole",
166
+ Effect: "Allow",
167
+ Principal: {
168
+ Service: "monitoring.rds.amazonaws.com"
169
+ }
170
+ }
171
+ ]
172
+ }),
173
+ tags: {
174
+ ...config.configuration.tags,
175
+ Purpose: "RDS Enhanced Monitoring"
176
+ }
177
+ }, provider ? { provider } : undefined);
178
+ new aws.iam.RolePolicyAttachment(`${config.meta.environment}-${config.id}-monitoring-policy`, {
179
+ role: monitoringRole.name,
180
+ policyArn: "arn:aws:iam::aws:policy/service-role/AmazonRDSEnhancedMonitoringRole"
181
+ }, provider ? { provider } : undefined);
182
+ return monitoringRole;
183
+ }
184
+ createAuroraAutoScaling(config, cluster, provider) {
185
+ if (!config.autoScaling?.enabled) {
186
+ return;
187
+ }
188
+ const autoScalingConfig = config.autoScaling;
189
+ const resourceId = cluster.clusterIdentifier.apply(id => `cluster:${id}`);
190
+ const scalableTarget = new aws.appautoscaling.Target(`${config.meta.environment}-${config.id}-autoscaling-target`, {
191
+ serviceNamespace: "rds",
192
+ resourceId: resourceId,
193
+ scalableDimension: "rds:cluster:ReadReplicaCount",
194
+ minCapacity: autoScalingConfig.minCapacity,
195
+ maxCapacity: autoScalingConfig.maxCapacity,
196
+ }, provider ? { provider } : undefined);
197
+ if (autoScalingConfig.targetCpuUtilization) {
198
+ new aws.appautoscaling.Policy(`${config.meta.environment}-${config.id}-cpu-scaling-policy`, {
199
+ name: `${config.meta.environment}-${config.id}-cpu-scaling-policy`,
200
+ serviceNamespace: scalableTarget.serviceNamespace,
201
+ resourceId: scalableTarget.resourceId,
202
+ scalableDimension: scalableTarget.scalableDimension,
203
+ policyType: "TargetTrackingScaling",
204
+ targetTrackingScalingPolicyConfiguration: {
205
+ targetValue: autoScalingConfig.targetCpuUtilization,
206
+ predefinedMetricSpecification: {
207
+ predefinedMetricType: "RDSReaderAverageCPUUtilization",
208
+ },
209
+ scaleInCooldown: autoScalingConfig.scaleInCooldown || 300,
210
+ scaleOutCooldown: autoScalingConfig.scaleOutCooldown || 300,
211
+ },
212
+ }, provider ? { provider, dependsOn: [scalableTarget] } : { dependsOn: [scalableTarget] });
213
+ }
214
+ }
215
+ async createCrossRegionBackup(config, cluster, provider) {
216
+ const backupConfig = config.crossRegionBackup;
217
+ const resolvedBackupRegion = backupConfig.backupRegion.startsWith('${')
218
+ ? config.meta.variables?.backupRegion || 'eu-west-3'
219
+ : backupConfig.backupRegion;
220
+ if (backupConfig.enableLambdaBackups === false) {
221
+ }
222
+ if (backupConfig.globalDatabase?.enabled) {
223
+ const configuredGlobalClusterIdentifier = backupConfig.globalDatabase.globalClusterIdentifier ||
224
+ `global-${config.meta.environment}-${config.id}`;
225
+ const globalClusterIdentifier = configuredGlobalClusterIdentifier.includes('${meta.environment}')
226
+ ? configuredGlobalClusterIdentifier.replace('${meta.environment}', config.meta.environment).toLowerCase()
227
+ : configuredGlobalClusterIdentifier.toLowerCase();
228
+ const globalCluster = new aws.rds.GlobalCluster(`${config.meta.environment}-${config.id}-global-cluster`, {
229
+ globalClusterIdentifier: globalClusterIdentifier,
230
+ engine: config.configuration.engine || "aurora-postgresql",
231
+ engineVersion: config.configuration.engineVersion || "16.6",
232
+ storageEncrypted: config.configuration.storageEncrypted ?? true,
233
+ deletionProtection: config.configuration.deletionProtection ?? false,
234
+ forceDestroy: true,
235
+ }, provider ? { provider } : undefined);
236
+ }
237
+ if (backupConfig.snapshotCopy?.enabled && backupConfig.enableLambdaBackups !== false) {
238
+ const snapshotRule = new aws.cloudwatch.EventRule(`${config.meta.environment}-${config.id}-snapshot-rule`, {
239
+ name: `${config.meta.environment}-${config.id}-snapshot-rule`,
240
+ description: `Automated Aurora snapshot copy to ${resolvedBackupRegion}`,
241
+ scheduleExpression: `rate(${backupConfig.snapshotCopy.copyInterval || 24} hours)`,
242
+ state: "ENABLED",
243
+ }, provider ? { provider } : undefined);
244
+ const snapshotLogGroup = new aws.cloudwatch.LogGroup(`${config.meta.environment}-${config.id}-snapshot-logs`, {
245
+ name: `/aws/lambda/${config.meta.environment}-${config.id}-aurora-snapshot-copy`,
246
+ retentionInDays: 365,
247
+ }, provider ? { provider } : undefined);
248
+ const snapshotLambdaRole = new aws.iam.Role(`${config.meta.environment}-${config.id}-snapshot-lambda-role`, {
249
+ assumeRolePolicy: JSON.stringify({
250
+ Version: "2012-10-17",
251
+ Statement: [
252
+ {
253
+ Action: "sts:AssumeRole",
254
+ Effect: "Allow",
255
+ Principal: {
256
+ Service: "lambda.amazonaws.com"
257
+ }
258
+ }
259
+ ]
260
+ })
261
+ }, provider ? { provider } : undefined);
262
+ const snapshotLambdaPolicy = new aws.iam.RolePolicy(`${config.meta.environment}-${config.id}-snapshot-lambda-policy`, {
263
+ role: snapshotLambdaRole.id,
264
+ policy: JSON.stringify({
265
+ Version: "2012-10-17",
266
+ Statement: [
267
+ {
268
+ Effect: "Allow",
269
+ Action: [
270
+ "logs:CreateLogGroup",
271
+ "logs:CreateLogStream",
272
+ "logs:PutLogEvents"
273
+ ],
274
+ Resource: "arn:aws:logs:*:*:*"
275
+ },
276
+ {
277
+ Effect: "Allow",
278
+ Action: [
279
+ "rds:DescribeDBClusters",
280
+ "rds:DescribeDBClusterSnapshots",
281
+ "rds:CreateDBClusterSnapshot",
282
+ "rds:CopyDBClusterSnapshot",
283
+ "rds:DeleteDBClusterSnapshot"
284
+ ],
285
+ Resource: "*"
286
+ },
287
+ {
288
+ Effect: "Allow",
289
+ Action: [
290
+ "kms:Decrypt",
291
+ "kms:DescribeKey",
292
+ "kms:Encrypt",
293
+ "kms:GenerateDataKey*",
294
+ "kms:ReEncrypt*"
295
+ ],
296
+ Resource: "*"
297
+ }
298
+ ]
299
+ })
300
+ }, provider ? { provider } : undefined);
301
+ const snapshotLambda = new aws.lambda.Function(`${config.meta.environment}-${config.id}-snapshot-lambda`, {
302
+ name: `${config.meta.environment}-${config.id}-aurora-snapshot-copy`,
303
+ role: snapshotLambdaRole.arn,
304
+ handler: "index.handler",
305
+ runtime: "python3.9",
306
+ timeout: 300,
307
+ code: new pulumi.asset.AssetArchive({
308
+ "index.py": new pulumi.asset.StringAsset(`
309
+ import boto3
310
+ import json
311
+ import os
312
+ from datetime import datetime
313
+ def handler(event, context):
314
+ cluster_id = os.environ['CLUSTER_ID']
315
+ backup_region = os.environ['BACKUP_REGION']
316
+ retention_days = int(os.environ.get('RETENTION_DAYS', '14'))
317
+ # Create RDS clients for both regions
318
+ source_rds = boto3.client('rds')
319
+ target_rds = boto3.client('rds', region_name=backup_region)
320
+ try:
321
+ # Create snapshot in source region
322
+ timestamp = datetime.now().strftime('%Y-%m-%d-%H-%M-%S')
323
+ snapshot_id = f"{cluster_id}-snapshot-{timestamp}"
324
+ print(f"Creating snapshot {snapshot_id} for cluster {cluster_id}")
325
+ source_rds.create_db_cluster_snapshot(
326
+ DBClusterSnapshotIdentifier=snapshot_id,
327
+ DBClusterIdentifier=cluster_id
328
+ )
329
+ # Wait for snapshot to be available
330
+ waiter = source_rds.get_waiter('db_cluster_snapshot_completed')
331
+ waiter.wait(DBClusterSnapshotIdentifier=snapshot_id)
332
+ # Copy snapshot to backup region
333
+ source_snapshot_arn = f"arn:aws:rds:eu-central-1:{context.invoked_function_arn.split(':')[4]}:cluster-snapshot:{snapshot_id}"
334
+ target_snapshot_id = f"{cluster_id}-backup-{timestamp}"
335
+ print(f"Copying snapshot to {backup_region} as {target_snapshot_id}")
336
+ copy_params = {
337
+ 'SourceDBClusterSnapshotIdentifier': source_snapshot_arn,
338
+ 'TargetDBClusterSnapshotIdentifier': target_snapshot_id,
339
+ 'CopyTags': True
340
+ }
341
+ # Add KMS key if provided for encrypted snapshots
342
+ target_kms_key = os.environ.get('TARGET_KMS_KEY_ID')
343
+ if target_kms_key:
344
+ copy_params['KmsKeyId'] = target_kms_key
345
+ print(f"Using KMS key for cross-region encryption: {target_kms_key}")
346
+ target_rds.copy_db_cluster_snapshot(**copy_params)
347
+ # Clean up old snapshots (retention policy)
348
+ snapshots = target_rds.describe_db_cluster_snapshots(
349
+ SnapshotType='manual',
350
+ DBClusterIdentifier=cluster_id
351
+ )
352
+ # Sort by creation time and delete old ones
353
+ old_snapshots = sorted(
354
+ [s for s in snapshots['DBClusterSnapshots'] if s['DBClusterSnapshotIdentifier'].startswith(f"{cluster_id}-backup-")],
355
+ key=lambda x: x['SnapshotCreateTime']
356
+ )[:-retention_days]
357
+ for old_snapshot in old_snapshots:
358
+ print(f"Deleting old snapshot {old_snapshot['DBClusterSnapshotIdentifier']}")
359
+ target_rds.delete_db_cluster_snapshot(
360
+ DBClusterSnapshotIdentifier=old_snapshot['DBClusterSnapshotIdentifier']
361
+ )
362
+ return {
363
+ 'statusCode': 200,
364
+ 'body': json.dumps(f'Successfully copied snapshot {snapshot_id} to {backup_region}')
365
+ }
366
+ except Exception as e:
367
+ print(f"Error: {str(e)}")
368
+ return {
369
+ 'statusCode': 500,
370
+ 'body': json.dumps(f'Error: {str(e)}')
371
+ }
372
+ `)
373
+ }),
374
+ environment: {
375
+ variables: {
376
+ CLUSTER_ID: cluster.clusterIdentifier,
377
+ BACKUP_REGION: resolvedBackupRegion,
378
+ RETENTION_DAYS: (backupConfig.snapshotCopy.retentionPeriod || 14).toString(),
379
+ TARGET_KMS_KEY_ID: backupConfig.snapshotCopy.kmsKeyId || "",
380
+ }
381
+ },
382
+ }, {
383
+ provider: provider,
384
+ dependsOn: [snapshotLogGroup, snapshotLambdaPolicy]
385
+ });
386
+ const snapshotLambdaPermission = new aws.lambda.Permission(`${config.meta.environment}-${config.id}-snapshot-lambda-permission`, {
387
+ action: "lambda:InvokeFunction",
388
+ function: snapshotLambda.name,
389
+ principal: "events.amazonaws.com",
390
+ sourceArn: snapshotRule.arn,
391
+ }, provider ? { provider } : undefined);
392
+ const snapshotTarget = new aws.cloudwatch.EventTarget(`${config.meta.environment}-${config.id}-snapshot-target`, {
393
+ rule: snapshotRule.name,
394
+ targetId: "SnapshotCopyTarget",
395
+ arn: snapshotLambda.arn,
396
+ }, provider ? { provider } : undefined);
397
+ }
398
+ if (backupConfig.crossRegionBackups?.enabled && backupConfig.enableLambdaBackups !== false) {
399
+ const backupProvider = new aws.Provider(`${config.meta.environment}-${config.id}-backup-provider`, {
400
+ region: resolvedBackupRegion,
401
+ profile: aws.config.profile,
402
+ allowedAccountIds: aws.config.allowedAccountIds,
403
+ });
404
+ const backupRule = new aws.cloudwatch.EventRule(`${config.meta.environment}-${config.id}-backup-rule`, {
405
+ name: `${config.meta.environment}-${config.id}-cross-region-backup`,
406
+ description: `Automated cross-region backup for Aurora cluster`,
407
+ scheduleExpression: `cron(0 1 * * ? *)`,
408
+ state: "ENABLED",
409
+ }, provider ? { provider } : undefined);
410
+ const backupLogGroup = new aws.cloudwatch.LogGroup(`${config.meta.environment}-${config.id}-backup-logs`, {
411
+ name: `/aws/lambda/${config.meta.environment}-${config.id}-aurora-backup`,
412
+ retentionInDays: 365,
413
+ }, provider ? { provider } : undefined);
414
+ const backupLambdaRole = new aws.iam.Role(`${config.meta.environment}-${config.id}-backup-lambda-role`, {
415
+ assumeRolePolicy: JSON.stringify({
416
+ Version: "2012-10-17",
417
+ Statement: [
418
+ {
419
+ Action: "sts:AssumeRole",
420
+ Effect: "Allow",
421
+ Principal: {
422
+ Service: "lambda.amazonaws.com"
423
+ }
424
+ }
425
+ ]
426
+ })
427
+ }, provider ? { provider } : undefined);
428
+ const backupLambdaPolicy = new aws.iam.RolePolicy(`${config.meta.environment}-${config.id}-backup-lambda-policy`, {
429
+ role: backupLambdaRole.id,
430
+ policy: JSON.stringify({
431
+ Version: "2012-10-17",
432
+ Statement: [
433
+ {
434
+ Effect: "Allow",
435
+ Action: [
436
+ "logs:CreateLogGroup",
437
+ "logs:CreateLogStream",
438
+ "logs:PutLogEvents"
439
+ ],
440
+ Resource: "arn:aws:logs:*:*:*"
441
+ },
442
+ {
443
+ Effect: "Allow",
444
+ Action: [
445
+ "rds:DescribeDBClusters",
446
+ "rds:DescribeDBClusterSnapshots",
447
+ "rds:CreateDBClusterSnapshot",
448
+ "rds:CopyDBClusterSnapshot",
449
+ "rds:DeleteDBClusterSnapshot",
450
+ "rds:RestoreDBClusterFromSnapshot",
451
+ "rds:DescribeDBClusterBackups"
452
+ ],
453
+ Resource: "*"
454
+ },
455
+ {
456
+ Effect: "Allow",
457
+ Action: [
458
+ "kms:Decrypt",
459
+ "kms:DescribeKey",
460
+ "kms:Encrypt",
461
+ "kms:GenerateDataKey*",
462
+ "kms:ReEncrypt*"
463
+ ],
464
+ Resource: "*"
465
+ }
466
+ ]
467
+ })
468
+ }, provider ? { provider } : undefined);
469
+ const backupLambda = new aws.lambda.Function(`${config.meta.environment}-${config.id}-backup-lambda`, {
470
+ name: `${config.meta.environment}-${config.id}-aurora-backup`,
471
+ role: backupLambdaRole.arn,
472
+ handler: "index.handler",
473
+ runtime: "python3.9",
474
+ timeout: 600,
475
+ code: new pulumi.asset.AssetArchive({
476
+ "index.py": new pulumi.asset.StringAsset(`
477
+ import boto3
478
+ import json
479
+ import os
480
+ from datetime import datetime, timedelta
481
+ def handler(event, context):
482
+ cluster_id = os.environ['CLUSTER_ID']
483
+ backup_region = os.environ['BACKUP_REGION']
484
+ retention_days = int(os.environ.get('RETENTION_DAYS', '7'))
485
+ # Create RDS clients for both regions
486
+ source_rds = boto3.client('rds')
487
+ target_rds = boto3.client('rds', region_name=backup_region)
488
+ try:
489
+ # Get cluster info
490
+ cluster_info = source_rds.describe_db_clusters(
491
+ DBClusterIdentifier=cluster_id
492
+ )['DBClusters'][0]
493
+ # Create cross-region automated backup snapshot
494
+ timestamp = datetime.now().strftime('%Y-%m-%d-%H-%M-%S')
495
+ backup_id = f"{cluster_id}-auto-backup-{timestamp}"
496
+ print(f"Creating automated backup {backup_id} for cluster {cluster_id}")
497
+ # Create snapshot in source region
498
+ source_rds.create_db_cluster_snapshot(
499
+ DBClusterSnapshotIdentifier=backup_id,
500
+ DBClusterIdentifier=cluster_id,
501
+ Tags=[
502
+ {
503
+ 'Key': 'BackupType',
504
+ 'Value': 'CrossRegionAutomated'
505
+ },
506
+ {
507
+ 'Key': 'SourceRegion',
508
+ 'Value': os.environ.get('AWS_REGION', 'eu-central-1')
509
+ },
510
+ {
511
+ 'Key': 'CreatedBy',
512
+ 'Value': 'Aurora-CrossRegion-Backup-Lambda'
513
+ }
514
+ ]
515
+ )
516
+ # Wait for snapshot to be available
517
+ waiter = source_rds.get_waiter('db_cluster_snapshot_completed')
518
+ waiter.wait(
519
+ DBClusterSnapshotIdentifier=backup_id,
520
+ WaiterConfig={'Delay': 30, 'MaxAttempts': 60}
521
+ )
522
+ # Copy to backup region
523
+ source_snapshot_arn = f"arn:aws:rds:eu-central-1:{context.invoked_function_arn.split(':')[4]}:cluster-snapshot:{backup_id}"
524
+ target_backup_id = f"{cluster_id}-cross-region-{timestamp}"
525
+ print(f"Copying backup to {backup_region} as {target_backup_id}")
526
+ copy_params = {
527
+ 'SourceDBClusterSnapshotIdentifier': source_snapshot_arn,
528
+ 'TargetDBClusterSnapshotIdentifier': target_backup_id,
529
+ 'CopyTags': True,
530
+ 'Tags': [
531
+ {
532
+ 'Key': 'BackupType',
533
+ 'Value': 'CrossRegionAutomated'
534
+ },
535
+ {
536
+ 'Key': 'SourceRegion',
537
+ 'Value': os.environ.get('AWS_REGION', 'eu-central-1')
538
+ }
539
+ ]
540
+ }
541
+ # Add KMS key if provided for encrypted snapshots
542
+ target_kms_key = os.environ.get('TARGET_KMS_KEY_ID')
543
+ if target_kms_key:
544
+ copy_params['KmsKeyId'] = target_kms_key
545
+ print(f"Using KMS key for cross-region encryption: {target_kms_key}")
546
+ target_rds.copy_db_cluster_snapshot(**copy_params)
547
+ # Clean up old automated backups in backup region
548
+ cutoff_date = datetime.now() - timedelta(days=retention_days)
549
+ snapshots = target_rds.describe_db_cluster_snapshots(
550
+ SnapshotType='manual',
551
+ DBClusterIdentifier=cluster_id
552
+ )
553
+ for snapshot in snapshots['DBClusterSnapshots']:
554
+ if (snapshot['DBClusterSnapshotIdentifier'].startswith(f"{cluster_id}-cross-region-") and
555
+ snapshot['SnapshotCreateTime'].replace(tzinfo=None) < cutoff_date):
556
+ print(f"Deleting old backup {snapshot['DBClusterSnapshotIdentifier']}")
557
+ target_rds.delete_db_cluster_snapshot(
558
+ DBClusterSnapshotIdentifier=snapshot['DBClusterSnapshotIdentifier']
559
+ )
560
+ return {
561
+ 'statusCode': 200,
562
+ 'body': json.dumps({
563
+ 'message': f'Successfully created cross-region backup {target_backup_id}',
564
+ 'sourceSnapshot': backup_id,
565
+ 'targetSnapshot': target_backup_id,
566
+ 'backupRegion': backup_region
567
+ })
568
+ }
569
+ except Exception as e:
570
+ print(f"Error in cross-region backup: {str(e)}")
571
+ return {
572
+ 'statusCode': 500,
573
+ 'body': json.dumps(f'Error: {str(e)}')
574
+ }
575
+ `)
576
+ }),
577
+ environment: {
578
+ variables: {
579
+ CLUSTER_ID: cluster.clusterIdentifier,
580
+ BACKUP_REGION: resolvedBackupRegion,
581
+ RETENTION_DAYS: (backupConfig.crossRegionBackups.retentionPeriod || 7).toString(),
582
+ TARGET_KMS_KEY_ID: backupConfig.crossRegionBackups.kmsKeyId || "",
583
+ }
584
+ },
585
+ }, {
586
+ provider: provider,
587
+ dependsOn: [backupLogGroup, backupLambdaPolicy]
588
+ });
589
+ const backupLambdaPermission = new aws.lambda.Permission(`${config.meta.environment}-${config.id}-backup-lambda-permission`, {
590
+ action: "lambda:InvokeFunction",
591
+ function: backupLambda.name,
592
+ principal: "events.amazonaws.com",
593
+ sourceArn: backupRule.arn,
594
+ }, provider ? { provider } : undefined);
595
+ const backupTarget = new aws.cloudwatch.EventTarget(`${config.meta.environment}-${config.id}-backup-target`, {
596
+ rule: backupRule.name,
597
+ targetId: "CrossRegionBackupTarget",
598
+ arn: backupLambda.arn,
599
+ }, provider ? { provider } : undefined);
600
+ }
601
+ }
602
+ buildDataProtectionPolicy(dataProtectionConfig, logGroupName) {
603
+ return (0, dataProtectionPolicyBuilder_1.buildDataProtectionPolicy)(dataProtectionConfig, logGroupName, dataProtectionPolicyBuilder_1.DEFAULT_DATA_IDENTIFIERS.DATABASE_LOGS, "Aurora");
604
+ }
605
+ getOutputs(resource) {
606
+ return {
607
+ id: resource.id,
608
+ endpoint: resource.endpoint,
609
+ arn: resource.arn,
610
+ sgId: resource.vpcSecurityGroupIds,
611
+ subnetGroupName: resource.dbSubnetGroupName,
612
+ clusterId: resource.clusterIdentifier,
613
+ };
614
+ }
615
+ validateConfig(config) {
616
+ (0, validateAuroraConfig_1.validateAuroraConfig)(config);
617
+ }
618
+ }
619
+ exports.AuroraFactory = AuroraFactory;