@fjall/components-infrastructure 0.73.17 → 0.74.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/dist/lib/__tests__/patterns/__snapshots__/compute.test.js.snap +433 -0
- package/dist/lib/__tests__/patterns/compute.test.d.ts +1 -0
- package/dist/lib/__tests__/patterns/compute.test.js +137 -0
- package/dist/lib/__tests__/simple.test.d.ts +0 -0
- package/dist/lib/__tests__/simple.test.js +12 -0
- package/dist/lib/config/aws/disasterRecovery.d.ts +27 -0
- package/dist/lib/config/aws/disasterRecovery.js +227 -0
- package/dist/lib/patterns/aws/managedAccount.js +15 -2
- package/dist/lib/resources/aws/backup/backupPlan.d.ts +19 -0
- package/dist/lib/resources/aws/backup/backupPlan.js +71 -0
- package/dist/lib/resources/aws/backup/backupVault.d.ts +19 -0
- package/dist/lib/resources/aws/backup/backupVault.js +43 -0
- package/dist/lib/resources/aws/backup/index.d.ts +2 -0
- package/dist/lib/resources/aws/backup/index.js +19 -0
- package/dist/lib/resources/aws/index.d.ts +1 -0
- package/dist/lib/resources/aws/index.js +2 -1
- package/dist/lib/resources/aws/organisations/account.d.ts +37 -0
- package/dist/lib/resources/aws/organisations/account.js +220 -0
- package/dist/lib/resources/aws/organisations/delegatedAdministrator.d.ts +14 -0
- package/dist/lib/resources/aws/organisations/delegatedAdministrator.js +61 -0
- package/dist/lib/resources/aws/organisations/index.d.ts +8 -0
- package/dist/lib/resources/aws/organisations/index.js +22 -0
- package/dist/lib/resources/aws/organisations/interfaces.d.ts +105 -0
- package/dist/lib/resources/aws/organisations/interfaces.js +3 -0
- package/dist/lib/resources/aws/organisations/organisation.d.ts +47 -0
- package/dist/lib/resources/aws/organisations/organisation.js +263 -0
- package/dist/lib/resources/aws/organisations/organisationalUnit.d.ts +28 -0
- package/dist/lib/resources/aws/organisations/organisationalUnit.js +170 -0
- package/dist/lib/resources/aws/organisations/policy.d.ts +17 -0
- package/dist/lib/resources/aws/organisations/policy.js +93 -0
- package/dist/lib/resources/aws/organisations/trustedServiceAccess.d.ts +13 -0
- package/dist/lib/resources/aws/organisations/trustedServiceAccess.js +58 -0
- package/dist/lib/resources/aws/organisations/types.d.ts +165 -0
- package/dist/lib/resources/aws/organisations/types.js +36 -0
- package/dist/lib/utils/directTagging.d.ts +31 -0
- package/dist/lib/utils/directTagging.js +86 -0
- package/dist/lib/utils/fjallConstruct.d.ts +8 -0
- package/dist/lib/utils/fjallConstruct.js +18 -0
- package/dist/lib/utils/fjallStackSynthesizer.d.ts +9 -0
- package/dist/lib/utils/fjallStackSynthesizer.js +22 -0
- package/dist/lib/utils/getConfig.d.ts +1 -0
- package/dist/lib/utils/getConfig.js +2 -1
- package/dist/lib/utils/tagContext.d.ts +28 -0
- package/dist/lib/utils/tagContext.js +53 -0
- package/dist/lib/utils/tagSynthesizer.d.ts +13 -0
- package/dist/lib/utils/tagSynthesizer.js +55 -0
- package/package.json +3 -3
- package/dist/lib/patterns/aws/ec2.d.ts +0 -43
- package/dist/lib/patterns/aws/ec2.js +0 -123
- package/dist/lib/utils/getCidr.d.ts +0 -8
- package/dist/lib/utils/getCidr.js +0 -40
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DisasterRecovery = void 0;
|
|
4
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
5
|
+
const constructs_1 = require("constructs");
|
|
6
|
+
const backup_1 = require("../../resources/aws/backup");
|
|
7
|
+
const aws_backup_1 = require("aws-cdk-lib/aws-backup");
|
|
8
|
+
const events = require("aws-cdk-lib/aws-events");
|
|
9
|
+
const aws_iam_1 = require("aws-cdk-lib/aws-iam");
|
|
10
|
+
const util_1 = require("@fjall/util");
|
|
11
|
+
// Backup retention constants (in days)
|
|
12
|
+
const RETENTION_PERIODS = {
|
|
13
|
+
STANDARD: 90,
|
|
14
|
+
RESILIENT: 365,
|
|
15
|
+
ENTERPRISE_CONTINUOUS: 35, // AWS max for continuous backup
|
|
16
|
+
ENTERPRISE_COMPLIANCE: 2555, // 7 years
|
|
17
|
+
COLD_STORAGE_MINIMUM: 90, // AWS minimum
|
|
18
|
+
COLD_STORAGE_ONE_YEAR: 365
|
|
19
|
+
};
|
|
20
|
+
class DisasterRecovery extends constructs_1.Construct {
|
|
21
|
+
constructor(scope, id, props) {
|
|
22
|
+
super(scope, id);
|
|
23
|
+
const fjallConfig = util_1.Config.loadConfig();
|
|
24
|
+
// Determine if this is a compliance account
|
|
25
|
+
const account = fjallConfig.getProviderAccountById(props.accountId);
|
|
26
|
+
const isComplianceAccount = account?.environment === "compliance";
|
|
27
|
+
// Get DR configuration
|
|
28
|
+
const disasterRecoveryRegion = fjallConfig.getDisasterRecoveryRegion();
|
|
29
|
+
// Look up compliance account for cross-account replication
|
|
30
|
+
// Skip if the compliance account (prevent self-replication)
|
|
31
|
+
const disasterRecoveryAccount = isComplianceAccount
|
|
32
|
+
? undefined
|
|
33
|
+
: fjallConfig.getAccountByEnvironment("compliance");
|
|
34
|
+
// Construct cross-account DR vault ARN (compliance account in DR region)
|
|
35
|
+
const disasterRecoveryVaultArn = disasterRecoveryAccount && disasterRecoveryRegion
|
|
36
|
+
? `arn:aws:backup:${disasterRecoveryRegion}:${disasterRecoveryAccount.id}:backup-vault:backupVault`
|
|
37
|
+
: undefined;
|
|
38
|
+
// Compliance accounts get vault locks for protection
|
|
39
|
+
const lockConfiguration = isComplianceAccount
|
|
40
|
+
? {
|
|
41
|
+
minRetention: aws_cdk_lib_1.Duration.days(365), // Minimum 1 year retention
|
|
42
|
+
maxRetention: aws_cdk_lib_1.Duration.days(36500), // Maximum ~100 years
|
|
43
|
+
changeableFor: aws_cdk_lib_1.Duration.days(3) // 3-day grace period to modify lock
|
|
44
|
+
}
|
|
45
|
+
: undefined;
|
|
46
|
+
// Create primary backup vault
|
|
47
|
+
this.backupVault = new backup_1.BackupVault(this, "BackupVault", {
|
|
48
|
+
vaultName: "backupVault",
|
|
49
|
+
removalPolicy: aws_cdk_lib_1.RemovalPolicy.RETAIN,
|
|
50
|
+
lockConfiguration: lockConfiguration
|
|
51
|
+
});
|
|
52
|
+
// Configure cross-account access policies
|
|
53
|
+
if (disasterRecoveryAccount) {
|
|
54
|
+
// Production vaults: Allow compliance account to restore FROM this vault
|
|
55
|
+
const restoreStatement = new aws_iam_1.PolicyStatement({
|
|
56
|
+
effect: aws_iam_1.Effect.ALLOW,
|
|
57
|
+
principals: [new aws_iam_1.AccountPrincipal(disasterRecoveryAccount.id)],
|
|
58
|
+
actions: [
|
|
59
|
+
"backup:DescribeBackupVault",
|
|
60
|
+
"backup:ListRecoveryPointsByBackupVault",
|
|
61
|
+
"backup:GetRecoveryPointRestoreMetadata",
|
|
62
|
+
"backup:StartRestoreJob",
|
|
63
|
+
"backup:DescribeRestoreJob"
|
|
64
|
+
],
|
|
65
|
+
resources: ["*"]
|
|
66
|
+
});
|
|
67
|
+
this.backupVault.vault.addToAccessPolicy(restoreStatement);
|
|
68
|
+
}
|
|
69
|
+
if (isComplianceAccount) {
|
|
70
|
+
// Compliance vaults: Allow production accounts to copy TO this vault
|
|
71
|
+
const allAccounts = fjallConfig.rootConfig.providerAccounts || [];
|
|
72
|
+
const productionAccounts = allAccounts.filter((acc) => acc.environment === "production");
|
|
73
|
+
if (productionAccounts.length > 0) {
|
|
74
|
+
const copyStatement = new aws_iam_1.PolicyStatement({
|
|
75
|
+
effect: aws_iam_1.Effect.ALLOW,
|
|
76
|
+
principals: productionAccounts.map((acc) => new aws_iam_1.AccountPrincipal(acc.id)),
|
|
77
|
+
actions: ["backup:CopyIntoBackupVault"],
|
|
78
|
+
resources: ["*"]
|
|
79
|
+
});
|
|
80
|
+
this.backupVault.vault.addToAccessPolicy(copyStatement);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// Construct cross-region replication vault ARN (same account, DR region)
|
|
84
|
+
// Only replicate if DR region exists AND is different from current region
|
|
85
|
+
const replicationVaultArn = disasterRecoveryRegion && disasterRecoveryRegion !== props.region
|
|
86
|
+
? `arn:aws:backup:${disasterRecoveryRegion}:${props.accountId}:backup-vault:backupVault`
|
|
87
|
+
: undefined;
|
|
88
|
+
// Create all three backup plans
|
|
89
|
+
this.backupPlans = {
|
|
90
|
+
standard: new backup_1.BackupPlan(this, "StandardBackupPlan", {
|
|
91
|
+
planName: "standard",
|
|
92
|
+
rules: this.createStandardBackupRules("standard"),
|
|
93
|
+
tagValue: "default",
|
|
94
|
+
backupVault: this.backupVault
|
|
95
|
+
}),
|
|
96
|
+
resilient: new backup_1.BackupPlan(this, "ResilientBackupPlan", {
|
|
97
|
+
planName: "resilient",
|
|
98
|
+
rules: this.createResilientBackupRules("resilient", replicationVaultArn),
|
|
99
|
+
tagValue: "resilient",
|
|
100
|
+
backupVault: this.backupVault
|
|
101
|
+
}),
|
|
102
|
+
enterprise: new backup_1.BackupPlan(this, "EnterpriseBackupPlan", {
|
|
103
|
+
planName: "enterprise",
|
|
104
|
+
rules: this.createEnterpriseBackupRules("enterprise", replicationVaultArn, disasterRecoveryVaultArn),
|
|
105
|
+
tagValue: "enterprise",
|
|
106
|
+
backupVault: this.backupVault
|
|
107
|
+
})
|
|
108
|
+
};
|
|
109
|
+
// Create custom backup plans if provided
|
|
110
|
+
if (props.customBackupPlans && props.customBackupPlans.length > 0) {
|
|
111
|
+
this.customBackupPlans = props.customBackupPlans.map((config, index) => {
|
|
112
|
+
return new backup_1.BackupPlan(this, `CustomBackupPlan${index}`, {
|
|
113
|
+
planName: config.planName,
|
|
114
|
+
rules: config.rules,
|
|
115
|
+
tagValue: config.tagValue,
|
|
116
|
+
backupVault: this.backupVault
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
// Export disaster recovery configuration
|
|
121
|
+
new aws_cdk_lib_1.CfnOutput(this, "DisasterRecoveryEnabled", {
|
|
122
|
+
key: "DisasterRecoveryEnabled",
|
|
123
|
+
value: "true",
|
|
124
|
+
exportName: "DisasterRecoveryEnabled"
|
|
125
|
+
});
|
|
126
|
+
if (disasterRecoveryRegion) {
|
|
127
|
+
new aws_cdk_lib_1.CfnOutput(this, "ReplicationRegion", {
|
|
128
|
+
key: "ReplicationRegion",
|
|
129
|
+
value: disasterRecoveryRegion,
|
|
130
|
+
exportName: "BackupReplicationRegion"
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
if (isComplianceAccount) {
|
|
134
|
+
new aws_cdk_lib_1.CfnOutput(this, "VaultLockEnabled", {
|
|
135
|
+
key: "VaultLockEnabled",
|
|
136
|
+
value: "true",
|
|
137
|
+
exportName: "VaultLockEnabled"
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
createStandardBackupRules(planName) {
|
|
142
|
+
return [
|
|
143
|
+
new aws_backup_1.BackupPlanRule({
|
|
144
|
+
ruleName: `${planName}Daily`,
|
|
145
|
+
scheduleExpression: events.Schedule.cron({ hour: "2", minute: "0" }), // 2 AM daily
|
|
146
|
+
deleteAfter: aws_cdk_lib_1.Duration.days(RETENTION_PERIODS.STANDARD),
|
|
147
|
+
startWindow: aws_cdk_lib_1.Duration.minutes(60),
|
|
148
|
+
completionWindow: aws_cdk_lib_1.Duration.hours(12)
|
|
149
|
+
})
|
|
150
|
+
];
|
|
151
|
+
}
|
|
152
|
+
createResilientBackupRules(planName, replicationVaultArn) {
|
|
153
|
+
const copyActions = this.createCopyActions(planName, replicationVaultArn, undefined, aws_cdk_lib_1.Duration.days(RETENTION_PERIODS.RESILIENT), aws_cdk_lib_1.Duration.days(RETENTION_PERIODS.COLD_STORAGE_MINIMUM));
|
|
154
|
+
return [
|
|
155
|
+
new aws_backup_1.BackupPlanRule({
|
|
156
|
+
ruleName: `${planName}Daily`,
|
|
157
|
+
scheduleExpression: events.Schedule.cron({ hour: "2", minute: "0" }), // 2 AM daily
|
|
158
|
+
deleteAfter: aws_cdk_lib_1.Duration.days(RETENTION_PERIODS.RESILIENT),
|
|
159
|
+
moveToColdStorageAfter: aws_cdk_lib_1.Duration.days(RETENTION_PERIODS.COLD_STORAGE_MINIMUM),
|
|
160
|
+
enableContinuousBackup: true,
|
|
161
|
+
startWindow: aws_cdk_lib_1.Duration.minutes(60),
|
|
162
|
+
completionWindow: aws_cdk_lib_1.Duration.hours(12),
|
|
163
|
+
copyActions
|
|
164
|
+
})
|
|
165
|
+
];
|
|
166
|
+
}
|
|
167
|
+
createEnterpriseBackupRules(planName, replicationVaultArn, disasterRecoveryVaultArn) {
|
|
168
|
+
const continuousCopyActions = this.createCopyActions(planName, replicationVaultArn, disasterRecoveryVaultArn, aws_cdk_lib_1.Duration.days(RETENTION_PERIODS.ENTERPRISE_CONTINUOUS), undefined);
|
|
169
|
+
const complianceCopyActions = this.createCopyActions(planName, replicationVaultArn, disasterRecoveryVaultArn, aws_cdk_lib_1.Duration.days(RETENTION_PERIODS.ENTERPRISE_COMPLIANCE), aws_cdk_lib_1.Duration.days(RETENTION_PERIODS.COLD_STORAGE_ONE_YEAR));
|
|
170
|
+
return [
|
|
171
|
+
// Continuous backup (35-day max PITR window)
|
|
172
|
+
new aws_backup_1.BackupPlanRule({
|
|
173
|
+
ruleName: `${planName}Continuous`,
|
|
174
|
+
scheduleExpression: events.Schedule.cron({ hour: "2", minute: "0" }), // Daily for continuous backup
|
|
175
|
+
deleteAfter: aws_cdk_lib_1.Duration.days(RETENTION_PERIODS.ENTERPRISE_CONTINUOUS),
|
|
176
|
+
enableContinuousBackup: true,
|
|
177
|
+
startWindow: aws_cdk_lib_1.Duration.minutes(60),
|
|
178
|
+
completionWindow: aws_cdk_lib_1.Duration.hours(12),
|
|
179
|
+
copyActions: continuousCopyActions
|
|
180
|
+
}),
|
|
181
|
+
// Hourly snapshots for long-term compliance (7 years)
|
|
182
|
+
new aws_backup_1.BackupPlanRule({
|
|
183
|
+
ruleName: `${planName}HourlyCompliance`,
|
|
184
|
+
scheduleExpression: events.Schedule.cron({ minute: "0" }), // Every hour
|
|
185
|
+
deleteAfter: aws_cdk_lib_1.Duration.days(RETENTION_PERIODS.ENTERPRISE_COMPLIANCE),
|
|
186
|
+
moveToColdStorageAfter: aws_cdk_lib_1.Duration.days(RETENTION_PERIODS.COLD_STORAGE_ONE_YEAR),
|
|
187
|
+
startWindow: aws_cdk_lib_1.Duration.minutes(60),
|
|
188
|
+
completionWindow: aws_cdk_lib_1.Duration.hours(2),
|
|
189
|
+
copyActions: complianceCopyActions
|
|
190
|
+
})
|
|
191
|
+
];
|
|
192
|
+
}
|
|
193
|
+
createCopyActions(planName, replicationVaultArn, disasterRecoveryVaultArn, deleteAfter, moveToColdStorageAfter) {
|
|
194
|
+
const actions = [];
|
|
195
|
+
// Cross-region replication
|
|
196
|
+
if (replicationVaultArn) {
|
|
197
|
+
const replicationAction = {
|
|
198
|
+
destinationBackupVault: aws_backup_1.BackupVault.fromBackupVaultArn(this, `${planName}ReplicationVaultRef`, replicationVaultArn),
|
|
199
|
+
...(deleteAfter && { deleteAfter }),
|
|
200
|
+
// Only add cold storage if specified and >= 90 days
|
|
201
|
+
...(moveToColdStorageAfter &&
|
|
202
|
+
moveToColdStorageAfter.toDays() >=
|
|
203
|
+
RETENTION_PERIODS.COLD_STORAGE_MINIMUM
|
|
204
|
+
? { moveToColdStorageAfter }
|
|
205
|
+
: {})
|
|
206
|
+
};
|
|
207
|
+
actions.push(replicationAction);
|
|
208
|
+
}
|
|
209
|
+
// Cross-account DR vault
|
|
210
|
+
if (disasterRecoveryVaultArn) {
|
|
211
|
+
const drAction = {
|
|
212
|
+
destinationBackupVault: aws_backup_1.BackupVault.fromBackupVaultArn(this, `${planName}DisasterRecoveryVaultRef`, disasterRecoveryVaultArn),
|
|
213
|
+
...(deleteAfter && { deleteAfter }),
|
|
214
|
+
// Only add cold storage if specified and >= 90 days
|
|
215
|
+
...(moveToColdStorageAfter &&
|
|
216
|
+
moveToColdStorageAfter.toDays() >=
|
|
217
|
+
RETENTION_PERIODS.COLD_STORAGE_MINIMUM
|
|
218
|
+
? { moveToColdStorageAfter }
|
|
219
|
+
: {})
|
|
220
|
+
};
|
|
221
|
+
actions.push(drAction);
|
|
222
|
+
}
|
|
223
|
+
return actions.length > 0 ? actions : undefined;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
exports.DisasterRecovery = DisasterRecovery;
|
|
227
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGlzYXN0ZXJSZWNvdmVyeS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2xpYi9jb25maWcvYXdzL2Rpc2FzdGVyUmVjb3ZlcnkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsNkNBQWlFO0FBQ2pFLDJDQUF1QztBQUN2Qyx1REFBcUU7QUFDckUsdURBSWdDO0FBQ2hDLGlEQUFpRDtBQUNqRCxpREFBZ0Y7QUFDaEYsc0NBQW9EO0FBRXBELHVDQUF1QztBQUN2QyxNQUFNLGlCQUFpQixHQUFHO0lBQ3hCLFFBQVEsRUFBRSxFQUFFO0lBQ1osU0FBUyxFQUFFLEdBQUc7SUFDZCxxQkFBcUIsRUFBRSxFQUFFLEVBQUUsZ0NBQWdDO0lBQzNELHFCQUFxQixFQUFFLElBQUksRUFBRSxVQUFVO0lBQ3ZDLG9CQUFvQixFQUFFLEVBQUUsRUFBRSxjQUFjO0lBQ3hDLHFCQUFxQixFQUFFLEdBQUc7Q0FDbEIsQ0FBQztBQWNYLE1BQWEsZ0JBQWlCLFNBQVEsc0JBQVM7SUFTN0MsWUFBWSxLQUFnQixFQUFFLEVBQVUsRUFBRSxLQUE0QjtRQUNwRSxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBRWpCLE1BQU0sV0FBVyxHQUFHLGFBQVcsQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUU3Qyw0Q0FBNEM7UUFDNUMsTUFBTSxPQUFPLEdBQUcsV0FBVyxDQUFDLHNCQUFzQixDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUNwRSxNQUFNLG1CQUFtQixHQUFHLE9BQU8sRUFBRSxXQUFXLEtBQUssWUFBWSxDQUFDO1FBRWxFLHVCQUF1QjtRQUN2QixNQUFNLHNCQUFzQixHQUFHLFdBQVcsQ0FBQyx5QkFBeUIsRUFBRSxDQUFDO1FBRXZFLDJEQUEyRDtRQUMzRCw0REFBNEQ7UUFDNUQsTUFBTSx1QkFBdUIsR0FBRyxtQkFBbUI7WUFDakQsQ0FBQyxDQUFDLFNBQVM7WUFDWCxDQUFDLENBQUMsV0FBVyxDQUFDLHVC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QUN6QjtnQkFDRCxHQUFHLENBQUMsV0FBVyxJQUFJLEVBQUUsV0FBVyxFQUFFLENBQUM7Z0JBQ25DLG9EQUFvRDtnQkFDcEQsR0FBRyxDQUFDLHNCQUFzQjtvQkFDMUIsc0JBQXNCLENBQUMsTUFBTSxFQUFFO3dCQUM3QixpQkFBaUIsQ0FBQyxvQkFBb0I7b0JBQ3RDLENBQUMsQ0FBQyxFQUFFLHNCQUFzQixFQUFFO29CQUM1QixDQUFDLENBQUMsRUFBRSxDQUFDO2FBQ1IsQ0FBQztZQUNGLE9BQU8sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDekIsQ0FBQztRQUVELE9BQU8sT0FBTyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO0lBQ2xELENBQUM7Q0FDRjtBQXZTRCw0Q0F1U0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDZm5PdXRwdXQsIER1cmF0aW9uLCBSZW1vdmFsUG9saWN5IH0gZnJvbSBcImF3cy1jZGstbGliXCI7XG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tIFwiY29uc3RydWN0c1wiO1xuaW1wb3J0IHsgQmFja3VwVmF1bHQsIEJhY2t1cFBsYW4gfSBmcm9tIFwiLi4vLi4vcmVzb3VyY2VzL2F3cy9iYWNrdXBcIjtcbmltcG9ydCB7XG4gIEJhY2t1cFBsYW5SdWxlLFxuICBCYWNrdXBQbGFuQ29weUFjdGlvblByb3BzLFxuICBCYWNrdXBWYXVsdCBhcyBWYXVsdFxufSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWJhY2t1cFwiO1xuaW1wb3J0ICogYXMgZXZlbnRzIGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtZXZlbnRzXCI7XG5pbXBvcnQgeyBBY2NvdW50UHJpbmNpcGFsLCBFZmZlY3QsIFBvbGljeVN0YXRlbWVudCB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtaWFtXCI7XG5pbXBvcnQgeyBDb25maWcgYXMgRmphbGxDb25maWcgfSBmcm9tIFwiQGZqYWxsL3V0aWxcIjtcblxuLy8gQmFja3VwIHJldGVudGlvbiBjb25zdGFudHMgKGluIGRheXMpXG5jb25zdCBSRVRFTlRJT05fUEVSSU9EUyA9IHtcbiAgU1RBTkRBUkQ6IDkwLFxuICBSRVNJTElFTlQ6IDM2NSxcbiAgRU5URVJQUklTRV9DT05USU5VT1VTOiAzNSwgLy8gQVdTIG1heCBmb3IgY29udGludW91cyBiYWNrdXBcbiAgRU5URVJQUklTRV9DT01QTElBTkNFOiAyNTU1LCAvLyA3IHllYXJzXG4gIENPTERfU1RPUkFHRV9NSU5JTVVNOiA5MCwgLy8gQVdTIG1pbmltdW1cbiAgQ09MRF9TVE9SQUdFX09ORV9ZRUFSOiAzNjVcbn0gYXMgY29uc3Q7XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ3VzdG9tQmFja3VwUGxhbkNvbmZpZyB7XG4gIHBsYW5OYW1lOiBzdHJpbmc7XG4gIHJ1bGVzOiBCYWNrdXBQbGFuUnVsZVtdO1xuICB0YWdWYWx1ZTogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIERpc2FzdGVyUmVjb3ZlcnlQcm9wcyB7XG4gIHJlZ2lvbjogc3RyaW5nO1xuICBhY2NvdW50SWQ6IHN0cmluZztcbiAgY3VzdG9tQmFja3VwUGxhbnM/OiBDdXN0b21CYWNrdXBQbGFuQ29uZmlnW107XG59XG5cbmV4cG9ydCBjbGFzcyBEaXNhc3RlclJlY292ZXJ5IGV4dGVuZHMgQ29uc3RydWN0IHtcbiAgcHVibGljIHJlYWRvbmx5IGJhY2t1cFZhdWx0OiBCYWNrdXBWYXVsdDtcbiAgcHVibGljIHJlYWRvbmx5IGJhY2t1cFBsYW5zOiB7XG4gICAgc3RhbmRhcmQ6IEJhY2t1cFBsYW47XG4gICAgcmVzaWxpZW50OiBCYWNrdXBQbGFuO1xuICAgIGVudGVycHJpc2U6IEJhY2t1cFBsYW47XG4gIH07XG4gIHB1YmxpYyByZWFkb25seSBjdXN0b21CYWNrdXBQbGFucz86IEJhY2t1cFBsYW5bXTtcblxuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogRGlzYXN0ZXJSZWNvdmVyeVByb3BzKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkKTtcblxuICAgIGNvbnN0IGZqYWxsQ29uZmlnID0gRmphbGxDb25maWcubG9hZENvbmZpZygpO1xuXG4gICAgLy8gRGV0ZXJtaW5lIGlmIHRoaXMgaXMgYSBjb21wbGlhbmNlIGFjY291bnRcbiAgICBjb25zdCBhY2NvdW50ID0gZmphbGxDb25maWcuZ2V0UHJvdmlkZXJBY2NvdW50QnlJZChwcm9wcy5hY2NvdW50SWQpO1xuICAgIGNvbnN0IGlzQ29tcGxpYW5jZUFjY291bnQgPSBhY2NvdW50Py5lbnZpcm9ubWVudCA9PT0gXCJjb21wbGlhbmNlXCI7XG5cbiAgICAvLyBHZXQgRFIgY29uZmlndXJhdGlvblxuICAgIGNvbnN0IGRpc2FzdGVyUmVjb3ZlcnlSZWdpb24gPSBmamFsbENvbmZpZy5nZXREaXNhc3RlclJlY292ZXJ5UmVnaW9uKCk7XG5cbiAgICAvLyBMb29rIHVwIGNvbXBsaWFuY2UgYWNjb3VudCBmb3IgY3Jvc3MtYWNjb3VudCByZXBsaWNhdGlvblxuICAgIC8vIFNraXAgaWYgdGhlIGNvbXBsaWFuY2UgYWNjb3VudCAocHJldmVudCBzZWxmLXJlcGxpY2F0aW9uKVxuICAgIGNvbnN0IGRpc2FzdGVyUmVjb3ZlcnlBY2NvdW50ID0gaXNDb21wbGlhbmNlQWNjb3VudFxuICAgICAgPyB1bmRlZmluZWRcbiAgICAgIDogZmphbGxDb25maWcuZ2V0QWNjb3VudEJ5RW52aXJvbm1lbnQoXCJjb21wbGlhbmNlXCIpO1xuXG4gICAgLy8gQ29uc3RydWN0IGNyb3NzLWFjY291bnQgRFIgdmF1bHQgQVJOIChjb21wbGlhbmNlIGFjY291bnQgaW4gRFIgcmVnaW9uKVxuICAgIGNvbnN0IGRpc2FzdGVyUmVjb3ZlcnlWYXVsdEFybiA9XG4gICAgICBkaXNhc3RlclJlY292ZXJ5QWNjb3VudCAmJiBkaXNhc3RlclJlY292ZXJ5UmVnaW9uXG4gICAgICAgID8gYGFybjphd3M6YmFja3VwOiR7ZGlzYXN0ZXJSZWNvdmVyeVJlZ2lvbn06JHtkaXNhc3RlclJlY292ZXJ5QWNjb3VudC5pZH06YmFja3VwLXZhdWx0OmJhY2t1cFZhdWx0YFxuICAgICAgICA6IHVuZGVmaW5lZDtcblxuICAgIC8vIENvbXBsaWFuY2UgYWNjb3VudHMgZ2V0IHZhdWx0IGxvY2tzIGZvciBwcm90ZWN0aW9uXG4gICAgY29uc3QgbG9ja0NvbmZpZ3VyYXRpb24gPSBpc0NvbXBsaWFuY2VBY2NvdW50XG4gICAgICA/IHtcbiAgICAgICAgICBtaW5SZXRlbnRpb246IER1cmF0aW9uLmRheXMoMzY1KSwgLy8gTWluaW11bSAxIHllYXIgcmV0ZW50aW9uXG4gICAgICAgICAgbWF4UmV0ZW50aW9uOiBEdXJhdGlvbi5kYXlzKDM2NTAwKSwgLy8gTWF4aW11bSB+MTAwIHllYXJzXG4gICAgICAgICAgY2hhbmdlYWJsZUZvcjogRHVyYXRpb24uZGF5cygzKSAvLyAzLWRheSBncmFjZSBwZXJpb2QgdG8gbW9kaWZ5IGxvY2tcbiAgICAgICAgfVxuICAgICAgOiB1bmRlZmluZWQ7XG5cbiAgICAvLyBDcmVhdGUgcHJpbWFyeSBiYWNrdXAgdmF1bHRcbiAgICB0aGlzLmJhY2t1cFZhdWx0ID0gbmV3IEJhY2t1cFZhdWx0KHRoaXMsIFwiQmFja3VwVmF1bHRcIiwge1xuICAgICAgdmF1bHROYW1lOiBcImJhY2t1cFZhdWx0XCIsXG4gICAgICByZW1vdmFsUG9saWN5OiBSZW1vdmFsUG9saWN5LlJFVEFJTixcbiAgICAgIGxvY2tDb25maWd1cmF0aW9uOiBsb2NrQ29uZmlndXJhdGlvblxuICAgIH0pO1xuXG4gICAgLy8gQ29uZmlndXJlIGNyb3NzLWFjY291bnQgYWNjZXNzIHBvbGljaWVzXG4gICAgaWYgKGRpc2FzdGVyUmVjb3ZlcnlBY2NvdW50KSB7XG4gICAgICAvLyBQcm9kdWN0aW9uIHZhdWx0czogQWxsb3cgY29tcGxpYW5jZSBhY2NvdW50IHRvIHJlc3RvcmUgRlJPTSB0aGlzIHZhdWx0XG4gICAgICBjb25zdCByZXN0b3JlU3RhdGVtZW50ID0gbmV3IFBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgIGVmZmVjdDogRWZmZWN0LkFMTE9XLFxuICAgICAgICBwcmluY2lwYWxzOiBbbmV3IEFjY291bnRQcmluY2lwYWwoZGlzYXN0ZXJSZWNvdmVyeUFjY291bnQuaWQpXSxcbiAgICAgICAgYWN0aW9uczogW1xuICAgICAgICAgIFwiYmFja3VwOkRlc2NyaWJlQmFja3VwVmF1bHRcIixcbiAgICAgICAgICBcImJhY2t1cDpMaXN0UmVjb3ZlcnlQb2ludHNCeUJhY2t1cFZhdWx0XCIsXG4gICAgICAgICAgXCJiYWNrdXA6R2V0UmVjb3ZlcnlQb2ludFJlc3RvcmVNZXRhZGF0YVwiLFxuICAgICAgICAgIFwiYmFja3VwOlN0YXJ0UmVzdG9yZUpvYlwiLFxuICAgICAgICAgIFwiYmFja3VwOkRlc2NyaWJlUmVzdG9yZUpvYlwiXG4gICAgICAgIF0sXG4gICAgICAgIHJlc291cmNlczogW1wiKlwiXVxuICAgICAgfSk7XG4gICAgICB0aGlzLmJhY2t1cFZhdWx0LnZhdWx0LmFkZFRvQWNjZXNzUG9saWN5KHJlc3RvcmVTdGF0ZW1lbnQpO1xuICAgIH1cblxuICAgIGlmIChpc0NvbXBsaWFuY2VBY2NvdW50KSB7XG4gICAgICAvLyBDb21wbGlhbmNlIHZhdWx0czogQWxsb3cgcHJvZHVjdGlvbiBhY2NvdW50cyB0byBjb3B5IFRPIHRoaXMgdmF1bHRcbiAgICAgIGNvbnN0IGFsbEFjY291bnRzID0gZmphbGxDb25maWcucm9vdENvbmZpZy5wcm92aWRlckFjY291bnRzIHx8IFtdO1xuICAgICAgY29uc3QgcHJvZHVjdGlvbkFjY291bnRzID0gYWxsQWNjb3VudHMuZmlsdGVyKFxuICAgICAgICAoYWNjKSA9PiBhY2MuZW52aXJvbm1lbnQgPT09IFwicHJvZHVjdGlvblwiXG4gICAgICApO1xuXG4gICAgICBpZiAocHJvZHVjdGlvbkFjY291bnRzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgY29uc3QgY29weVN0YXRlbWVudCA9IG5ldyBQb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICAgIGVmZmVjdDogRWZmZWN0LkFMTE9XLFxuICAgICAgICAgIHByaW5jaXBhbHM6IHByb2R1Y3Rpb25BY2NvdW50cy5tYXAoXG4gICAgICAgICAgICAoYWNjKSA9PiBuZXcgQWNjb3VudFByaW5jaXBhbChhY2MuaWQpXG4gICAgICAgICAgKSxcbiAgICAgICAgICBhY3Rpb25zOiBbXCJiYWNrdXA6Q29weUludG9CYWNrdXBWYXVsdFwiXSxcbiAgICAgICAgICByZXNvdXJjZXM6IFtcIipcIl1cbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuYmFja3VwVmF1bHQudmF1bHQuYWRkVG9BY2Nlc3NQb2xpY3koY29weVN0YXRlbWVudCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gQ29uc3RydWN0IGNyb3NzLXJlZ2lvbiByZXBsaWNhdGlvbiB2YXVsdCBBUk4gKHNhbWUgYWNjb3VudCwgRFIgcmVnaW9uKVxuICAgIC8vIE9ubHkgcmVwbGljYXRlIGlmIERSIHJlZ2lvbiBleGlzdHMgQU5EIGlzIGRpZmZlcmVudCBmcm9tIGN1cnJlbnQgcmVnaW9uXG4gICAgY29uc3QgcmVwbGljYXRpb25WYXVsdEFybiA9XG4gICAgICBkaXNhc3RlclJlY292ZXJ5UmVnaW9uICYmIGRpc2FzdGVyUmVjb3ZlcnlSZWdpb24gIT09IHByb3BzLnJlZ2lvblxuICAgICAgICA/IGBhcm46YXdzOmJhY2t1cDoke2Rpc2FzdGVyUmVjb3ZlcnlSZWdpb259OiR7cHJvcHMuYWNjb3VudElkfTpiYWNrdXAtdmF1bHQ6YmFja3VwVmF1bHRgXG4gICAgICAgIDogdW5kZWZpbmVkO1xuXG4gICAgLy8gQ3JlYXRlIGFsbCB0aHJlZSBiYWNrdXAgcGxhbnNcbiAgICB0aGlzLmJhY2t1cFBsYW5zID0ge1xuICAgICAgc3RhbmRhcmQ6IG5ldyBCYWNrdXBQbGFuKHRoaXMsIFwiU3RhbmRhcmRCYWNrdXBQbGFuXCIsIHtcbiAgICAgICAgcGxhbk5hbWU6IFwic3RhbmRhcmRcIixcbiAgICAgICAgcnVsZXM6IHRoaXMuY3JlYXRlU3RhbmRhcmRCYWNrdXBSdWxlcyhcInN0YW5kYXJkXCIpLFxuICAgICAgICB0YWdWYWx1ZTogXCJkZWZhdWx0XCIsXG4gICAgICAgIGJhY2t1cFZhdWx0OiB0aGlzLmJhY2t1cFZhdWx0XG4gICAgICB9KSxcbiAgICAgIHJlc2lsaWVudDogbmV3IEJhY2t1cFBsYW4odGhpcywgXCJSZXNpbGllbnRCYWNrdXBQbGFuXCIsIHtcbiAgICAgICAgcGxhbk5hbWU6IFwicmVzaWxpZW50XCIsXG4gICAgICAgIHJ1bGVzOiB0aGlzLmNyZWF0ZVJlc2lsaWVudEJhY2t1cFJ1bGVzKFxuICAgICAgICAgIFwicmVzaWxpZW50XCIsXG4gICAgICAgICAgcmVwbGljYXRpb25WYXVsdEFyblxuICAgICAgICApLFxuICAgICAgICB0YWdWYWx1ZTogXCJyZXNpbGllbnRcIixcbiAgICAgICAgYmFja3VwVmF1bHQ6IHRoaXMuYmFja3VwVmF1bHRcbiAgICAgIH0pLFxuICAgICAgZW50ZXJwcmlzZTogbmV3IEJhY2t1cFBsYW4odGhpcywgXCJFbnRlcnByaXNlQmFja3VwUGxhblwiLCB7XG4gICAgICAgIHBsYW5OYW1lOiBcImVudGVycHJpc2VcIixcbiAgICAgICAgcnVsZXM6IHRoaXMuY3JlYXRlRW50ZXJwcmlzZUJhY2t1cFJ1bGVzKFxuICAgICAgICAgIFwiZW50ZXJwcmlzZVwiLFxuICAgICAgICAgIHJlcGxpY2F0aW9uVmF1bHRBcm4sXG4gICAgICAgICAgZGlzYXN0ZXJSZWNvdmVyeVZhdWx0QXJuXG4gICAgICAgICksXG4gICAgICAgIHRhZ1ZhbHVlOiBcImVudGVycHJpc2VcIixcbiAgICAgICAgYmFja3VwVmF1bHQ6IHRoaXMuYmFja3VwVmF1bHRcbiAgICAgIH0pXG4gICAgfTtcblxuICAgIC8vIENyZWF0ZSBjdXN0b20gYmFja3VwIHBsYW5zIGlmIHByb3ZpZGVkXG4gICAgaWYgKHByb3BzLmN1c3RvbUJhY2t1cFBsYW5zICYmIHByb3BzLmN1c3RvbUJhY2t1cFBsYW5zLmxlbmd0aCA+IDApIHtcbiAgICAgIHRoaXMuY3VzdG9tQmFja3VwUGxhbnMgPSBwcm9wcy5jdXN0b21CYWNrdXBQbGFucy5tYXAoKGNvbmZpZywgaW5kZXgpID0+IHtcbiAgICAgICAgcmV0dXJuIG5ldyBCYWNrdXBQbGFuKHRoaXMsIGBDdXN0b21CYWNrdXBQbGFuJHtpbmRleH1gLCB7XG4gICAgICAgICAgcGxhbk5hbWU6IGNvbmZpZy5wbGFuTmFtZSxcbiAgICAgICAgICBydWxlczogY29uZmlnLnJ1bGVzLFxuICAgICAgICAgIHRhZ1ZhbHVlOiBjb25maWcudGFnVmFsdWUsXG4gICAgICAgICAgYmFja3VwVmF1bHQ6IHRoaXMuYmFja3VwVmF1bHRcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICAvLyBFeHBvcnQgZGlzYXN0ZXIgcmVjb3ZlcnkgY29uZmlndXJhdGlvblxuICAgIG5ldyBDZm5PdXRwdXQodGhpcywgXCJEaXNhc3RlclJlY292ZXJ5RW5hYmxlZFwiLCB7XG4gICAgICBrZXk6IFwiRGlzYXN0ZXJSZWNvdmVyeUVuYWJsZWRcIixcbiAgICAgIHZhbHVlOiBcInRydWVcIixcbiAgICAgIGV4cG9ydE5hbWU6IFwiRGlzYXN0ZXJSZWNvdmVyeUVuYWJsZWRcIlxuICAgIH0pO1xuXG4gICAgaWYgKGRpc2FzdGVyUmVjb3ZlcnlSZWdpb24pIHtcbiAgICAgIG5ldyBDZm5PdXRwdXQodGhpcywgXCJSZXBsaWNhdGlvblJlZ2lvblwiLCB7XG4gICAgICAgIGtleTogXCJSZXBsaWNhdGlvblJlZ2lvblwiLFxuICAgICAgICB2YWx1ZTogZGlzYXN0ZXJSZWNvdmVyeVJlZ2lvbixcbiAgICAgICAgZXhwb3J0TmFtZTogXCJCYWNrdXBSZXBsaWNhdGlvblJlZ2lvblwiXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAoaXNDb21wbGlhbmNlQWNjb3VudCkge1xuICAgICAgbmV3IENmbk91dHB1dCh0aGlzLCBcIlZhdWx0TG9ja0VuYWJsZWRcIiwge1xuICAgICAgICBrZXk6IFwiVmF1bHRMb2NrRW5hYmxlZFwiLFxuICAgICAgICB2YWx1ZTogXCJ0cnVlXCIsXG4gICAgICAgIGV4cG9ydE5hbWU6IFwiVmF1bHRMb2NrRW5hYmxlZFwiXG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGNyZWF0ZVN0YW5kYXJkQmFja3VwUnVsZXMocGxhbk5hbWU6IHN0cmluZyk6IEJhY2t1cFBsYW5SdWxlW10ge1xuICAgIHJldHVybiBbXG4gICAgICBuZXcgQmFja3VwUGxhblJ1bGUoe1xuICAgICAgICBydWxlTmFtZTogYCR7cGxhbk5hbWV9RGFpbHlgLFxuICAgICAgICBzY2hlZHVsZUV4cHJlc3Npb246IGV2ZW50cy5TY2hlZHVsZS5jcm9uKHsgaG91cjogXCIyXCIsIG1pbnV0ZTogXCIwXCIgfSksIC8vIDIgQU0gZGFpbHlcbiAgICAgICAgZGVsZXRlQWZ0ZXI6IER1cmF0aW9uLmRheXMoUkVURU5USU9OX1BFUklPRFMuU1RBTkRBUkQpLFxuICAgICAgICBzdGFydFdpbmRvdzogRHVyYXRpb24ubWludXRlcyg2MCksXG4gICAgICAgIGNvbXBsZXRpb25XaW5kb3c6IER1cmF0aW9uLmhvdXJzKDEyKVxuICAgICAgfSlcbiAgICBdO1xuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVSZXNpbGllbnRCYWNrdXBSdWxlcyhcbiAgICBwbGFuTmFtZTogc3RyaW5nLFxuICAgIHJlcGxpY2F0aW9uVmF1bHRBcm4/OiBzdHJpbmdcbiAgKTogQmFja3VwUGxhblJ1bGVbXSB7XG4gICAgY29uc3QgY29weUFjdGlvbnMgPSB0aGlzLmNyZWF0ZUNvcHlBY3Rpb25zKFxuICAgICAgcGxhbk5hbWUsXG4gICAgICByZXBsaWNhdGlvblZhdWx0QXJuLFxuICAgICAgdW5kZWZpbmVkLFxuICAgICAgRHVyYXRpb24uZGF5cyhSRVRFTlRJT05fUEVSSU9EUy5SRVNJTElFTlQpLFxuICAgICAgRHVyYXRpb24uZGF5cyhSRVRFTlRJT05fUEVSSU9EUy5DT0xEX1NUT1JBR0VfTUlOSU1VTSlcbiAgICApO1xuXG4gICAgcmV0dXJuIFtcbiAgICAgIG5ldyBCYWNrdXBQbGFuUnVsZSh7XG4gICAgICAgIHJ1bGVOYW1lOiBgJHtwbGFuTmFtZX1EYWlseWAsXG4gICAgICAgIHNjaGVkdWxlRXhwcmVzc2lvbjogZXZlbnRzLlNjaGVkdWxlLmNyb24oeyBob3VyOiBcIjJcIiwgbWludXRlOiBcIjBcIiB9KSwgLy8gMiBBTSBkYWlseVxuICAgICAgICBkZWxldGVBZnRlcjogRHVyYXRpb24uZGF5cyhSRVRFTlRJT05fUEVSSU9EUy5SRVNJTElFTlQpLFxuICAgICAgICBtb3ZlVG9Db2xkU3RvcmFnZUFmdGVyOiBEdXJhdGlvbi5kYXlzKFxuICAgICAgICAgIFJFVEVOVElPTl9QRVJJT0RTLkNPTERfU1RPUkFHRV9NSU5JTVVNXG4gICAgICAgICksXG4gICAgICAgIGVuYWJsZUNvbnRpbnVvdXNCYWNrdXA6IHRydWUsXG4gICAgICAgIHN0YXJ0V2luZG93OiBEdXJhdGlvbi5taW51dGVzKDYwKSxcbiAgICAgICAgY29tcGxldGlvbldpbmRvdzogRHVyYXRpb24uaG91cnMoMTIpLFxuICAgICAgICBjb3B5QWN0aW9uc1xuICAgICAgfSlcbiAgICBdO1xuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVFbnRlcnByaXNlQmFja3VwUnVsZXMoXG4gICAgcGxhbk5hbWU6IHN0cmluZyxcbiAgICByZXBsaWNhdGlvblZhdWx0QXJuPzogc3RyaW5nLFxuICAgIGRpc2FzdGVyUmVjb3ZlcnlWYXVsdEFybj86IHN0cmluZ1xuICApOiBCYWNrdXBQbGFuUnVsZVtdIHtcbiAgICBjb25zdCBjb250aW51b3VzQ29weUFjdGlvbnMgPSB0aGlzLmNyZWF0ZUNvcHlBY3Rpb25zKFxuICAgICAgcGxhbk5hbWUsXG4gICAgICByZXBsaWNhdGlvblZhdWx0QXJuLFxuICAgICAgZGlzYXN0ZXJSZWNvdmVyeVZhdWx0QXJuLFxuICAgICAgRHVyYXRpb24uZGF5cyhSRVRFTlRJT05fUEVSSU9EUy5FTlRFUlBSSVNFX0NPTlRJTlVPVVMpLFxuICAgICAgdW5kZWZpbmVkXG4gICAgKTtcblxuICAgIGNvbnN0IGNvbXBsaWFuY2VDb3B5QWN0aW9ucyA9IHRoaXMuY3JlYXRlQ29weUFjdGlvbnMoXG4gICAgICBwbGFuTmFtZSxcbiAgICAgIHJlcGxpY2F0aW9uVmF1bHRBcm4sXG4gICAgICBkaXNhc3RlclJlY292ZXJ5VmF1bHRBcm4sXG4gICAgICBEdXJhdGlvbi5kYXlzKFJFVEVOVElPTl9QRVJJT0RTLkVOVEVSUFJJU0VfQ09NUExJQU5DRSksXG4gICAgICBEdXJhdGlvbi5kYXlzKFJFVEVOVElPTl9QRVJJT0RTLkNPTERfU1RPUkFHRV9PTkVfWUVBUilcbiAgICApO1xuXG4gICAgcmV0dXJuIFtcbiAgICAgIC8vIENvbnRpbnVvdXMgYmFja3VwICgzNS1kYXkgbWF4IFBJVFIgd2luZG93KVxuICAgICAgbmV3IEJhY2t1cFBsYW5SdWxlKHtcbiAgICAgICAgcnVsZU5hbWU6IGAke3BsYW5OYW1lfUNvbnRpbnVvdXNgLFxuICAgICAgICBzY2hlZHVsZUV4cHJlc3Npb246IGV2ZW50cy5TY2hlZHVsZS5jcm9uKHsgaG91cjogXCIyXCIsIG1pbnV0ZTogXCIwXCIgfSksIC8vIERhaWx5IGZvciBjb250aW51b3VzIGJhY2t1cFxuICAgICAgICBkZWxldGVBZnRlcjogRHVyYXRpb24uZGF5cyhSRVRFTlRJT05fUEVSSU9EUy5FTlRFUlBSSVNFX0NPTlRJTlVPVVMpLFxuICAgICAgICBlbmFibGVDb250aW51b3VzQmFja3VwOiB0cnVlLFxuICAgICAgICBzdGFydFdpbmRvdzogRHVyYXRpb24ubWludXRlcyg2MCksXG4gICAgICAgIGNvbXBsZXRpb25XaW5kb3c6IER1cmF0aW9uLmhvdXJzKDEyKSxcbiAgICAgICAgY29weUFjdGlvbnM6IGNvbnRpbnVvdXNDb3B5QWN0aW9uc1xuICAgICAgfSksXG4gICAgICAvLyBIb3VybHkgc25hcHNob3RzIGZvciBsb25nLXRlcm0gY29tcGxpYW5jZSAoNyB5ZWFycylcbiAgICAgIG5ldyBCYWNrdXBQbGFuUnVsZSh7XG4gICAgICAgIHJ1bGVOYW1lOiBgJHtwbGFuTmFtZX1Ib3VybHlDb21wbGlhbmNlYCxcbiAgICAgICAgc2NoZWR1bGVFeHByZXNzaW9uOiBldmVudHMuU2NoZWR1bGUuY3Jvbih7IG1pbnV0ZTogXCIwXCIgfSksIC8vIEV2ZXJ5IGhvdXJcbiAgICAgICAgZGVsZXRlQWZ0ZXI6IER1cmF0aW9uLmRheXMoUkVURU5USU9OX1BFUklPRFMuRU5URVJQUklTRV9DT01QTElBTkNFKSxcbiAgICAgICAgbW92ZVRvQ29sZFN0b3JhZ2VBZnRlcjogRHVyYXRpb24uZGF5cyhcbiAgICAgICAgICBSRVRFTlRJT05fUEVSSU9EUy5DT0xEX1NUT1JBR0VfT05FX1lFQVJcbiAgICAgICAgKSxcbiAgICAgICAgc3RhcnRXaW5kb3c6IER1cmF0aW9uLm1pbnV0ZXMoNjApLFxuICAgICAgICBjb21wbGV0aW9uV2luZG93OiBEdXJhdGlvbi5ob3VycygyKSxcbiAgICAgICAgY29weUFjdGlvbnM6IGNvbXBsaWFuY2VDb3B5QWN0aW9uc1xuICAgICAgfSlcbiAgICBdO1xuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVDb3B5QWN0aW9ucyhcbiAgICBwbGFuTmFtZTogc3RyaW5nLFxuICAgIHJlcGxpY2F0aW9uVmF1bHRBcm4/OiBzdHJpbmcsXG4gICAgZGlzYXN0ZXJSZWNvdmVyeVZhdWx0QXJuPzogc3RyaW5nLFxuICAgIGRlbGV0ZUFmdGVyPzogRHVyYXRpb24sXG4gICAgbW92ZVRvQ29sZFN0b3JhZ2VBZnRlcj86IER1cmF0aW9uXG4gICk6IEJhY2t1cFBsYW5Db3B5QWN0aW9uUHJvcHNbXSB8IHVuZGVmaW5lZCB7XG4gICAgY29uc3QgYWN0aW9uczogQmFja3VwUGxhbkNvcHlBY3Rpb25Qcm9wc1tdID0gW107XG5cbiAgICAvLyBDcm9zcy1yZWdpb24gcmVwbGljYXRpb25cbiAgICBpZiAocmVwbGljYXRpb25WYXVsdEFybikge1xuICAgICAgY29uc3QgcmVwbGljYXRpb25BY3Rpb246IEJhY2t1cFBsYW5Db3B5QWN0aW9uUHJvcHMgPSB7XG4gICAgICAgIGRlc3RpbmF0aW9uQmFja3VwVmF1bHQ6IFZhdWx0LmZyb21CYWNrdXBWYXVsdEFybihcbiAgICAgICAgICB0aGlzLFxuICAgICAgICAgIGAke3BsYW5OYW1lfVJlcGxpY2F0aW9uVmF1bHRSZWZgLFxuICAgICAgICAgIHJlcGxpY2F0aW9uVmF1bHRBcm5cbiAgICAgICAgKSxcbiAgICAgICAgLi4uKGRlbGV0ZUFmdGVyICYmIHsgZGVsZXRlQWZ0ZXIgfSksXG4gICAgICAgIC8vIE9ubHkgYWRkIGNvbGQgc3RvcmFnZSBpZiBzcGVjaWZpZWQgYW5kID49IDkwIGRheXNcbiAgICAgICAgLi4uKG1vdmVUb0NvbGRTdG9yYWdlQWZ0ZXIgJiZcbiAgICAgICAgbW92ZVRvQ29sZFN0b3JhZ2VBZnRlci50b0RheXMoKSA+PVxuICAgICAgICAgIFJFVEVOVElPTl9QRVJJT0RTLkNPTERfU1RPUkFHRV9NSU5JTVVNXG4gICAgICAgICAgPyB7IG1vdmVUb0NvbGRTdG9yYWdlQWZ0ZXIgfVxuICAgICAgICAgIDoge30pXG4gICAgICB9O1xuICAgICAgYWN0aW9ucy5wdXNoKHJlcGxpY2F0aW9uQWN0aW9uKTtcbiAgICB9XG5cbiAgICAvLyBDcm9zcy1hY2NvdW50IERSIHZhdWx0XG4gICAgaWYgKGRpc2FzdGVyUmVjb3ZlcnlWYXVsdEFybikge1xuICAgICAgY29uc3QgZHJBY3Rpb246IEJhY2t1cFBsYW5Db3B5QWN0aW9uUHJvcHMgPSB7XG4gICAgICAgIGRlc3RpbmF0aW9uQmFja3VwVmF1bHQ6IFZhdWx0LmZyb21CYWNrdXBWYXVsdEFybihcbiAgICAgICAgICB0aGlzLFxuICAgICAgICAgIGAke3BsYW5OYW1lfURpc2FzdGVyUmVjb3ZlcnlWYXVsdFJlZmAsXG4gICAgICAgICAgZGlzYXN0ZXJSZWNvdmVyeVZhdWx0QXJuXG4gICAgICAgICksXG4gICAgICAgIC4uLihkZWxldGVBZnRlciAmJiB7IGRlbGV0ZUFmdGVyIH0pLFxuICAgICAgICAvLyBPbmx5IGFkZCBjb2xkIHN0b3JhZ2UgaWYgc3BlY2lmaWVkIGFuZCA+PSA5MCBkYXlzXG4gICAgICAgIC4uLihtb3ZlVG9Db2xkU3RvcmFnZUFmdGVyICYmXG4gICAgICAgIG1vdmVUb0NvbGRTdG9yYWdlQWZ0ZXIudG9EYXlzKCkgPj1cbiAgICAgICAgICBSRVRFTlRJT05fUEVSSU9EUy5DT0xEX1NUT1JBR0VfTUlOSU1VTVxuICAgICAgICAgID8geyBtb3ZlVG9Db2xkU3RvcmFnZUFmdGVyIH1cbiAgICAgICAgICA6IHt9KVxuICAgICAgfTtcbiAgICAgIGFjdGlvbnMucHVzaChkckFjdGlvbik7XG4gICAgfVxuXG4gICAgcmV0dXJuIGFjdGlvbnMubGVuZ3RoID4gMCA/IGFjdGlvbnMgOiB1bmRlZmluZWQ7XG4gIH1cbn1cbiJdfQ==
|
|
@@ -6,6 +6,8 @@ const aws_1 = require("../../config/aws");
|
|
|
6
6
|
const cloudTrail_1 = require("../../config/aws/cloudTrail");
|
|
7
7
|
const aws_cdk_lib_2 = require("aws-cdk-lib");
|
|
8
8
|
const getConfig_1 = require("../../utils/getConfig");
|
|
9
|
+
const disasterRecovery_1 = require("../../config/aws/disasterRecovery");
|
|
10
|
+
const util_1 = require("@fjall/util");
|
|
9
11
|
class ManagedAccount extends aws_cdk_lib_1.Stack {
|
|
10
12
|
constructor(scope, id, props) {
|
|
11
13
|
super(scope, id, props);
|
|
@@ -28,9 +30,20 @@ class ManagedAccount extends aws_cdk_lib_1.Stack {
|
|
|
28
30
|
accountId: account.accountId.value,
|
|
29
31
|
eventBusArn: eventBus.defaultEventBusArn.value
|
|
30
32
|
});
|
|
31
|
-
// Export environment for applications to use in tags
|
|
32
33
|
const config = (0, getConfig_1.getConfig)();
|
|
33
34
|
const environment = config.environment || "unknown";
|
|
35
|
+
const fjallConfig = util_1.Config.loadConfig();
|
|
36
|
+
const isComplianceAccount = environment === "compliance";
|
|
37
|
+
const isReplicationRegion = config.disasterRecoveryRegion &&
|
|
38
|
+
props.region === config.disasterRecoveryRegion;
|
|
39
|
+
if (environment === "production" ||
|
|
40
|
+
isComplianceAccount ||
|
|
41
|
+
isReplicationRegion) {
|
|
42
|
+
new disasterRecovery_1.DisasterRecovery(this, "DisasterRecovery", {
|
|
43
|
+
region: props.region,
|
|
44
|
+
accountId: props.accountId
|
|
45
|
+
});
|
|
46
|
+
}
|
|
34
47
|
new aws_cdk_lib_2.CfnOutput(this, "Environment", {
|
|
35
48
|
key: "Environment",
|
|
36
49
|
value: environment,
|
|
@@ -40,4 +53,4 @@ class ManagedAccount extends aws_cdk_lib_1.Stack {
|
|
|
40
53
|
}
|
|
41
54
|
}
|
|
42
55
|
exports.ManagedAccount = ManagedAccount;
|
|
43
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
56
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFuYWdlZEFjY291bnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9saWIvcGF0dGVybnMvYXdzL21hbmFnZWRBY2NvdW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDZDQUFnRDtBQUNoRCwwQ0FNMEI7QUFFMUIsNERBQW9FO0FBQ3BFLDZDQUF3QztBQUN4QyxxREFBa0Q7QUFDbEQsd0VBQXFFO0FBQ3JFLHNDQUFvRDtBQU9wRCxNQUFhLGNBQWUsU0FBUSxtQkFBSztJQUN2QyxZQUFZLEtBQWdCLEVBQUUsRUFBVSxFQUFFLEtBQTBCO1FBQ2xFLEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBRXhCLE1BQU0sWUFBWSxHQUFHLElBQUksb0JBQWMsQ0FBQyxJQUFJLEVBQUUsZ0JBQWdCLENBQUMsQ0FBQztRQUVoRSxNQUFNLE9BQU8sR0FBRyxJQUFJLGVBQVMsQ0FBQyxJQUFJLEVBQUUsV0FBVyxDQUFDLENBQUM7UUFFakQsTUFBTSxRQUFRLEdBQUcsSUFBSSxxQkFBZSxDQUFDLElBQUksRUFBRSxVQUFVLENBQUMsQ0FBQztRQUV2RCxJQUFJLEVBQUUsS0FBSyxnQkFBZ0IsRUFBRSxDQUFDO1lBQzVCLElBQUksZ0JBQVUsQ0FBQyxJQUFJLEVBQUUsWUFBWSxFQUFFO2dCQUNqQyxTQUFTLEVBQUUsS0FBSyxDQUFDLFNBQVM7Z0JBQzFCLE1BQU0sRUFBRSxLQUFLLENBQUMsTUFBTTtnQkFDcEIsT0FBTyxFQUFFLFlBQVksQ0FBQyxzQkFBc0IsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQzthQUNqRSxDQUFDLENBQUM7UUFDTCxDQUFDO1FBRUQsSUFBSSxrQ0FBcUIsQ0FBQyxJQUFJLEVBQUUsWUFBWSxFQUFFO1lBQzVDLFNBQVMsRUFBRSxPQUFPLENBQUMsU0FBUyxDQUFDLEtBQUs7WUFDbEMsTUFBTSxFQUFFLEtBQUssQ0FBQyxNQUFNO1NBQ3JCLENBQUMsQ0FBQztRQUVILElBQUkscUJBQWUsQ0FBQyxJQUFJLEVBQUUsaUJBQWlCLEVBQUU7WUFDM0MsTUFBTSxFQUFFLEtBQUssQ0FBQyxNQUFNO1lBQ3BCLFNBQVMsRUFBRSxPQUFPLENBQUMsU0FBUyxDQUFDLEtBQUs7WUFDbEMsV0FBVyxFQUFFLFFBQVEsQ0FBQyxrQkFBa0IsQ0FBQyxLQUFLO1NBQy9DLENBQUMsQ0FBQztRQUVILE1BQU0sTUFBTSxHQUFHLElBQUEscUJBQVMsR0FBRSxDQUFDO1FBQzNCLE1BQU0sV0FBVyxHQUFHLE1BQU0sQ0FBQyxXQUFXLElBQUksU0FBUyxDQUFDO1FBQ3BELE1BQU0sV0FBVyxHQUFHLGFBQVcsQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUU3QyxNQUFNLG1CQUFtQixHQUFHLFdBQVcsS0FBSyxZQUFZLENBQUM7UUFDekQsTUFBTSxtQkFBbUIsR0FDdkIsTUFBTSxDQUFDLHNCQUFzQjtZQUM3QixLQUFLLENBQUMsTUFBTSxLQUFLLE1BQU0sQ0FBQyxzQkFBc0IsQ0FBQztRQUVqRCxJQUNFLFdBQVcsS0FBSyxZQUFZO1lBQzVCLG1CQUFtQjtZQUNuQixtQkFBbUIsRUFDbkIsQ0FBQztZQUNELElBQUksbUNBQWdCLENBQUMsSUFBSSxFQUFFLGtCQUFrQixFQUFFO2dCQUM3QyxNQUFNLEVBQUUsS0FBSyxDQUFDLE1BQU07Z0JBQ3BCLFNBQVMsRUFBRSxLQUFLLENBQUMsU0FBUzthQUMzQixDQUFDLENBQUM7UUFDTCxDQUFDO1FBRUQsSUFBSSx1QkFBUyxDQUFDLElBQUksRUFBRSxhQUFhLEVBQUU7WUFDakMsR0FBRyxFQUFFLGFBQWE7WUFDbEIsS0FBSyxFQUFFLFdBQVc7WUFDbEIsVUFBVSxFQUFFLGFBQWE7WUFDekIsV0FBVyxFQUNULDRFQUE0RTtTQUMvRSxDQUFDLENBQUM7SUFDTCxDQUFDO0NBQ0Y7QUF6REQsd0NBeURDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgU3RhY2ssIFN0YWNrUHJvcHMgfSBmcm9tIFwiYXdzLWNkay1saWJcIjtcbmltcG9ydCB7XG4gIE9yZ2FuaXNhdGlvbklkLFxuICBBY2NvdW50SWQsXG4gIElwYW1Qb29sSWQsXG4gIEVjckRlZmF1bHRJbWFnZSxcbiAgRGVmYXVsdEV2ZW50QnVzXG59IGZyb20gXCIuLi8uLi9jb25maWcvYXdzXCI7XG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tIFwiY29uc3RydWN0c1wiO1xuaW1wb3J0IHsgTWFuYWdlbWVudEV2ZW50c1RyYWlsIH0gZnJvbSBcIi4uLy4uL2NvbmZpZy9hd3MvY2xvdWRUcmFpbFwiO1xuaW1wb3J0IHsgQ2ZuT3V0cHV0IH0gZnJvbSBcImF3cy1jZGstbGliXCI7XG5pbXBvcnQgeyBnZXRDb25maWcgfSBmcm9tIFwiLi4vLi4vdXRpbHMvZ2V0Q29uZmlnXCI7XG5pbXBvcnQgeyBEaXNhc3RlclJlY292ZXJ5IH0gZnJvbSBcIi4uLy4uL2NvbmZpZy9hd3MvZGlzYXN0ZXJSZWNvdmVyeVwiO1xuaW1wb3J0IHsgQ29uZmlnIGFzIEZqYWxsQ29uZmlnIH0gZnJvbSBcIkBmamFsbC91dGlsXCI7XG5cbmV4cG9ydCBpbnRlcmZhY2UgTWFuYWdlZEFjY291bnRQcm9wcyBleHRlbmRzIFN0YWNrUHJvcHMge1xuICBhY2NvdW50SWQ6IHN0cmluZztcbiAgcmVnaW9uOiBzdHJpbmc7XG59XG5cbmV4cG9ydCBjbGFzcyBNYW5hZ2VkQWNjb3VudCBleHRlbmRzIFN0YWNrIHtcbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IE1hbmFnZWRBY2NvdW50UHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQsIHByb3BzKTtcblxuICAgIGNvbnN0IG9yZ2FuaXNhdGlvbiA9IG5ldyBPcmdhbmlzYXRpb25JZCh0aGlzLCBcIk9yZ2FuaXNhdGlvbklkXCIpO1xuXG4gICAgY29uc3QgYWNjb3VudCA9IG5ldyBBY2NvdW50SWQodGhpcywgXCJBY2NvdW50SWRcIik7XG5cbiAgICBjb25zdCBldmVudEJ1cyA9IG5ldyBEZWZhdWx0RXZlbnRCdXModGhpcywgXCJFdmVudEJ1c1wiKTtcblxuICAgIGlmIChpZCA9PT0gXCJNYW5hZ2VkQWNjb3VudFwiKSB7XG4gICAgICBuZXcgSXBhbVBvb2xJZCh0aGlzLCBcIklwYW1Qb29sSWRcIiwge1xuICAgICAgICBhY2NvdW50SWQ6IHByb3BzLmFjY291bnRJZCxcbiAgICAgICAgcmVnaW9uOiBwcm9wcy5yZWdpb24sXG4gICAgICAgIG93bmVySWQ6IG9yZ2FuaXNhdGlvbi5vcmdhbmlzYXRpb25BY2NvdW50QXJuLnZhbHVlLnNwbGl0KFwiOlwiKVs0XVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgbmV3IE1hbmFnZW1lbnRFdmVudHNUcmFpbCh0aGlzLCBcIkNsb3VkVHJhaWxcIiwge1xuICAgICAgYWNjb3VudElkOiBhY2NvdW50LmFjY291bnRJZC52YWx1ZSxcbiAgICAgIHJlZ2lvbjogcHJvcHMucmVnaW9uXG4gICAgfSk7XG5cbiAgICBuZXcgRWNyRGVmYXVsdEltYWdlKHRoaXMsIFwiRWNyRGVmYXVsdEltYWdlXCIsIHtcbiAgICAgIHJlZ2lvbjogcHJvcHMucmVnaW9uLFxuICAgICAgYWNjb3VudElkOiBhY2NvdW50LmFjY291bnRJZC52YWx1ZSxcbiAgICAgIGV2ZW50QnVzQXJuOiBldmVudEJ1cy5kZWZhdWx0RXZlbnRCdXNBcm4udmFsdWVcbiAgICB9KTtcblxuICAgIGNvbnN0IGNvbmZpZyA9IGdldENvbmZpZygpO1xuICAgIGNvbnN0IGVudmlyb25tZW50ID0gY29uZmlnLmVudmlyb25tZW50IHx8IFwidW5rbm93blwiO1xuICAgIGNvbnN0IGZqYWxsQ29uZmlnID0gRmphbGxDb25maWcubG9hZENvbmZpZygpO1xuXG4gICAgY29uc3QgaXNDb21wbGlhbmNlQWNjb3VudCA9IGVudmlyb25tZW50ID09PSBcImNvbXBsaWFuY2VcIjtcbiAgICBjb25zdCBpc1JlcGxpY2F0aW9uUmVnaW9uID1cbiAgICAgIGNvbmZpZy5kaXNhc3RlclJlY292ZXJ5UmVnaW9uICYmXG4gICAgICBwcm9wcy5yZWdpb24gPT09IGNvbmZpZy5kaXNhc3RlclJlY292ZXJ5UmVnaW9uO1xuXG4gICAgaWYgKFxuICAgICAgZW52aXJvbm1lbnQgPT09IFwicHJvZHVjdGlvblwiIHx8XG4gICAgICBpc0NvbXBsaWFuY2VBY2NvdW50IHx8XG4gICAgICBpc1JlcGxpY2F0aW9uUmVnaW9uXG4gICAgKSB7XG4gICAgICBuZXcgRGlzYXN0ZXJSZWNvdmVyeSh0aGlzLCBcIkRpc2FzdGVyUmVjb3ZlcnlcIiwge1xuICAgICAgICByZWdpb246IHByb3BzLnJlZ2lvbixcbiAgICAgICAgYWNjb3VudElkOiBwcm9wcy5hY2NvdW50SWRcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIG5ldyBDZm5PdXRwdXQodGhpcywgXCJFbnZpcm9ubWVudFwiLCB7XG4gICAgICBrZXk6IFwiRW52aXJvbm1lbnRcIixcbiAgICAgIHZhbHVlOiBlbnZpcm9ubWVudCxcbiAgICAgIGV4cG9ydE5hbWU6IFwiRW52aXJvbm1lbnRcIixcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICBcIkVudmlyb25tZW50IHR5cGUgZm9yIHRoaXMgYWNjb3VudCAoZS5nLiwgcHJvZHVjdGlvbiwgc3RhZ2luZywgZGV2ZWxvcG1lbnQpXCJcbiAgICB9KTtcbiAgfVxufVxuIl19
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Construct } from "constructs";
|
|
2
|
+
import { CfnOutput } from "aws-cdk-lib";
|
|
3
|
+
import { BackupPlan as Plan, BackupSelection, BackupPlanRule } from "aws-cdk-lib/aws-backup";
|
|
4
|
+
import { BackupVault } from "./backupVault";
|
|
5
|
+
export interface BackupPlanProps {
|
|
6
|
+
planName: string;
|
|
7
|
+
rules: BackupPlanRule[];
|
|
8
|
+
backupVault: BackupVault;
|
|
9
|
+
tagValue: string;
|
|
10
|
+
tagKey?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare class BackupPlan extends Construct {
|
|
13
|
+
readonly plan: Plan;
|
|
14
|
+
readonly selection: BackupSelection;
|
|
15
|
+
readonly planArn: CfnOutput;
|
|
16
|
+
constructor(scope: Construct, id: string, props: BackupPlanProps);
|
|
17
|
+
private createBackupRole;
|
|
18
|
+
static build(id: string, props: BackupPlanProps): (scope: Construct) => BackupPlan;
|
|
19
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BackupPlan = void 0;
|
|
4
|
+
const constructs_1 = require("constructs");
|
|
5
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
6
|
+
const aws_backup_1 = require("aws-cdk-lib/aws-backup");
|
|
7
|
+
const iam = require("aws-cdk-lib/aws-iam");
|
|
8
|
+
class BackupPlan extends constructs_1.Construct {
|
|
9
|
+
constructor(scope, id, props) {
|
|
10
|
+
super(scope, id);
|
|
11
|
+
const tagKey = props.tagKey || "fjall:disasterRecovery:tier";
|
|
12
|
+
// Create backup plan with provided rules
|
|
13
|
+
this.plan = new aws_backup_1.BackupPlan(this, `${props.planName}Plan`, {
|
|
14
|
+
backupPlanName: props.planName,
|
|
15
|
+
backupVault: props.backupVault.vault,
|
|
16
|
+
backupPlanRules: props.rules
|
|
17
|
+
});
|
|
18
|
+
// Create tag-based selection
|
|
19
|
+
this.selection = new aws_backup_1.BackupSelection(this, `${props.planName}Selection`, {
|
|
20
|
+
backupPlan: this.plan,
|
|
21
|
+
resources: [aws_backup_1.BackupResource.fromTag(tagKey, props.tagValue)],
|
|
22
|
+
role: this.createBackupRole(props)
|
|
23
|
+
});
|
|
24
|
+
// Export plan ARN
|
|
25
|
+
const planNamePascal = props.planName.charAt(0).toUpperCase() + props.planName.slice(1);
|
|
26
|
+
this.planArn = new aws_cdk_lib_1.CfnOutput(this, `${props.planName}PlanArn`, {
|
|
27
|
+
key: `${props.planName}PlanArn`,
|
|
28
|
+
value: this.plan.backupPlanArn,
|
|
29
|
+
exportName: `${planNamePascal}BackupPlanArn`
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
createBackupRole(props) {
|
|
33
|
+
const role = new iam.Role(this, `${props.planName}BackupRole`, {
|
|
34
|
+
assumedBy: new iam.ServicePrincipal("backup.amazonaws.com"),
|
|
35
|
+
description: `Backup role for ${props.planName}`,
|
|
36
|
+
managedPolicies: [
|
|
37
|
+
// Core backup policies
|
|
38
|
+
iam.ManagedPolicy.fromAwsManagedPolicyName("service-role/AWSBackupServiceRolePolicyForBackup"),
|
|
39
|
+
iam.ManagedPolicy.fromAwsManagedPolicyName("service-role/AWSBackupServiceRolePolicyForRestores"),
|
|
40
|
+
// S3 backup support
|
|
41
|
+
iam.ManagedPolicy.fromAwsManagedPolicyName("AWSBackupServiceRolePolicyForS3Backup"),
|
|
42
|
+
iam.ManagedPolicy.fromAwsManagedPolicyName("AWSBackupServiceRolePolicyForS3Restore")
|
|
43
|
+
]
|
|
44
|
+
});
|
|
45
|
+
role.addToPolicy(new iam.PolicyStatement({
|
|
46
|
+
effect: iam.Effect.ALLOW,
|
|
47
|
+
actions: [
|
|
48
|
+
"rds:ModifyDBInstance",
|
|
49
|
+
"rds:DescribeDBInstanceAutomatedBackups",
|
|
50
|
+
"rds:RestoreDBInstanceToPointInTime",
|
|
51
|
+
"rds:DescribeDBInstances",
|
|
52
|
+
"rds:DescribeDBClusters",
|
|
53
|
+
"rds:RestoreDBClusterToPointInTime"
|
|
54
|
+
],
|
|
55
|
+
resources: ["*"]
|
|
56
|
+
}));
|
|
57
|
+
role.addToPolicy(new iam.PolicyStatement({
|
|
58
|
+
effect: iam.Effect.ALLOW,
|
|
59
|
+
actions: ["backup:CopyIntoBackupVault", "backup:CopyFromBackupVault"],
|
|
60
|
+
resources: ["*"] // TODO: Tighten up
|
|
61
|
+
}));
|
|
62
|
+
return role;
|
|
63
|
+
}
|
|
64
|
+
static build(id, props) {
|
|
65
|
+
return (scope) => {
|
|
66
|
+
return new BackupPlan(scope, id, props);
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
exports.BackupPlan = BackupPlan;
|
|
71
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFja3VwUGxhbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL2xpYi9yZXNvdXJjZXMvYXdzL2JhY2t1cC9iYWNrdXBQbGFuLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDJDQUF1QztBQUN2Qyw2Q0FBd0M7QUFDeEMsdURBS2dDO0FBQ2hDLDJDQUEyQztBQVczQyxNQUFhLFVBQVcsU0FBUSxzQkFBUztJQUt2QyxZQUFZLEtBQWdCLEVBQUUsRUFBVSxFQUFFLEtBQXNCO1FBQzlELEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFFakIsTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLE1BQU0sSUFBSSw2QkFBNkIsQ0FBQztRQUU3RCx5Q0FBeUM7UUFDekMsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLHVCQUFJLENBQUMsSUFBSSxFQUFFLEdBQUcsS0FBSyxDQUFDLFFBQVEsTUFBTSxFQUFFO1lBQ2xELGNBQWMsRUFBRSxLQUFLLENBQUMsUUFBUTtZQUM5QixXQUFXLEVBQUUsS0FBSyxDQUFDLFdBQVcsQ0FBQyxLQUFLO1lBQ3BDLGVBQWUsRUFBRSxLQUFLLENBQUMsS0FBSztTQUM3QixDQUFDLENBQUM7UUFFSCw2QkFBNkI7UUFDN0IsSUFBSSxDQUFDLFNBQVMsR0FBRyxJQUFJLDRCQUFlLENBQUMsSUFBSSxFQUFFLEdBQUcsS0FBSyxDQUFDLFFBQVEsV0FBVyxFQUFFO1lBQ3ZFLFVBQVUsRUFBRSxJQUFJLENBQUMsSUFBSTtZQUNyQixTQUFTLEVBQUUsQ0FBQywyQkFBYyxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBQzNELElBQUksRUFBRSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsS0FBSyxDQUFDO1NBQ25DLENBQUMsQ0FBQztRQUVILGtCQUFrQjtRQUNsQixNQUFNLGNBQWMsR0FDbEIsS0FBSyxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsV0FBVyxFQUFFLEdBQUcsS0FBSyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFFbkUsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLHVCQUFTLENBQUMsSUFBSSxFQUFFLEdBQUcsS0FBSyxDQUFDLFFBQVEsU0FBUyxFQUFFO1lBQzdELEdBQUcsRUFBRSxHQUFHLEtBQUssQ0FBQyxRQUFRLFNBQVM7WUFDL0IsS0FBSyxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsYUFBYTtZQUM5QixVQUFVLEVBQUUsR0FBRyxjQUFjLGVBQWU7U0FDN0MsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVPLGdCQUFnQixDQUFDLEtBQXNCO1FBQzdDLE1BQU0sSUFBSSxHQUFHLElBQUksR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsR0FBRyxLQUFLLENBQUMsUUFBUSxZQUFZLEVBQUU7WUFDN0QsU0FBUyxFQUFFLElBQUksR0FBRyxDQUFDLGdCQUFnQixDQUFDLHNCQUFzQixDQUFDO1lBQzNELFdBQVcsRUFBRSxtQkFBbUIsS0FBSyxDQUFDLFFBQVEsRUFBRTtZQUNoRCxlQUFlLEVBQUU7Z0JBQ2YsdUJBQXVCO2dCQUN2QixHQUFHLENBQUMsYUFBYSxDQUFDLHdCQUF3QixDQUN4QyxrREFBa0QsQ0FDbkQ7Z0JBQ0QsR0FBRyxDQUFDLGFBQWEsQ0FBQyx3QkFBd0IsQ0FDeEMsb0RBQW9ELENBQ3JEO2dCQUNELG9CQUFvQjtnQkFDcEIsR0FBRyxDQUFDLGFBQWEsQ0FBQyx3QkFBd0IsQ0FDeEMsdUNBQXVDLENBQ3hDO2dCQUNELEdBQUcsQ0FBQyxhQUFhLENBQUMsd0JBQXdCLENBQ3hDLHdDQUF3QyxDQUN6QzthQUNGO1NBQ0YsQ0FBQyxDQUFDO1FBRUgsSUFBSSxDQUFDLFdBQVcsQ0FDZCxJQUFJLEdBQUcsQ0FBQyxlQUFlLENBQUM7WUFDdEIsTUFBTSxFQUFFLEdBQUcsQ0FBQyxNQUFNLENBQUMsS0FBSztZQUN4QixPQUFPLEVBQUU7Z0JBQ1Asc0JBQXNCO2dCQUN0Qix3Q0FBd0M7Z0JBQ3hDLG9DQUFvQztnQkFDcEMseUJBQXlCO2dCQUN6Qix3QkFBd0I7Z0JBQ3hCLG1DQUFtQzthQUNwQztZQUNELFNBQVMsRUFBRSxDQUFDLEdBQUcsQ0FBQztTQUNqQixDQUFDLENBQ0gsQ0FBQztRQUVGLElBQUksQ0FBQyxXQUFXLENBQ2QsSUFBSSxHQUFHLENBQUMsZUFBZSxDQUFDO1lBQ3RCLE1BQU0sRUFBRSxHQUFHLENBQUMsTUFBTSxDQUFDLEtBQUs7WUFDeEIsT0FBTyxFQUFFLENBQUMsNEJBQTRCLEVBQUUsNEJBQTRCLENBQUM7WUFDckUsU0FBUyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsbUJBQW1CO1NBQ3JDLENBQUMsQ0FDSCxDQUFDO1FBRUYsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQsTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFVLEVBQUUsS0FBc0I7UUFDN0MsT0FBTyxDQUFDLEtBQWdCLEVBQUUsRUFBRTtZQUMxQixPQUFPLElBQUksVUFBVSxDQUFDLEtBQUssRUFBRSxFQUFFLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDMUMsQ0FBQyxDQUFDO0lBQ0osQ0FBQztDQUNGO0FBeEZELGdDQXdGQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbnN0cnVjdCB9IGZyb20gXCJjb25zdHJ1Y3RzXCI7XG5pbXBvcnQgeyBDZm5PdXRwdXQgfSBmcm9tIFwiYXdzLWNkay1saWJcIjtcbmltcG9ydCB7XG4gIEJhY2t1cFBsYW4gYXMgUGxhbixcbiAgQmFja3VwU2VsZWN0aW9uLFxuICBCYWNrdXBSZXNvdXJjZSxcbiAgQmFja3VwUGxhblJ1bGVcbn0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1iYWNrdXBcIjtcbmltcG9ydCAqIGFzIGlhbSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWlhbVwiO1xuaW1wb3J0IHsgQmFja3VwVmF1bHQgfSBmcm9tIFwiLi9iYWNrdXBWYXVsdFwiO1xuXG5leHBvcnQgaW50ZXJmYWNlIEJhY2t1cFBsYW5Qcm9wcyB7XG4gIHBsYW5OYW1lOiBzdHJpbmc7XG4gIHJ1bGVzOiBCYWNrdXBQbGFuUnVsZVtdO1xuICBiYWNrdXBWYXVsdDogQmFja3VwVmF1bHQ7XG4gIHRhZ1ZhbHVlOiBzdHJpbmc7XG4gIHRhZ0tleT86IHN0cmluZztcbn1cblxuZXhwb3J0IGNsYXNzIEJhY2t1cFBsYW4gZXh0ZW5kcyBDb25zdHJ1Y3Qge1xuICBwdWJsaWMgcmVhZG9ubHkgcGxhbjogUGxhbjtcbiAgcHVibGljIHJlYWRvbmx5IHNlbGVjdGlvbjogQmFja3VwU2VsZWN0aW9uO1xuICBwdWJsaWMgcmVhZG9ubHkgcGxhbkFybjogQ2ZuT3V0cHV0O1xuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBCYWNrdXBQbGFuUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuXG4gICAgY29uc3QgdGFnS2V5ID0gcHJvcHMudGFnS2V5IHx8IFwiZmphbGw6ZGlzYXN0ZXJSZWNvdmVyeTp0aWVyXCI7XG5cbiAgICAvLyBDcmVhdGUgYmFja3VwIHBsYW4gd2l0aCBwcm92aWRlZCBydWxlc1xuICAgIHRoaXMucGxhbiA9IG5ldyBQbGFuKHRoaXMsIGAke3Byb3BzLnBsYW5OYW1lfVBsYW5gLCB7XG4gICAgICBiYWNrdXBQbGFuTmFtZTogcHJvcHMucGxhbk5hbWUsXG4gICAgICBiYWNrdXBWYXVsdDogcHJvcHMuYmFja3VwVmF1bHQudmF1bHQsXG4gICAgICBiYWNrdXBQbGFuUnVsZXM6IHByb3BzLnJ1bGVzXG4gICAgfSk7XG5cbiAgICAvLyBDcmVhdGUgdGFnLWJhc2VkIHNlbGVjdGlvblxuICAgIHRoaXMuc2VsZWN0aW9uID0gbmV3IEJhY2t1cFNlbGVjdGlvbih0aGlzLCBgJHtwcm9wcy5wbGFuTmFtZX1TZWxlY3Rpb25gLCB7XG4gICAgICBiYWNrdXBQbGFuOiB0aGlzLnBsYW4sXG4gICAgICByZXNvdXJjZXM6IFtCYWNrdXBSZXNvdXJjZS5mcm9tVGFnKHRhZ0tleSwgcHJvcHMudGFnVmFsdWUpXSxcbiAgICAgIHJvbGU6IHRoaXMuY3JlYXRlQmFja3VwUm9sZShwcm9wcylcbiAgICB9KTtcblxuICAgIC8vIEV4cG9ydCBwbGFuIEFSTlxuICAgIGNvbnN0IHBsYW5OYW1lUGFzY2FsID1cbiAgICAgIHByb3BzLnBsYW5OYW1lLmNoYXJBdCgwKS50b1VwcGVyQ2FzZSgpICsgcHJvcHMucGxhbk5hbWUuc2xpY2UoMSk7XG5cbiAgICB0aGlzLnBsYW5Bcm4gPSBuZXcgQ2ZuT3V0cHV0KHRoaXMsIGAke3Byb3BzLnBsYW5OYW1lfVBsYW5Bcm5gLCB7XG4gICAgICBrZXk6IGAke3Byb3BzLnBsYW5OYW1lfVBsYW5Bcm5gLFxuICAgICAgdmFsdWU6IHRoaXMucGxhbi5iYWNrdXBQbGFuQXJuLFxuICAgICAgZXhwb3J0TmFtZTogYCR7cGxhbk5hbWVQYXNjYWx9QmFja3VwUGxhbkFybmBcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgY3JlYXRlQmFja3VwUm9sZShwcm9wczogQmFja3VwUGxhblByb3BzKTogaWFtLlJvbGUge1xuICAgIGNvbnN0IHJvbGUgPSBuZXcgaWFtLlJvbGUodGhpcywgYCR7cHJvcHMucGxhbk5hbWV9QmFja3VwUm9sZWAsIHtcbiAgICAgIGFzc3VtZWRCeTogbmV3IGlhbS5TZXJ2aWNlUHJpbmNpcGFsKFwiYmFja3VwLmFtYXpvbmF3cy5jb21cIiksXG4gICAgICBkZXNjcmlwdGlvbjogYEJhY2t1cCByb2xlIGZvciAke3Byb3BzLnBsYW5OYW1lfWAsXG4gICAgICBtYW5hZ2VkUG9saWNpZXM6IFtcbiAgICAgICAgLy8gQ29yZSBiYWNrdXAgcG9saWNpZXNcbiAgICAgICAgaWFtLk1hbmFnZWRQb2xpY3kuZnJvbUF3c01hbmFnZWRQb2xpY3lOYW1lKFxuICAgICAgICAgIFwic2VydmljZS1yb2xlL0FXU0JhY2t1cFNlcnZpY2VSb2xlUG9saWN5Rm9yQmFja3VwXCJcbiAgICAgICAgKSxcbiAgICAgICAgaWFtLk1hbmFnZWRQb2xpY3kuZnJvbUF3c01hbmFnZWRQb2xpY3lOYW1lKFxuICAgICAgICAgIFwic2VydmljZS1yb2xlL0FXU0JhY2t1cFNlcnZpY2VSb2xlUG9saWN5Rm9yUmVzdG9yZXNcIlxuICAgICAgICApLFxuICAgICAgICAvLyBTMyBiYWNrdXAgc3VwcG9ydFxuICAgICAgICBpYW0uTWFuYWdlZFBvbGljeS5mcm9tQXdzTWFuYWdlZFBvbGljeU5hbWUoXG4gICAgICAgICAgXCJBV1NCYWNrdXBTZXJ2aWNlUm9sZVBvbGljeUZvclMzQmFja3VwXCJcbiAgICAgICAgKSxcbiAgICAgICAgaWFtLk1hbmFnZWRQb2xpY3kuZnJvbUF3c01hbmFnZWRQb2xpY3lOYW1lKFxuICAgICAgICAgIFwiQVdTQmFja3VwU2VydmljZVJvbGVQb2xpY3lGb3JTM1Jlc3RvcmVcIlxuICAgICAgICApXG4gICAgICBdXG4gICAgfSk7XG5cbiAgICByb2xlLmFkZFRvUG9saWN5KFxuICAgICAgbmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBlZmZlY3Q6IGlhbS5FZmZlY3QuQUxMT1csXG4gICAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAgICBcInJkczpNb2RpZnlEQkluc3RhbmNlXCIsXG4gICAgICAgICAgXCJyZHM6RGVzY3JpYmVEQkluc3RhbmNlQXV0b21hdGVkQmFja3Vwc1wiLFxuICAgICAgICAgIFwicmRzOlJlc3RvcmVEQkluc3RhbmNlVG9Qb2ludEluVGltZVwiLFxuICAgICAgICAgIFwicmRzOkRlc2NyaWJlREJJbnN0YW5jZXNcIixcbiAgICAgICAgICBcInJkczpEZXNjcmliZURCQ2x1c3RlcnNcIixcbiAgICAgICAgICBcInJkczpSZXN0b3JlREJDbHVzdGVyVG9Qb2ludEluVGltZVwiXG4gICAgICAgIF0sXG4gICAgICAgIHJlc291cmNlczogW1wiKlwiXVxuICAgICAgfSlcbiAgICApO1xuXG4gICAgcm9sZS5hZGRUb1BvbGljeShcbiAgICAgIG5ldyBpYW0uUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgZWZmZWN0OiBpYW0uRWZmZWN0LkFMTE9XLFxuICAgICAgICBhY3Rpb25zOiBbXCJiYWNrdXA6Q29weUludG9CYWNrdXBWYXVsdFwiLCBcImJhY2t1cDpDb3B5RnJvbUJhY2t1cFZhdWx0XCJdLFxuICAgICAgICByZXNvdXJjZXM6IFtcIipcIl0gLy8gVE9ETzogVGlnaHRlbiB1cFxuICAgICAgfSlcbiAgICApO1xuXG4gICAgcmV0dXJuIHJvbGU7XG4gIH1cblxuICBzdGF0aWMgYnVpbGQoaWQ6IHN0cmluZywgcHJvcHM6IEJhY2t1cFBsYW5Qcm9wcykge1xuICAgIHJldHVybiAoc2NvcGU6IENvbnN0cnVjdCkgPT4ge1xuICAgICAgcmV0dXJuIG5ldyBCYWNrdXBQbGFuKHNjb3BlLCBpZCwgcHJvcHMpO1xuICAgIH07XG4gIH1cbn1cbiJdfQ==
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Construct } from "constructs";
|
|
2
|
+
import { CfnOutput, RemovalPolicy } from "aws-cdk-lib";
|
|
3
|
+
import { BackupVault as Vault, LockConfiguration } from "aws-cdk-lib/aws-backup";
|
|
4
|
+
import { PolicyDocument } from "aws-cdk-lib/aws-iam";
|
|
5
|
+
import { CustomerManagedKey } from "../secrets/kms";
|
|
6
|
+
export interface BackupVaultProps {
|
|
7
|
+
vaultName: string;
|
|
8
|
+
encryptionKey?: CustomerManagedKey;
|
|
9
|
+
accessPolicy?: PolicyDocument;
|
|
10
|
+
lockConfiguration?: LockConfiguration;
|
|
11
|
+
removalPolicy?: RemovalPolicy;
|
|
12
|
+
}
|
|
13
|
+
export declare class BackupVault extends Construct {
|
|
14
|
+
readonly vault: Vault;
|
|
15
|
+
readonly vaultArn: CfnOutput;
|
|
16
|
+
readonly vaultName: CfnOutput;
|
|
17
|
+
constructor(scope: Construct, id: string, props: BackupVaultProps);
|
|
18
|
+
static build(id: string, props: BackupVaultProps): (scope: Construct) => BackupVault;
|
|
19
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BackupVault = void 0;
|
|
4
|
+
const constructs_1 = require("constructs");
|
|
5
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
6
|
+
const aws_backup_1 = require("aws-cdk-lib/aws-backup");
|
|
7
|
+
const kms_1 = require("../secrets/kms");
|
|
8
|
+
class BackupVault extends constructs_1.Construct {
|
|
9
|
+
constructor(scope, id, props) {
|
|
10
|
+
super(scope, id);
|
|
11
|
+
const encryptionKey = props.encryptionKey ||
|
|
12
|
+
new kms_1.CustomerManagedKey(this, `${props.vaultName}Key`, {
|
|
13
|
+
description: `Encryption key for backup vault ${props.vaultName}`,
|
|
14
|
+
aliasName: `cmk/backupVault/${props.vaultName}`
|
|
15
|
+
});
|
|
16
|
+
this.vault = new aws_backup_1.BackupVault(this, `${props.vaultName}Vault`, {
|
|
17
|
+
backupVaultName: props.vaultName,
|
|
18
|
+
encryptionKey: encryptionKey.key,
|
|
19
|
+
accessPolicy: props.accessPolicy,
|
|
20
|
+
lockConfiguration: props.lockConfiguration,
|
|
21
|
+
removalPolicy: props.removalPolicy || aws_cdk_lib_1.RemovalPolicy.RETAIN
|
|
22
|
+
});
|
|
23
|
+
const vaultNamePascal = props.vaultName.charAt(0).toUpperCase() + props.vaultName.slice(1);
|
|
24
|
+
this.vaultArn = new aws_cdk_lib_1.CfnOutput(this, `${props.vaultName}VaultArn`, {
|
|
25
|
+
key: `${props.vaultName}VaultArn`,
|
|
26
|
+
value: this.vault.backupVaultArn,
|
|
27
|
+
exportName: `${vaultNamePascal}Arn`
|
|
28
|
+
});
|
|
29
|
+
this.vaultName = new aws_cdk_lib_1.CfnOutput(this, `${props.vaultName}VaultName`, {
|
|
30
|
+
key: `${props.vaultName}VaultName`,
|
|
31
|
+
value: this.vault.backupVaultName,
|
|
32
|
+
exportName: `${vaultNamePascal}Name`
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
// Factory method following existing patterns
|
|
36
|
+
static build(id, props) {
|
|
37
|
+
return (scope) => {
|
|
38
|
+
return new BackupVault(scope, id, props);
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
exports.BackupVault = BackupVault;
|
|
43
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFja3VwVmF1bHQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9saWIvcmVzb3VyY2VzL2F3cy9iYWNrdXAvYmFja3VwVmF1bHQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsMkNBQXVDO0FBQ3ZDLDZDQUF1RDtBQUN2RCx1REFHZ0M7QUFFaEMsd0NBQW9EO0FBVXBELE1BQWEsV0FBWSxTQUFRLHNCQUFTO0lBS3hDLFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBdUI7UUFDL0QsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQUVqQixNQUFNLGFBQWEsR0FDakIsS0FBSyxDQUFDLGFBQWE7WUFDbkIsSUFBSSx3QkFBa0IsQ0FBQyxJQUFJLEVBQUUsR0FBRyxLQUFLLENBQUMsU0FBUyxLQUFLLEVBQUU7Z0JBQ3BELFdBQVcsRUFBRSxtQ0FBbUMsS0FBSyxDQUFDLFNBQVMsRUFBRTtnQkFDakUsU0FBUyxFQUFFLG1CQUFtQixLQUFLLENBQUMsU0FBUyxFQUFFO2FBQ2hELENBQUMsQ0FBQztRQUVMLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSx3QkFBSyxDQUFDLElBQUksRUFBRSxHQUFHLEtBQUssQ0FBQyxTQUFTLE9BQU8sRUFBRTtZQUN0RCxlQUFlLEVBQUUsS0FBSyxDQUFDLFNBQVM7WUFDaEMsYUFBYSxFQUFFLGFBQWEsQ0FBQyxHQUFHO1lBQ2hDLFlBQVksRUFBRSxLQUFLLENBQUMsWUFBWTtZQUNoQyxpQkFBaUIsRUFBRSxLQUFLLENBQUMsaUJBQWlCO1lBQzFDLGFBQWEsRUFBRSxLQUFLLENBQUMsYUFBYSxJQUFJLDJCQUFhLENBQUMsTUFBTTtTQUMzRCxDQUFDLENBQUM7UUFFSCxNQUFNLGVBQWUsR0FDbkIsS0FBSyxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsV0FBVyxFQUFFLEdBQUcsS0FBSyxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFFckUsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLHVCQUFTLENBQUMsSUFBSSxFQUFFLEdBQUcsS0FBSyxDQUFDLFNBQVMsVUFBVSxFQUFFO1lBQ2hFLEdBQUcsRUFBRSxHQUFHLEtBQUssQ0FBQyxTQUFTLFVBQVU7WUFDakMsS0FBSyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsY0FBYztZQUNoQyxVQUFVLEVBQUUsR0FBRyxlQUFlLEtBQUs7U0FDcEMsQ0FBQyxDQUFDO1FBRUgsSUFBSSxDQUFDLFNBQVMsR0FBRyxJQUFJLHVCQUFTLENBQUMsSUFBSSxFQUFFLEdBQUcsS0FBSyxDQUFDLFNBQVMsV0FBVyxFQUFFO1lBQ2xFLEdBQUcsRUFBRSxHQUFHLEtBQUssQ0FBQyxTQUFTLFdBQVc7WUFDbEMsS0FBSyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsZUFBZTtZQUNqQyxVQUFVLEVBQUUsR0FBRyxlQUFlLE1BQU07U0FDckMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVELDZDQUE2QztJQUM3QyxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQVUsRUFBRSxLQUF1QjtRQUM5QyxPQUFPLENBQUMsS0FBZ0IsRUFBRSxFQUFFO1lBQzFCLE9BQU8sSUFBSSxXQUFXLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUMzQyxDQUFDLENBQUM7SUFDSixDQUFDO0NBQ0Y7QUE3Q0Qsa0NBNkNDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSBcImNvbnN0cnVjdHNcIjtcbmltcG9ydCB7IENmbk91dHB1dCwgUmVtb3ZhbFBvbGljeSB9IGZyb20gXCJhd3MtY2RrLWxpYlwiO1xuaW1wb3J0IHtcbiAgQmFja3VwVmF1bHQgYXMgVmF1bHQsXG4gIExvY2tDb25maWd1cmF0aW9uXG59IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtYmFja3VwXCI7XG5pbXBvcnQgeyBQb2xpY3lEb2N1bWVudCB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtaWFtXCI7XG5pbXBvcnQgeyBDdXN0b21lck1hbmFnZWRLZXkgfSBmcm9tIFwiLi4vc2VjcmV0cy9rbXNcIjtcblxuZXhwb3J0IGludGVyZmFjZSBCYWNrdXBWYXVsdFByb3BzIHtcbiAgdmF1bHROYW1lOiBzdHJpbmc7XG4gIGVuY3J5cHRpb25LZXk/OiBDdXN0b21lck1hbmFnZWRLZXk7XG4gIGFjY2Vzc1BvbGljeT86IFBvbGljeURvY3VtZW50O1xuICBsb2NrQ29uZmlndXJhdGlvbj86IExvY2tDb25maWd1cmF0aW9uO1xuICByZW1vdmFsUG9saWN5PzogUmVtb3ZhbFBvbGljeTtcbn1cblxuZXhwb3J0IGNsYXNzIEJhY2t1cFZhdWx0IGV4dGVuZHMgQ29uc3RydWN0IHtcbiAgcHVibGljIHJlYWRvbmx5IHZhdWx0OiBWYXVsdDtcbiAgcHVibGljIHJlYWRvbmx5IHZhdWx0QXJuOiBDZm5PdXRwdXQ7XG4gIHB1YmxpYyByZWFkb25seSB2YXVsdE5hbWU6IENmbk91dHB1dDtcblxuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogQmFja3VwVmF1bHRQcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCk7XG5cbiAgICBjb25zdCBlbmNyeXB0aW9uS2V5ID1cbiAgICAgIHByb3BzLmVuY3J5cHRpb25LZXkgfHxcbiAgICAgIG5ldyBDdXN0b21lck1hbmFnZWRLZXkodGhpcywgYCR7cHJvcHMudmF1bHROYW1lfUtleWAsIHtcbiAgICAgICAgZGVzY3JpcHRpb246IGBFbmNyeXB0aW9uIGtleSBmb3IgYmFja3VwIHZhdWx0ICR7cHJvcHMudmF1bHROYW1lfWAsXG4gICAgICAgIGFsaWFzTmFtZTogYGNtay9iYWNrdXBWYXVsdC8ke3Byb3BzLnZhdWx0TmFtZX1gXG4gICAgICB9KTtcblxuICAgIHRoaXMudmF1bHQgPSBuZXcgVmF1bHQodGhpcywgYCR7cHJvcHMudmF1bHROYW1lfVZhdWx0YCwge1xuICAgICAgYmFja3VwVmF1bHROYW1lOiBwcm9wcy52YXVsdE5hbWUsXG4gICAgICBlbmNyeXB0aW9uS2V5OiBlbmNyeXB0aW9uS2V5LmtleSxcbiAgICAgIGFjY2Vzc1BvbGljeTogcHJvcHMuYWNjZXNzUG9saWN5LFxuICAgICAgbG9ja0NvbmZpZ3VyYXRpb246IHByb3BzLmxvY2tDb25maWd1cmF0aW9uLFxuICAgICAgcmVtb3ZhbFBvbGljeTogcHJvcHMucmVtb3ZhbFBvbGljeSB8fCBSZW1vdmFsUG9saWN5LlJFVEFJTlxuICAgIH0pO1xuXG4gICAgY29uc3QgdmF1bHROYW1lUGFzY2FsID1cbiAgICAgIHByb3BzLnZhdWx0TmFtZS5jaGFyQXQoMCkudG9VcHBlckNhc2UoKSArIHByb3BzLnZhdWx0TmFtZS5zbGljZSgxKTtcblxuICAgIHRoaXMudmF1bHRBcm4gPSBuZXcgQ2ZuT3V0cHV0KHRoaXMsIGAke3Byb3BzLnZhdWx0TmFtZX1WYXVsdEFybmAsIHtcbiAgICAgIGtleTogYCR7cHJvcHMudmF1bHROYW1lfVZhdWx0QXJuYCxcbiAgICAgIHZhbHVlOiB0aGlzLnZhdWx0LmJhY2t1cFZhdWx0QXJuLFxuICAgICAgZXhwb3J0TmFtZTogYCR7dmF1bHROYW1lUGFzY2FsfUFybmBcbiAgICB9KTtcblxuICAgIHRoaXMudmF1bHROYW1lID0gbmV3IENmbk91dHB1dCh0aGlzLCBgJHtwcm9wcy52YXVsdE5hbWV9VmF1bHROYW1lYCwge1xuICAgICAga2V5OiBgJHtwcm9wcy52YXVsdE5hbWV9VmF1bHROYW1lYCxcbiAgICAgIHZhbHVlOiB0aGlzLnZhdWx0LmJhY2t1cFZhdWx0TmFtZSxcbiAgICAgIGV4cG9ydE5hbWU6IGAke3ZhdWx0TmFtZVBhc2NhbH1OYW1lYFxuICAgIH0pO1xuICB9XG5cbiAgLy8gRmFjdG9yeSBtZXRob2QgZm9sbG93aW5nIGV4aXN0aW5nIHBhdHRlcm5zXG4gIHN0YXRpYyBidWlsZChpZDogc3RyaW5nLCBwcm9wczogQmFja3VwVmF1bHRQcm9wcykge1xuICAgIHJldHVybiAoc2NvcGU6IENvbnN0cnVjdCkgPT4ge1xuICAgICAgcmV0dXJuIG5ldyBCYWNrdXBWYXVsdChzY29wZSwgaWQsIHByb3BzKTtcbiAgICB9O1xuICB9XG59XG4iXX0=
|
|
@@ -0,0 +1,19 @@
|
|
|
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./backupVault"), exports);
|
|
18
|
+
__exportStar(require("./backupPlan"), exports);
|
|
19
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9saWIvcmVzb3VyY2VzL2F3cy9iYWNrdXAvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLGdEQUE4QjtBQUM5QiwrQ0FBNkIiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgKiBmcm9tIFwiLi9iYWNrdXBWYXVsdFwiO1xuZXhwb3J0ICogZnJvbSBcIi4vYmFja3VwUGxhblwiO1xuIl19
|
|
@@ -17,4 +17,5 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
17
17
|
__exportStar(require("./networking"), exports);
|
|
18
18
|
__exportStar(require("./storage"), exports);
|
|
19
19
|
__exportStar(require("./base"), exports);
|
|
20
|
-
|
|
20
|
+
__exportStar(require("./backup"), exports);
|
|
21
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9saWIvcmVzb3VyY2VzL2F3cy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsK0NBQTZCO0FBQzdCLDRDQUEwQjtBQUMxQix5Q0FBdUI7QUFDdkIsMkNBQXlCIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0ICogZnJvbSBcIi4vbmV0d29ya2luZ1wiO1xuZXhwb3J0ICogZnJvbSBcIi4vc3RvcmFnZVwiO1xuZXhwb3J0ICogZnJvbSBcIi4vYmFzZVwiO1xuZXhwb3J0ICogZnJvbSBcIi4vYmFja3VwXCI7XG4iXX0=
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Construct } from "constructs";
|
|
2
|
+
import { IAccount, IPolicy } from "./interfaces";
|
|
3
|
+
import { AccountProps } from "./types";
|
|
4
|
+
/**
|
|
5
|
+
* AWS Account construct for managing member accounts
|
|
6
|
+
*/
|
|
7
|
+
export declare class Account extends Construct implements IAccount {
|
|
8
|
+
readonly accountId: string;
|
|
9
|
+
readonly accountArn: string;
|
|
10
|
+
readonly accountName: string;
|
|
11
|
+
readonly email: string;
|
|
12
|
+
constructor(scope: Construct, id: string, props: AccountProps);
|
|
13
|
+
/**
|
|
14
|
+
* Attach policy to this account
|
|
15
|
+
*/
|
|
16
|
+
attachPolicy(policy: IPolicy): void;
|
|
17
|
+
/**
|
|
18
|
+
* Delegate administrator privileges for a service
|
|
19
|
+
*/
|
|
20
|
+
delegateAdministrator(servicePrincipal: string): void;
|
|
21
|
+
/**
|
|
22
|
+
* Helper to normalize account names for construct IDs
|
|
23
|
+
*/
|
|
24
|
+
private normalizeAccountName;
|
|
25
|
+
/**
|
|
26
|
+
* Helper to normalize policy names for construct IDs
|
|
27
|
+
*/
|
|
28
|
+
private normalizePolicyName;
|
|
29
|
+
/**
|
|
30
|
+
* Helper to normalize service names for construct IDs
|
|
31
|
+
*/
|
|
32
|
+
private normalizeServiceName;
|
|
33
|
+
/**
|
|
34
|
+
* Get the root ID (placeholder - would need custom logic to get this)
|
|
35
|
+
*/
|
|
36
|
+
private getRootId;
|
|
37
|
+
}
|