@fjall/components-infrastructure 2.29.0 → 2.30.3
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__/setup.d.ts +48 -0
- package/dist/lib/__tests__/setup.js +1 -0
- package/dist/lib/app.d.ts +8 -4
- package/dist/lib/app.js +24 -6
- package/dist/lib/config/aws/accountId.d.ts +6 -0
- package/dist/lib/config/aws/accountId.js +33 -0
- package/dist/lib/config/aws/backupGlobalSettings.d.ts +29 -0
- package/dist/lib/config/aws/backupGlobalSettings.js +51 -0
- package/dist/lib/config/aws/costAllocationTags.d.ts +12 -0
- package/dist/lib/config/aws/costAllocationTags.js +48 -0
- package/dist/lib/config/aws/eventBus.d.ts +7 -0
- package/dist/lib/config/aws/eventBus.js +24 -0
- package/dist/lib/config/aws/identityCenterGroupMembership.d.ts +10 -0
- package/dist/lib/config/aws/identityCenterGroupMembership.js +115 -0
- package/dist/lib/config/aws/ipamDelegateAdmin.d.ts +8 -0
- package/dist/lib/config/aws/ipamDelegateAdmin.js +58 -0
- package/dist/lib/config/aws/ipamPoolId.d.ts +10 -0
- package/dist/lib/config/aws/ipamPoolId.js +39 -0
- package/dist/lib/config/aws/organisation.d.ts +30 -0
- package/dist/lib/config/aws/organisation.js +95 -0
- package/dist/lib/config/aws/organisationId.d.ts +7 -0
- package/dist/lib/config/aws/organisationId.js +46 -0
- package/dist/lib/config/aws/organisationsAccess.d.ts +10 -0
- package/dist/lib/config/aws/organisationsAccess.js +50 -0
- package/dist/lib/config/aws/ramSharing.d.ts +4 -0
- package/dist/lib/config/aws/ramSharing.js +35 -0
- package/dist/lib/config/monitoring.d.ts +18 -0
- package/dist/lib/config/monitoring.js +22 -0
- package/dist/lib/lambda-assets/static-site-forms/asset/index.js +175 -0
- package/dist/lib/lambda-assets/static-site-forms/asset/package.json +4 -0
- package/dist/lib/patterns/aws/cdn.d.ts +19 -2
- package/dist/lib/patterns/aws/cdn.js +13 -2
- package/dist/lib/patterns/aws/cicdRole.d.ts +67 -0
- package/dist/lib/patterns/aws/cicdRole.js +68 -0
- package/dist/lib/patterns/aws/compute.js +9 -0
- package/dist/lib/patterns/aws/computeLambda.d.ts +38 -3
- package/dist/lib/patterns/aws/computeLambda.js +29 -2
- package/dist/lib/patterns/aws/hostedZone.d.ts +28 -0
- package/dist/lib/patterns/aws/hostedZone.js +150 -0
- package/dist/lib/patterns/aws/interfaces/pattern.d.ts +134 -5
- package/dist/lib/patterns/aws/interfaces/pattern.js +6 -0
- package/dist/lib/patterns/aws/managedAccount.d.ts +9 -0
- package/dist/lib/patterns/aws/managedAccount.js +55 -0
- package/dist/lib/patterns/aws/managedIdentityCenter.d.ts +4 -0
- package/dist/lib/patterns/aws/managedIdentityCenter.js +24 -0
- package/dist/lib/patterns/aws/managedOrganisation.d.ts +36 -0
- package/dist/lib/patterns/aws/managedOrganisation.js +97 -0
- package/dist/lib/patterns/aws/managedPlatform.d.ts +12 -0
- package/dist/lib/patterns/aws/managedPlatform.js +29 -0
- package/dist/lib/patterns/aws/pattern.d.ts +20 -5
- package/dist/lib/patterns/aws/pattern.js +12 -6
- package/dist/lib/patterns/aws/staticSite.d.ts +59 -0
- package/dist/lib/patterns/aws/staticSite.js +307 -0
- package/dist/lib/patterns/aws/subdomainHostedZone.d.ts +9 -0
- package/dist/lib/patterns/aws/subdomainHostedZone.js +39 -0
- package/dist/lib/resources/aws/cdn/cloudFront.d.ts +35 -2
- package/dist/lib/resources/aws/cdn/cloudFront.js +63 -25
- package/dist/lib/resources/aws/cdn/index.d.ts +1 -0
- package/dist/lib/resources/aws/cdn/index.js +1 -0
- package/dist/lib/resources/aws/cdn/responseHeadersPolicy.d.ts +56 -0
- package/dist/lib/resources/aws/cdn/responseHeadersPolicy.js +92 -0
- package/dist/lib/resources/aws/cicd/cicdRole.d.ts +65 -0
- package/dist/lib/resources/aws/cicd/cicdRole.js +191 -0
- package/dist/lib/resources/aws/compute/ecsFreeTier.d.ts +75 -0
- package/dist/lib/resources/aws/compute/ecsFreeTier.js +1 -0
- package/dist/lib/resources/aws/compute/ecsImages.js +3 -25
- package/dist/lib/resources/aws/compute/ecsSpot.d.ts +75 -0
- package/dist/lib/resources/aws/compute/ecsSpot.js +1 -0
- package/dist/lib/resources/aws/compute/imageTagParameter.d.ts +12 -0
- package/dist/lib/resources/aws/compute/imageTagParameter.js +32 -0
- package/dist/lib/resources/aws/compute/lambda.d.ts +7 -0
- package/dist/lib/resources/aws/compute/utilities/capacityProviderDrainWaiter.d.ts +20 -0
- package/dist/lib/resources/aws/compute/utilities/capacityProviderDrainWaiter.js +1 -0
- package/dist/lib/resources/aws/database/database.d.ts +14 -0
- package/dist/lib/resources/aws/database/database.js +28 -0
- package/dist/lib/resources/aws/database/databaseInstance.d.ts +15 -0
- package/dist/lib/resources/aws/database/databaseInstance.js +30 -0
- package/dist/lib/resources/aws/iam/identityCenter/attachManagedPolicy.d.ts +13 -0
- package/dist/lib/resources/aws/iam/identityCenter/attachManagedPolicy.js +52 -0
- package/dist/lib/resources/aws/iam/securityGroup.d.ts +5 -0
- package/dist/lib/resources/aws/iam/securityGroup.js +14 -0
- package/dist/lib/resources/aws/monitoring/monitoringRole.d.ts +28 -0
- package/dist/lib/resources/aws/monitoring/monitoringRole.js +125 -0
- package/dist/lib/resources/aws/networking/domainCertificate.d.ts +7 -0
- package/dist/lib/resources/aws/networking/domainCertificate.js +9 -7
- package/dist/lib/resources/aws/utilities/cfnOutput.d.ts +5 -0
- package/dist/lib/resources/aws/utilities/cfnOutput.js +1 -0
- package/dist/lib/utils/addSuffixToEmail.js +5 -1
- package/dist/lib/utils/capitalizeString.d.ts +1 -0
- package/dist/lib/utils/capitalizeString.js +7 -0
- package/package.json +7 -5
- package/dist/lib/config/aws/identityCenterMembership.d.ts +0 -11
- package/dist/lib/config/aws/identityCenterMembership.js +0 -61
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { CfnOutput, type StackProps } from "aws-cdk-lib";
|
|
2
|
+
import { Construct } from "constructs";
|
|
3
|
+
import { type Account as ExistingAccounts } from "@aws-sdk/client-organizations";
|
|
4
|
+
import { type KeyValue } from "../../types";
|
|
5
|
+
interface OrganisationProps extends StackProps {
|
|
6
|
+
organisationName: string;
|
|
7
|
+
accounts: AccountsConfig;
|
|
8
|
+
orgEmail: string;
|
|
9
|
+
existingAccounts?: ExistingAccounts[];
|
|
10
|
+
}
|
|
11
|
+
type AccountsConfig = {
|
|
12
|
+
readonly [key: string]: readonly string[] | string;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* A construct for creating multi environment organisations with a production, staging and development account.
|
|
16
|
+
*/
|
|
17
|
+
export default class Organisation extends Construct {
|
|
18
|
+
accountId: CfnOutput;
|
|
19
|
+
private existingAccounts?;
|
|
20
|
+
private accounts;
|
|
21
|
+
private organisation;
|
|
22
|
+
private organisationalUnits;
|
|
23
|
+
constructor(scope: Construct, id: string, props: OrganisationProps);
|
|
24
|
+
private addOrganisation;
|
|
25
|
+
private addOrganisationUnitsAndAccounts;
|
|
26
|
+
private addOrganisationalUnit;
|
|
27
|
+
private addAccount;
|
|
28
|
+
getAccounts(): KeyValue;
|
|
29
|
+
}
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
4
|
+
const constructs_1 = require("constructs");
|
|
5
|
+
const stripAndCamelCase_1 = require("../../utils/stripAndCamelCase");
|
|
6
|
+
const cdk_organizations_1 = require("@pepperize/cdk-organizations");
|
|
7
|
+
const addSuffixToEmail_1 = require("../../utils/addSuffixToEmail");
|
|
8
|
+
/**
|
|
9
|
+
* A construct for creating multi environment organisations with a production, staging and development account.
|
|
10
|
+
*/
|
|
11
|
+
class Organisation extends constructs_1.Construct {
|
|
12
|
+
constructor(scope, id, props) {
|
|
13
|
+
super(scope, id);
|
|
14
|
+
this.accounts = {};
|
|
15
|
+
this.organisationalUnits = [];
|
|
16
|
+
this.existingAccounts = props.existingAccounts;
|
|
17
|
+
this.addOrganisation(props.organisationName);
|
|
18
|
+
this.addOrganisationUnitsAndAccounts(props.accounts, props.orgEmail);
|
|
19
|
+
}
|
|
20
|
+
addOrganisation(organisationName) {
|
|
21
|
+
this.organisation = new cdk_organizations_1.Organization(this, organisationName, {
|
|
22
|
+
featureSet: cdk_organizations_1.FeatureSet.ALL
|
|
23
|
+
});
|
|
24
|
+
// TODO: Validate this enables trusted access
|
|
25
|
+
this.organisation.enableAwsServiceAccess("account.amazonaws.com");
|
|
26
|
+
const enforcedPolicyTypes = [
|
|
27
|
+
cdk_organizations_1.PolicyType.SERVICE_CONTROL_POLICY,
|
|
28
|
+
cdk_organizations_1.PolicyType.TAG_POLICY,
|
|
29
|
+
cdk_organizations_1.PolicyType.BACKUP_POLICY,
|
|
30
|
+
cdk_organizations_1.PolicyType.AISERVICES_OPT_OUT_POLICY
|
|
31
|
+
];
|
|
32
|
+
for (const policyType of enforcedPolicyTypes) {
|
|
33
|
+
this.organisation.enablePolicyType(policyType);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
addOrganisationUnitsAndAccounts(accounts, orgEmail) {
|
|
37
|
+
for (const [environmentType, accountList] of Object.entries(accounts)) {
|
|
38
|
+
// Create OU for each environment type
|
|
39
|
+
const ouName = environmentType.charAt(0).toUpperCase() + environmentType.slice(1);
|
|
40
|
+
const orgUnit = this.addOrganisationalUnit(`${ouName}OrganizationalUnit`, ouName);
|
|
41
|
+
// Convert single account to array for uniform processing
|
|
42
|
+
const accountsArray = Array.isArray(accountList)
|
|
43
|
+
? accountList
|
|
44
|
+
: [accountList];
|
|
45
|
+
// Add accounts to this OU
|
|
46
|
+
for (const accountName of accountsArray) {
|
|
47
|
+
const accountNameId = (0, stripAndCamelCase_1.stripAndCamelCase)(accountName);
|
|
48
|
+
const importedAccount = this.existingAccounts?.find((account) => account.Name === accountName);
|
|
49
|
+
const accountEmail = importedAccount
|
|
50
|
+
? importedAccount.Email
|
|
51
|
+
: (0, addSuffixToEmail_1.default)(orgEmail, accountNameId.toLowerCase());
|
|
52
|
+
if (accountEmail) {
|
|
53
|
+
this.addAccount(`${accountNameId}Account`, accountName, accountEmail, { env: environmentType }, orgUnit);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
addOrganisationalUnit(id, name) {
|
|
59
|
+
const ou = new cdk_organizations_1.OrganizationalUnit(this, id, {
|
|
60
|
+
organizationalUnitName: name,
|
|
61
|
+
parent: this.organisation.root,
|
|
62
|
+
importOnDuplicate: true
|
|
63
|
+
});
|
|
64
|
+
this.organisationalUnits.push(ou);
|
|
65
|
+
return ou;
|
|
66
|
+
}
|
|
67
|
+
addAccount(id, name, email, tags, organisationalUnit) {
|
|
68
|
+
const acc = new cdk_organizations_1.Account(this, id, {
|
|
69
|
+
accountName: name,
|
|
70
|
+
email: email,
|
|
71
|
+
parent: organisationalUnit,
|
|
72
|
+
importOnDuplicate: true
|
|
73
|
+
});
|
|
74
|
+
for (const tag in tags) {
|
|
75
|
+
aws_cdk_lib_1.Tags.of(acc).add(tag, tags[tag]);
|
|
76
|
+
}
|
|
77
|
+
this.accounts[name] = acc.accountId;
|
|
78
|
+
new aws_cdk_lib_1.CfnOutput(this, `${id}Id`, {
|
|
79
|
+
key: `${id}Id`,
|
|
80
|
+
value: acc.accountId,
|
|
81
|
+
exportName: `${id}Id`
|
|
82
|
+
});
|
|
83
|
+
new aws_cdk_lib_1.CfnOutput(this, `${id}Arn`, {
|
|
84
|
+
key: `${id}Arn`,
|
|
85
|
+
value: acc.accountArn,
|
|
86
|
+
exportName: `${id}Arn`
|
|
87
|
+
});
|
|
88
|
+
return acc;
|
|
89
|
+
}
|
|
90
|
+
getAccounts() {
|
|
91
|
+
return this.accounts;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
exports.default = Organisation;
|
|
95
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3JnYW5pc2F0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vbGliL2NvbmZpZy9hd3Mvb3JnYW5pc2F0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsNkNBQStEO0FBQy9ELDJDQUF1QztBQUN2QyxxRUFBa0U7QUFFbEUsb0VBTXNDO0FBQ3RDLG1FQUE0RDtBQWM1RDs7R0FFRztBQUVILE1BQXFCLFlBQWEsU0FBUSxzQkFBUztJQVFqRCxZQUFZLEtBQWdCLEVBQUUsRUFBVSxFQUFFLEtBQXdCO1FBQ2hFLEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFMWCxhQUFRLEdBQWEsRUFBRSxDQUFDO1FBRXhCLHdCQUFtQixHQUF5QixFQUFFLENBQUM7UUFLckQsSUFBSSxDQUFDLGdCQUFnQixHQUFHLEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQztRQUMvQyxJQUFJLENBQUMsZUFBZSxDQUFDLEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1FBQzdDLElBQUksQ0FBQywrQkFBK0IsQ0FBQyxLQUFLLENBQUMsUUFBUSxFQUFFLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUN2RSxDQUFDO0lBRU8sZUFBZSxDQUFDLGdCQUF3QjtRQUM5QyxJQUFJLENBQUMsWUFBWSxHQUFHLElBQUksZ0NBQVksQ0FBQyxJQUFJLEVBQUUsZ0JBQWdCLEVBQUU7WUFDM0QsVUFBVSxFQUFFLDhCQUFVLENBQUMsR0FBRztTQUMzQixDQUFDLENBQUM7UUFFSCw2Q0FBNkM7UUFDN0MsSUFBSSxDQUFDLFlBQVksQ0FBQyxzQkFBc0IsQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDO1FBRWxFLE1BQU0sbUJBQW1CLEdBQWlCO1lBQ3hDLDhCQUFVLENBQUMsc0JBQXNCO1lBQ2pDLDhCQUFVLENBQUMsVUFBVTtZQUNyQiw4QkFBVSxDQUFDLGFBQWE7WUFDeEIsOEJBQVUsQ0FBQyx5QkFBeUI7U0FDckMsQ0FBQztRQUVGLEtBQUssTUFBTSxVQUFVLElBQUksbUJBQW1CLEVBQUUsQ0FBQztZQUM3QyxJQUFJLENBQUMsWUFBWSxDQUFDLGdCQUFnQixDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ2pELENBQUM7SUFDSCxDQUFDO0lBRU8sK0JBQStCLENBQ3JDLFFBQXdCLEVBQ3hCLFFBQWdCO1FBRWhCLEtBQUssTUFBTSxDQUFDLGVBQWUsRUFBRSxXQUFXLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUM7WUFDdEUsc0NBQXNDO1lBQ3RDLE1BQU0sTUFBTSxHQUNWLGVBQWUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsV0FBVyxFQUFFLEdBQUcsZUFBZSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUNyRSxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMscUJBQXFCLENBQ3hDLEdBQUcsTUFBTSxvQkFBb0IsRUFDN0IsTUFBTSxDQUNQLENBQUM7WUFFRix5REFBeUQ7WUFDekQsTUFBTSxhQUFhLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUM7Z0JBQzlDLENBQUMsQ0FBQyxXQUFXO2dCQUNiLENBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxDQUFDO1lBRWxCLDBCQUEwQjtZQUMxQixLQUFLLE1BQU0sV0FBVyxJQUFJLGFBQWEsRUFBRSxDQUFDO2dCQUN4QyxNQUFNLGFBQWEsR0FBRyxJQUFBLHFDQUFpQixFQUFDLFdBQVcsQ0FBQyxDQUFDO2dCQUVyRCxNQUFNLGVBQWUsR0FBRyxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsSUFBSSxDQUNqRCxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFDLElBQUksS0FBSyxXQUFXLENBQzFDLENBQUM7Z0JBQ0YsTUFBTSxZQUFZLEdBQUcsZUFBZTtvQkFDbEMsQ0FBQyxDQUFDLGVBQWUsQ0FBQyxLQUFLO29CQUN2QixDQUFDLENBQUMsSUFBQSwwQkFBZ0IsRUFBQyxRQUFRLEVBQUUsYUFBYSxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUM7Z0JBRTVELElBQUksWUFBWSxFQUFFLENBQUM7b0JBQ2pCLElBQUksQ0FBQyxVQUFVLENBQ2IsR0FBRyxhQUFhLFNBQVMsRUFDekIsV0FBVyxFQUNYLFlBQVksRUFDWixFQUFFLEdBQUcsRUFBRSxlQUFlLEVBQUUsRUFDeEIsT0FBTyxDQUNSLENBQUM7Z0JBQ0osQ0FBQztZQUNILENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVPLHFCQUFxQixDQUFDLEVBQVUsRUFBRSxJQUFZO1FBQ3BELE1BQU0sRUFBRSxHQUFHLElBQUksc0NBQWtCLENBQUMsSUFBSSxFQUFFLEVBQUUsRUFBRTtZQUMxQyxzQkFBc0IsRUFBRSxJQUFJO1lBQzVCLE1BQU0sRUFBRSxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUk7WUFDOUIsaUJBQWlCLEVBQUUsSUFBSTtTQUN4QixDQUFDLENBQUM7UUFFSCxJQUFJLENBQUMsbUJBQW1CLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ2xDLE9BQU8sRUFBRSxDQUFDO0lBQ1osQ0FBQztJQUVPLFVBQVUsQ0FDaEIsRUFBVSxFQUNWLElBQVksRUFDWixLQUFhLEVBQ2IsSUFBK0IsRUFDL0Isa0JBQXNDO1FBRXRDLE1BQU0sR0FBRyxHQUFHLElBQUksMkJBQU8sQ0FBQyxJQUFJLEVBQUUsRUFBRSxFQUFFO1lBQ2hDLFdBQVcsRUFBRSxJQUFJO1lBQ2pCLEtBQUssRUFBRSxLQUFLO1lBQ1osTUFBTSxFQUFFLGtCQUFrQjtZQUMxQixpQkFBaUIsRUFBRSxJQUFJO1NBQ3hCLENBQUMsQ0FBQztRQUVILEtBQUssTUFBTSxHQUFHLElBQUksSUFBSSxFQUFFLENBQUM7WUFDdkIsa0JBQUksQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUNuQyxDQUFDO1FBRUQsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsR0FBRyxHQUFHLENBQUMsU0FBUyxDQUFDO1FBRXBDLElBQUksdUJBQVMsQ0FBQyxJQUFJLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRTtZQUM3QixHQUFHLEVBQUUsR0FBRyxFQUFFLElBQUk7WUFDZCxLQUFLLEVBQUUsR0FBRyxDQUFDLFNBQVM7WUFDcEIsVUFBVSxFQUFFLEdBQUcsRUFBRSxJQUFJO1NBQ3RCLENBQUMsQ0FBQztRQUNILElBQUksdUJBQVMsQ0FBQyxJQUFJLEVBQUUsR0FBRyxFQUFFLEtBQUssRUFBRTtZQUM5QixHQUFHLEVBQUUsR0FBRyxFQUFFLEtBQUs7WUFDZixLQUFLLEVBQUUsR0FBRyxDQUFDLFVBQVU7WUFDckIsVUFBVSxFQUFFLEdBQUcsRUFBRSxLQUFLO1NBQ3ZCLENBQUMsQ0FBQztRQUVILE9BQU8sR0FBRyxDQUFDO0lBQ2IsQ0FBQztJQUVNLFdBQVc7UUFDaEIsT0FBTyxJQUFJLENBQUMsUUFBUSxDQUFDO0lBQ3ZCLENBQUM7Q0FDRjtBQTlIRCwrQkE4SEMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDZm5PdXRwdXQsIFRhZ3MsIHR5cGUgU3RhY2tQcm9wcyB9IGZyb20gXCJhd3MtY2RrLWxpYlwiO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSBcImNvbnN0cnVjdHNcIjtcbmltcG9ydCB7IHN0cmlwQW5kQ2FtZWxDYXNlIH0gZnJvbSBcIi4uLy4uL3V0aWxzL3N0cmlwQW5kQ2FtZWxDYXNlXCI7XG5pbXBvcnQgeyB0eXBlIEFjY291bnQgYXMgRXhpc3RpbmdBY2NvdW50cyB9IGZyb20gXCJAYXdzLXNkay9jbGllbnQtb3JnYW5pemF0aW9uc1wiO1xuaW1wb3J0IHtcbiAgQWNjb3VudCxcbiAgRmVhdHVyZVNldCxcbiAgT3JnYW5pemF0aW9uLFxuICBPcmdhbml6YXRpb25hbFVuaXQsXG4gIFBvbGljeVR5cGVcbn0gZnJvbSBcIkBwZXBwZXJpemUvY2RrLW9yZ2FuaXphdGlvbnNcIjtcbmltcG9ydCBhZGRTdWZmaXhUb0VtYWlsIGZyb20gXCIuLi8uLi91dGlscy9hZGRTdWZmaXhUb0VtYWlsXCI7XG5pbXBvcnQgeyB0eXBlIEtleVZhbHVlIH0gZnJvbSBcIi4uLy4uL3R5cGVzXCI7XG5cbmludGVyZmFjZSBPcmdhbmlzYXRpb25Qcm9wcyBleHRlbmRzIFN0YWNrUHJvcHMge1xuICBvcmdhbmlzYXRpb25OYW1lOiBzdHJpbmc7XG4gIGFjY291bnRzOiBBY2NvdW50c0NvbmZpZztcbiAgb3JnRW1haWw6IHN0cmluZztcbiAgZXhpc3RpbmdBY2NvdW50cz86IEV4aXN0aW5nQWNjb3VudHNbXTtcbn1cblxudHlwZSBBY2NvdW50c0NvbmZpZyA9IHtcbiAgcmVhZG9ubHkgW2tleTogc3RyaW5nXTogcmVhZG9ubHkgc3RyaW5nW10gfCBzdHJpbmc7XG59O1xuXG4vKipcbiAqIEEgY29uc3RydWN0IGZvciBjcmVhdGluZyBtdWx0aSBlbnZpcm9ubWVudCBvcmdhbmlzYXRpb25zIHdpdGggYSBwcm9kdWN0aW9uLCBzdGFnaW5nIGFuZCBkZXZlbG9wbWVudCBhY2NvdW50LlxuICovXG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE9yZ2FuaXNhdGlvbiBleHRlbmRzIENvbnN0cnVjdCB7XG4gIHB1YmxpYyBhY2NvdW50SWQ6IENmbk91dHB1dDtcblxuICBwcml2YXRlIGV4aXN0aW5nQWNjb3VudHM/OiBFeGlzdGluZ0FjY291bnRzW107XG4gIHByaXZhdGUgYWNjb3VudHM6IEtleVZhbHVlID0ge307XG4gIHByaXZhdGUgb3JnYW5pc2F0aW9uOiBPcmdhbml6YXRpb247XG4gIHByaXZhdGUgb3JnYW5pc2F0aW9uYWxVbml0czogT3JnYW5pemF0aW9uYWxVbml0W10gPSBbXTtcblxuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogT3JnYW5pc2F0aW9uUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuXG4gICAgdGhpcy5leGlzdGluZ0FjY291bnRzID0gcHJvcHMuZXhpc3RpbmdBY2NvdW50cztcbiAgICB0aGlzLmFkZE9yZ2FuaXNhdGlvbihwcm9wcy5vcmdhbmlzYXRpb25OYW1lKTtcbiAgICB0aGlzLmFkZE9yZ2FuaXNhdGlvblVuaXRzQW5kQWNjb3VudHMocHJvcHMuYWNjb3VudHMsIHByb3BzLm9yZ0VtYWlsKTtcbiAgfVxuXG4gIHByaXZhdGUgYWRkT3JnYW5pc2F0aW9uKG9yZ2FuaXNhdGlvbk5hbWU6IHN0cmluZykge1xuICAgIHRoaXMub3JnYW5pc2F0aW9uID0gbmV3IE9yZ2FuaXphdGlvbih0aGlzLCBvcmdhbmlzYXRpb25OYW1lLCB7XG4gICAgICBmZWF0dXJlU2V0OiBGZWF0dXJlU2V0LkFMTFxuICAgIH0pO1xuXG4gICAgLy8gVE9ETzogVmFsaWRhdGUgdGhpcyBlbmFibGVzIHRydXN0ZWQgYWNjZXNzXG4gICAgdGhpcy5vcmdhbmlzYXRpb24uZW5hYmxlQXdzU2VydmljZUFjY2VzcyhcImFjY291bnQuYW1hem9uYXdzLmNvbVwiKTtcblxuICAgIGNvbnN0IGVuZm9yY2VkUG9saWN5VHlwZXM6IFBvbGljeVR5cGVbXSA9IFtcbiAgICAgIFBvbGljeVR5cGUuU0VSVklDRV9DT05UUk9MX1BPTElDWSxcbiAgICAgIFBvbGljeVR5cGUuVEFHX1BPTElDWSxcbiAgICAgIFBvbGljeVR5cGUuQkFDS1VQX1BPTElDWSxcbiAgICAgIFBvbGljeVR5cGUuQUlTRVJWSUNFU19PUFRfT1VUX1BPTElDWVxuICAgIF07XG5cbiAgICBmb3IgKGNvbnN0IHBvbGljeVR5cGUgb2YgZW5mb3JjZWRQb2xpY3lUeXBlcykge1xuICAgICAgdGhpcy5vcmdhbmlzYXRpb24uZW5hYmxlUG9saWN5VHlwZShwb2xpY3lUeXBlKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFkZE9yZ2FuaXNhdGlvblVuaXRzQW5kQWNjb3VudHMoXG4gICAgYWNjb3VudHM6IEFjY291bnRzQ29uZmlnLFxuICAgIG9yZ0VtYWlsOiBzdHJpbmdcbiAgKSB7XG4gICAgZm9yIChjb25zdCBbZW52aXJvbm1lbnRUeXBlLCBhY2NvdW50TGlzdF0gb2YgT2JqZWN0LmVudHJpZXMoYWNjb3VudHMpKSB7XG4gICAgICAvLyBDcmVhdGUgT1UgZm9yIGVhY2ggZW52aXJvbm1lbnQgdHlwZVxuICAgICAgY29uc3Qgb3VOYW1lID1cbiAgICAgICAgZW52aXJvbm1lbnRUeXBlLmNoYXJBdCgwKS50b1VwcGVyQ2FzZSgpICsgZW52aXJvbm1lbnRUeXBlLnNsaWNlKDEpO1xuICAgICAgY29uc3Qgb3JnVW5pdCA9IHRoaXMuYWRkT3JnYW5pc2F0aW9uYWxVbml0KFxuICAgICAgICBgJHtvdU5hbWV9T3JnYW5pemF0aW9uYWxVbml0YCxcbiAgICAgICAgb3VOYW1lXG4gICAgICApO1xuXG4gICAgICAvLyBDb252ZXJ0IHNpbmdsZSBhY2NvdW50IHRvIGFycmF5IGZvciB1bmlmb3JtIHByb2Nlc3NpbmdcbiAgICAgIGNvbnN0IGFjY291bnRzQXJyYXkgPSBBcnJheS5pc0FycmF5KGFjY291bnRMaXN0KVxuICAgICAgICA/IGFjY291bnRMaXN0XG4gICAgICAgIDogW2FjY291bnRMaXN0XTtcblxuICAgICAgLy8gQWRkIGFjY291bnRzIHRvIHRoaXMgT1VcbiAgICAgIGZvciAoY29uc3QgYWNjb3VudE5hbWUgb2YgYWNjb3VudHNBcnJheSkge1xuICAgICAgICBjb25zdCBhY2NvdW50TmFtZUlkID0gc3RyaXBBbmRDYW1lbENhc2UoYWNjb3VudE5hbWUpO1xuXG4gICAgICAgIGNvbnN0IGltcG9ydGVkQWNjb3VudCA9IHRoaXMuZXhpc3RpbmdBY2NvdW50cz8uZmluZChcbiAgICAgICAgICAoYWNjb3VudCkgPT4gYWNjb3VudC5OYW1lID09PSBhY2NvdW50TmFtZVxuICAgICAgICApO1xuICAgICAgICBjb25zdCBhY2NvdW50RW1haWwgPSBpbXBvcnRlZEFjY291bnRcbiAgICAgICAgICA/IGltcG9ydGVkQWNjb3VudC5FbWFpbFxuICAgICAgICAgIDogYWRkU3VmZml4VG9FbWFpbChvcmdFbWFpbCwgYWNjb3VudE5hbWVJZC50b0xvd2VyQ2FzZSgpKTtcblxuICAgICAgICBpZiAoYWNjb3VudEVtYWlsKSB7XG4gICAgICAgICAgdGhpcy5hZGRBY2NvdW50KFxuICAgICAgICAgICAgYCR7YWNjb3VudE5hbWVJZH1BY2NvdW50YCxcbiAgICAgICAgICAgIGFjY291bnROYW1lLFxuICAgICAgICAgICAgYWNjb3VudEVtYWlsLFxuICAgICAgICAgICAgeyBlbnY6IGVudmlyb25tZW50VHlwZSB9LFxuICAgICAgICAgICAgb3JnVW5pdFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFkZE9yZ2FuaXNhdGlvbmFsVW5pdChpZDogc3RyaW5nLCBuYW1lOiBzdHJpbmcpOiBPcmdhbml6YXRpb25hbFVuaXQge1xuICAgIGNvbnN0IG91ID0gbmV3IE9yZ2FuaXphdGlvbmFsVW5pdCh0aGlzLCBpZCwge1xuICAgICAgb3JnYW5pemF0aW9uYWxVbml0TmFtZTogbmFtZSxcbiAgICAgIHBhcmVudDogdGhpcy5vcmdhbmlzYXRpb24ucm9vdCxcbiAgICAgIGltcG9ydE9uRHVwbGljYXRlOiB0cnVlXG4gICAgfSk7XG5cbiAgICB0aGlzLm9yZ2FuaXNhdGlvbmFsVW5pdHMucHVzaChvdSk7XG4gICAgcmV0dXJuIG91O1xuICB9XG5cbiAgcHJpdmF0ZSBhZGRBY2NvdW50KFxuICAgIGlkOiBzdHJpbmcsXG4gICAgbmFtZTogc3RyaW5nLFxuICAgIGVtYWlsOiBzdHJpbmcsXG4gICAgdGFnczogeyBba2V5OiBzdHJpbmddOiBzdHJpbmcgfSxcbiAgICBvcmdhbmlzYXRpb25hbFVuaXQ6IE9yZ2FuaXphdGlvbmFsVW5pdFxuICApOiBBY2NvdW50IHtcbiAgICBjb25zdCBhY2MgPSBuZXcgQWNjb3VudCh0aGlzLCBpZCwge1xuICAgICAgYWNjb3VudE5hbWU6IG5hbWUsXG4gICAgICBlbWFpbDogZW1haWwsXG4gICAgICBwYXJlbnQ6IG9yZ2FuaXNhdGlvbmFsVW5pdCxcbiAgICAgIGltcG9ydE9uRHVwbGljYXRlOiB0cnVlXG4gICAgfSk7XG5cbiAgICBmb3IgKGNvbnN0IHRhZyBpbiB0YWdzKSB7XG4gICAgICBUYWdzLm9mKGFjYykuYWRkKHRhZywgdGFnc1t0YWddKTtcbiAgICB9XG5cbiAgICB0aGlzLmFjY291bnRzW25hbWVdID0gYWNjLmFjY291bnRJZDtcblxuICAgIG5ldyBDZm5PdXRwdXQodGhpcywgYCR7aWR9SWRgLCB7XG4gICAgICBrZXk6IGAke2lkfUlkYCxcbiAgICAgIHZhbHVlOiBhY2MuYWNjb3VudElkLFxuICAgICAgZXhwb3J0TmFtZTogYCR7aWR9SWRgXG4gICAgfSk7XG4gICAgbmV3IENmbk91dHB1dCh0aGlzLCBgJHtpZH1Bcm5gLCB7XG4gICAgICBrZXk6IGAke2lkfUFybmAsXG4gICAgICB2YWx1ZTogYWNjLmFjY291bnRBcm4sXG4gICAgICBleHBvcnROYW1lOiBgJHtpZH1Bcm5gXG4gICAgfSk7XG5cbiAgICByZXR1cm4gYWNjO1xuICB9XG5cbiAgcHVibGljIGdldEFjY291bnRzKCkge1xuICAgIHJldHVybiB0aGlzLmFjY291bnRzO1xuICB9XG59XG4iXX0=
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { CfnOutput } from "aws-cdk-lib";
|
|
2
|
+
import { Construct } from "constructs";
|
|
3
|
+
export declare class OrganisationId extends Construct {
|
|
4
|
+
readonly organisationId: CfnOutput;
|
|
5
|
+
readonly organisationAccountArn: CfnOutput;
|
|
6
|
+
constructor(scope: Construct, id: string);
|
|
7
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OrganisationId = void 0;
|
|
4
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
5
|
+
const customResources = require("aws-cdk-lib/custom-resources");
|
|
6
|
+
const aws_iam_1 = require("aws-cdk-lib/aws-iam");
|
|
7
|
+
const constructs_1 = require("constructs");
|
|
8
|
+
const awsCustomResource_1 = require("../../resources/aws/utilities/awsCustomResource");
|
|
9
|
+
class OrganisationId extends constructs_1.Construct {
|
|
10
|
+
constructor(scope, id) {
|
|
11
|
+
super(scope, id);
|
|
12
|
+
const organisation = new awsCustomResource_1.AwsCustomResource(this, "OrganisationResource", {
|
|
13
|
+
functionName: "organisationId",
|
|
14
|
+
onCreate: {
|
|
15
|
+
service: "organizations",
|
|
16
|
+
action: "DescribeOrganizationCommand", // https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Organizations.html#describeOrganization-property
|
|
17
|
+
physicalResourceId: customResources.PhysicalResourceId.of("organisationId")
|
|
18
|
+
},
|
|
19
|
+
onUpdate: {
|
|
20
|
+
service: "organizations",
|
|
21
|
+
action: "DescribeOrganizationCommand", // https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Organizations.html#describeOrganization-property
|
|
22
|
+
physicalResourceId: customResources.PhysicalResourceId.of("organisationId")
|
|
23
|
+
},
|
|
24
|
+
resourceType: "Custom::DescribeOrganisation",
|
|
25
|
+
policy: customResources.AwsCustomResourcePolicy.fromStatements([
|
|
26
|
+
new aws_iam_1.PolicyStatement({
|
|
27
|
+
actions: ["organizations:DescribeOrganization"],
|
|
28
|
+
resources: ["*"],
|
|
29
|
+
effect: aws_iam_1.Effect.ALLOW
|
|
30
|
+
})
|
|
31
|
+
])
|
|
32
|
+
});
|
|
33
|
+
this.organisationId = new aws_cdk_lib_1.CfnOutput(this, "OrganisationIdOutput", {
|
|
34
|
+
key: "OrganisationId",
|
|
35
|
+
value: organisation.getResponseField("Organization.Id"),
|
|
36
|
+
exportName: "OrganisationId"
|
|
37
|
+
});
|
|
38
|
+
this.organisationAccountArn = new aws_cdk_lib_1.CfnOutput(this, "OrganisationAccountArnOutput", {
|
|
39
|
+
key: "OrganisationAccountArn",
|
|
40
|
+
value: organisation.getResponseField("Organization.MasterAccountArn"),
|
|
41
|
+
exportName: "OrganisationAccountArn"
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
exports.OrganisationId = OrganisationId;
|
|
46
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3JnYW5pc2F0aW9uSWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9saWIvY29uZmlnL2F3cy9vcmdhbmlzYXRpb25JZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSw2Q0FBd0M7QUFDeEMsZ0VBQWdFO0FBQ2hFLGlEQUE4RDtBQUM5RCwyQ0FBdUM7QUFFdkMsdUZBQW9GO0FBRXBGLE1BQWEsY0FBZSxTQUFRLHNCQUFTO0lBSTNDLFlBQVksS0FBZ0IsRUFBRSxFQUFVO1FBQ3RDLEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFFakIsTUFBTSxZQUFZLEdBQUcsSUFBSSxxQ0FBaUIsQ0FBQyxJQUFJLEVBQUUsc0JBQXNCLEVBQUU7WUFDdkUsWUFBWSxFQUFFLGdCQUFnQjtZQUM5QixRQUFRLEVBQUU7Z0JBQ1IsT0FBTyxFQUFFLGVBQWU7Z0JBQ3hCLE1BQU0sRUFBRSw2QkFBNkIsRUFBRSwyR0FBMkc7Z0JBQ2xKLGtCQUFrQixFQUNoQixlQUFlLENBQUMsa0JBQWtCLENBQUMsRUFBRSxDQUFDLGdCQUFnQixDQUFDO2FBQzFEO1lBQ0QsUUFBUSxFQUFFO2dCQUNSLE9BQU8sRUFBRSxlQUFlO2dCQUN4QixNQUFNLEVBQUUsNkJBQTZCLEVBQUUsMkdBQTJHO2dCQUNsSixrQkFBa0IsRUFDaEIsZUFBZSxDQUFDLGtCQUFrQixDQUFDLEVBQUUsQ0FBQyxnQkFBZ0IsQ0FBQzthQUMxRDtZQUNELFlBQVksRUFBRSw4QkFBOEI7WUFDNUMsTUFBTSxFQUFFLGVBQWUsQ0FBQyx1QkFBdUIsQ0FBQyxjQUFjLENBQUM7Z0JBQzdELElBQUkseUJBQWUsQ0FBQztvQkFDbEIsT0FBTyxFQUFFLENBQUMsb0NBQW9DLENBQUM7b0JBQy9DLFNBQVMsRUFBRSxDQUFDLEdBQUcsQ0FBQztvQkFDaEIsTUFBTSxFQUFFLGdCQUFNLENBQUMsS0FBSztpQkFDckIsQ0FBQzthQUNILENBQUM7U0FDSCxDQUFDLENBQUM7UUFFSCxJQUFJLENBQUMsY0FBYyxHQUFHLElBQUksdUJBQVMsQ0FBQyxJQUFJLEVBQUUsc0JBQXNCLEVBQUU7WUFDaEUsR0FBRyxFQUFFLGdCQUFnQjtZQUNyQixLQUFLLEVBQUUsWUFBWSxDQUFDLGdCQUFnQixDQUFDLGlCQUFpQixDQUFDO1lBQ3ZELFVBQVUsRUFBRSxnQkFBZ0I7U0FDN0IsQ0FBQyxDQUFDO1FBRUgsSUFBSSxDQUFDLHNCQUFzQixHQUFHLElBQUksdUJBQVMsQ0FDekMsSUFBSSxFQUNKLDhCQUE4QixFQUM5QjtZQUNFLEdBQUcsRUFBRSx3QkFBd0I7WUFDN0IsS0FBSyxFQUFFLFlBQVksQ0FBQyxnQkFBZ0IsQ0FBQywrQkFBK0IsQ0FBQztZQUNyRSxVQUFVLEVBQUUsd0JBQXdCO1NBQ3JDLENBQ0YsQ0FBQztJQUNKLENBQUM7Q0FDRjtBQS9DRCx3Q0ErQ0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDZm5PdXRwdXQgfSBmcm9tIFwiYXdzLWNkay1saWJcIjtcbmltcG9ydCAqIGFzIGN1c3RvbVJlc291cmNlcyBmcm9tIFwiYXdzLWNkay1saWIvY3VzdG9tLXJlc291cmNlc1wiO1xuaW1wb3J0IHsgRWZmZWN0LCBQb2xpY3lTdGF0ZW1lbnQgfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWlhbVwiO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSBcImNvbnN0cnVjdHNcIjtcblxuaW1wb3J0IHsgQXdzQ3VzdG9tUmVzb3VyY2UgfSBmcm9tIFwiLi4vLi4vcmVzb3VyY2VzL2F3cy91dGlsaXRpZXMvYXdzQ3VzdG9tUmVzb3VyY2VcIjtcblxuZXhwb3J0IGNsYXNzIE9yZ2FuaXNhdGlvbklkIGV4dGVuZHMgQ29uc3RydWN0IHtcbiAgcHVibGljIHJlYWRvbmx5IG9yZ2FuaXNhdGlvbklkOiBDZm5PdXRwdXQ7XG4gIHB1YmxpYyByZWFkb25seSBvcmdhbmlzYXRpb25BY2NvdW50QXJuOiBDZm5PdXRwdXQ7XG5cbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCk7XG5cbiAgICBjb25zdCBvcmdhbmlzYXRpb24gPSBuZXcgQXdzQ3VzdG9tUmVzb3VyY2UodGhpcywgXCJPcmdhbmlzYXRpb25SZXNvdXJjZVwiLCB7XG4gICAgICBmdW5jdGlvbk5hbWU6IFwib3JnYW5pc2F0aW9uSWRcIixcbiAgICAgIG9uQ3JlYXRlOiB7XG4gICAgICAgIHNlcnZpY2U6IFwib3JnYW5pemF0aW9uc1wiLFxuICAgICAgICBhY3Rpb246IFwiRGVzY3JpYmVPcmdhbml6YXRpb25Db21tYW5kXCIsIC8vIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9BV1NKYXZhU2NyaXB0U0RLL2xhdGVzdC9BV1MvT3JnYW5pemF0aW9ucy5odG1sI2Rlc2NyaWJlT3JnYW5pemF0aW9uLXByb3BlcnR5XG4gICAgICAgIHBoeXNpY2FsUmVzb3VyY2VJZDpcbiAgICAgICAgICBjdXN0b21SZXNvdXJjZXMuUGh5c2ljYWxSZXNvdXJjZUlkLm9mKFwib3JnYW5pc2F0aW9uSWRcIilcbiAgICAgIH0sXG4gICAgICBvblVwZGF0ZToge1xuICAgICAgICBzZXJ2aWNlOiBcIm9yZ2FuaXphdGlvbnNcIixcbiAgICAgICAgYWN0aW9uOiBcIkRlc2NyaWJlT3JnYW5pemF0aW9uQ29tbWFuZFwiLCAvLyBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQVdTSmF2YVNjcmlwdFNESy9sYXRlc3QvQVdTL09yZ2FuaXphdGlvbnMuaHRtbCNkZXNjcmliZU9yZ2FuaXphdGlvbi1wcm9wZXJ0eVxuICAgICAgICBwaHlzaWNhbFJlc291cmNlSWQ6XG4gICAgICAgICAgY3VzdG9tUmVzb3VyY2VzLlBoeXNpY2FsUmVzb3VyY2VJZC5vZihcIm9yZ2FuaXNhdGlvbklkXCIpXG4gICAgICB9LFxuICAgICAgcmVzb3VyY2VUeXBlOiBcIkN1c3RvbTo6RGVzY3JpYmVPcmdhbmlzYXRpb25cIixcbiAgICAgIHBvbGljeTogY3VzdG9tUmVzb3VyY2VzLkF3c0N1c3RvbVJlc291cmNlUG9saWN5LmZyb21TdGF0ZW1lbnRzKFtcbiAgICAgICAgbmV3IFBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgICAgYWN0aW9uczogW1wib3JnYW5pemF0aW9uczpEZXNjcmliZU9yZ2FuaXphdGlvblwiXSxcbiAgICAgICAgICByZXNvdXJjZXM6IFtcIipcIl0sXG4gICAgICAgICAgZWZmZWN0OiBFZmZlY3QuQUxMT1dcbiAgICAgICAgfSlcbiAgICAgIF0pXG4gICAgfSk7XG5cbiAgICB0aGlzLm9yZ2FuaXNhdGlvbklkID0gbmV3IENmbk91dHB1dCh0aGlzLCBcIk9yZ2FuaXNhdGlvbklkT3V0cHV0XCIsIHtcbiAgICAgIGtleTogXCJPcmdhbmlzYXRpb25JZFwiLFxuICAgICAgdmFsdWU6IG9yZ2FuaXNhdGlvbi5nZXRSZXNwb25zZUZpZWxkKFwiT3JnYW5pemF0aW9uLklkXCIpLFxuICAgICAgZXhwb3J0TmFtZTogXCJPcmdhbmlzYXRpb25JZFwiXG4gICAgfSk7XG5cbiAgICB0aGlzLm9yZ2FuaXNhdGlvbkFjY291bnRBcm4gPSBuZXcgQ2ZuT3V0cHV0KFxuICAgICAgdGhpcyxcbiAgICAgIFwiT3JnYW5pc2F0aW9uQWNjb3VudEFybk91dHB1dFwiLFxuICAgICAge1xuICAgICAgICBrZXk6IFwiT3JnYW5pc2F0aW9uQWNjb3VudEFyblwiLFxuICAgICAgICB2YWx1ZTogb3JnYW5pc2F0aW9uLmdldFJlc3BvbnNlRmllbGQoXCJPcmdhbml6YXRpb24uTWFzdGVyQWNjb3VudEFyblwiKSxcbiAgICAgICAgZXhwb3J0TmFtZTogXCJPcmdhbmlzYXRpb25BY2NvdW50QXJuXCJcbiAgICAgIH1cbiAgICApO1xuICB9XG59XG4iXX0=
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Construct } from "constructs";
|
|
2
|
+
import { type StackProps } from "aws-cdk-lib";
|
|
3
|
+
interface ActivateOrganisationsAccessProps extends StackProps {
|
|
4
|
+
account: string;
|
|
5
|
+
region: string;
|
|
6
|
+
}
|
|
7
|
+
export declare class ActivateOrganisationsAccess extends Construct {
|
|
8
|
+
constructor(scope: Construct, id: string, props: ActivateOrganisationsAccessProps);
|
|
9
|
+
}
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ActivateOrganisationsAccess = void 0;
|
|
4
|
+
const customResources = require("aws-cdk-lib/custom-resources");
|
|
5
|
+
const constructs_1 = require("constructs");
|
|
6
|
+
const awsCustomResource_1 = require("../../resources/aws/utilities/awsCustomResource");
|
|
7
|
+
const aws_iam_1 = require("aws-cdk-lib/aws-iam");
|
|
8
|
+
class ActivateOrganisationsAccess extends constructs_1.Construct {
|
|
9
|
+
constructor(scope, id, props) {
|
|
10
|
+
super(scope, id);
|
|
11
|
+
new awsCustomResource_1.AwsCustomResource(this, "activateOrganisationsAccess", {
|
|
12
|
+
functionName: "activateOrganisationsAccess",
|
|
13
|
+
onCreate: {
|
|
14
|
+
service: "cloudformation",
|
|
15
|
+
action: "ActivateOrganizationsAccessCommand", // https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/cloudformation/command/ActivateOrganizationsAccessCommand/
|
|
16
|
+
parameters: {},
|
|
17
|
+
physicalResourceId: customResources.PhysicalResourceId.of("activateOrganisationsAccess")
|
|
18
|
+
},
|
|
19
|
+
resourceType: "Custom::ActivateOrganisationsAccess",
|
|
20
|
+
policy: customResources.AwsCustomResourcePolicy.fromStatements([
|
|
21
|
+
new aws_iam_1.PolicyStatement({
|
|
22
|
+
actions: [
|
|
23
|
+
"cloudformation:ActivateOrganizationsAccess",
|
|
24
|
+
"cloudformation:DescribeOrganizationsAccess",
|
|
25
|
+
"organizations:EnableAWSServiceAccess",
|
|
26
|
+
"organizations:DescribeOrganization",
|
|
27
|
+
"organizations:ListRoots",
|
|
28
|
+
"organizations:ListAWSServiceAccessForOrganization",
|
|
29
|
+
"organizations:DisableAWSServiceAccess",
|
|
30
|
+
"iam:CreateServiceLinkedRole",
|
|
31
|
+
"iam:GetRole"
|
|
32
|
+
],
|
|
33
|
+
resources: [
|
|
34
|
+
"*" // TODO: Figure out what access is required here
|
|
35
|
+
],
|
|
36
|
+
effect: aws_iam_1.Effect.ALLOW
|
|
37
|
+
}),
|
|
38
|
+
new aws_iam_1.PolicyStatement({
|
|
39
|
+
actions: ["cloudformation:ActivateOrganizationsAccess"],
|
|
40
|
+
resources: [
|
|
41
|
+
`arn:aws:cloudformation:${props.region}:${props.account}:stackset/*`
|
|
42
|
+
],
|
|
43
|
+
effect: aws_iam_1.Effect.ALLOW
|
|
44
|
+
})
|
|
45
|
+
])
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.ActivateOrganisationsAccess = ActivateOrganisationsAccess;
|
|
50
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3JnYW5pc2F0aW9uc0FjY2Vzcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2xpYi9jb25maWcvYXdzL29yZ2FuaXNhdGlvbnNBY2Nlc3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsZ0VBQWdFO0FBQ2hFLDJDQUF1QztBQUV2Qyx1RkFBb0Y7QUFDcEYsaURBQThEO0FBUTlELE1BQWEsMkJBQTRCLFNBQVEsc0JBQVM7SUFDeEQsWUFDRSxLQUFnQixFQUNoQixFQUFVLEVBQ1YsS0FBdUM7UUFFdkMsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQUVqQixJQUFJLHFDQUFpQixDQUFDLElBQUksRUFBRSw2QkFBNkIsRUFBRTtZQUN6RCxZQUFZLEVBQUUsNkJBQTZCO1lBQzNDLFFBQVEsRUFBRTtnQkFDUixPQUFPLEVBQUUsZ0JBQWdCO2dCQUN6QixNQUFNLEVBQUUsb0NBQW9DLEVBQUUsMkhBQTJIO2dCQUN6SyxVQUFVLEVBQUUsRUFBRTtnQkFDZCxrQkFBa0IsRUFBRSxlQUFlLENBQUMsa0JBQWtCLENBQUMsRUFBRSxDQUN2RCw2QkFBNkIsQ0FDOUI7YUFDRjtZQUNELFlBQVksRUFBRSxxQ0FBcUM7WUFDbkQsTUFBTSxFQUFFLGVBQWUsQ0FBQyx1QkFBdUIsQ0FBQyxjQUFjLENBQUM7Z0JBQzdELElBQUkseUJBQWUsQ0FBQztvQkFDbEIsT0FBTyxFQUFFO3dCQUNQLDRDQUE0Qzt3QkFDNUMsNENBQTRDO3dCQUM1QyxzQ0FBc0M7d0JBQ3RDLG9DQUFvQzt3QkFDcEMseUJBQXlCO3dCQUN6QixtREFBbUQ7d0JBQ25ELHVDQUF1Qzt3QkFDdkMsNkJBQTZCO3dCQUM3QixhQUFhO3FCQUNkO29CQUNELFNBQVMsRUFBRTt3QkFDVCxHQUFHLENBQUMsZ0RBQWdEO3FCQUNyRDtvQkFDRCxNQUFNLEVBQUUsZ0JBQU0sQ0FBQyxLQUFLO2lCQUNyQixDQUFDO2dCQUNGLElBQUkseUJBQWUsQ0FBQztvQkFDbEIsT0FBTyxFQUFFLENBQUMsNENBQTRDLENBQUM7b0JBQ3ZELFNBQVMsRUFBRTt3QkFDVCwwQkFBMEIsS0FBSyxDQUFDLE1BQU0sSUFBSSxLQUFLLENBQUMsT0FBTyxhQUFhO3FCQUNyRTtvQkFDRCxNQUFNLEVBQUUsZ0JBQU0sQ0FBQyxLQUFLO2lCQUNyQixDQUFDO2FBQ0gsQ0FBQztTQUNILENBQUMsQ0FBQztJQUNMLENBQUM7Q0FDRjtBQS9DRCxrRUErQ0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBjdXN0b21SZXNvdXJjZXMgZnJvbSBcImF3cy1jZGstbGliL2N1c3RvbS1yZXNvdXJjZXNcIjtcbmltcG9ydCB7IENvbnN0cnVjdCB9IGZyb20gXCJjb25zdHJ1Y3RzXCI7XG5cbmltcG9ydCB7IEF3c0N1c3RvbVJlc291cmNlIH0gZnJvbSBcIi4uLy4uL3Jlc291cmNlcy9hd3MvdXRpbGl0aWVzL2F3c0N1c3RvbVJlc291cmNlXCI7XG5pbXBvcnQgeyBFZmZlY3QsIFBvbGljeVN0YXRlbWVudCB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtaWFtXCI7XG5pbXBvcnQgeyB0eXBlIFN0YWNrUHJvcHMgfSBmcm9tIFwiYXdzLWNkay1saWJcIjtcblxuaW50ZXJmYWNlIEFjdGl2YXRlT3JnYW5pc2F0aW9uc0FjY2Vzc1Byb3BzIGV4dGVuZHMgU3RhY2tQcm9wcyB7XG4gIGFjY291bnQ6IHN0cmluZztcbiAgcmVnaW9uOiBzdHJpbmc7XG59XG5cbmV4cG9ydCBjbGFzcyBBY3RpdmF0ZU9yZ2FuaXNhdGlvbnNBY2Nlc3MgZXh0ZW5kcyBDb25zdHJ1Y3Qge1xuICBjb25zdHJ1Y3RvcihcbiAgICBzY29wZTogQ29uc3RydWN0LFxuICAgIGlkOiBzdHJpbmcsXG4gICAgcHJvcHM6IEFjdGl2YXRlT3JnYW5pc2F0aW9uc0FjY2Vzc1Byb3BzXG4gICkge1xuICAgIHN1cGVyKHNjb3BlLCBpZCk7XG5cbiAgICBuZXcgQXdzQ3VzdG9tUmVzb3VyY2UodGhpcywgXCJhY3RpdmF0ZU9yZ2FuaXNhdGlvbnNBY2Nlc3NcIiwge1xuICAgICAgZnVuY3Rpb25OYW1lOiBcImFjdGl2YXRlT3JnYW5pc2F0aW9uc0FjY2Vzc1wiLFxuICAgICAgb25DcmVhdGU6IHtcbiAgICAgICAgc2VydmljZTogXCJjbG91ZGZvcm1hdGlvblwiLFxuICAgICAgICBhY3Rpb246IFwiQWN0aXZhdGVPcmdhbml6YXRpb25zQWNjZXNzQ29tbWFuZFwiLCAvLyBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQVdTSmF2YVNjcmlwdFNESy92My9sYXRlc3QvY2xpZW50L2Nsb3VkZm9ybWF0aW9uL2NvbW1hbmQvQWN0aXZhdGVPcmdhbml6YXRpb25zQWNjZXNzQ29tbWFuZC9cbiAgICAgICAgcGFyYW1ldGVyczoge30sXG4gICAgICAgIHBoeXNpY2FsUmVzb3VyY2VJZDogY3VzdG9tUmVzb3VyY2VzLlBoeXNpY2FsUmVzb3VyY2VJZC5vZihcbiAgICAgICAgICBcImFjdGl2YXRlT3JnYW5pc2F0aW9uc0FjY2Vzc1wiXG4gICAgICAgIClcbiAgICAgIH0sXG4gICAgICByZXNvdXJjZVR5cGU6IFwiQ3VzdG9tOjpBY3RpdmF0ZU9yZ2FuaXNhdGlvbnNBY2Nlc3NcIixcbiAgICAgIHBvbGljeTogY3VzdG9tUmVzb3VyY2VzLkF3c0N1c3RvbVJlc291cmNlUG9saWN5LmZyb21TdGF0ZW1lbnRzKFtcbiAgICAgICAgbmV3IFBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgICAgYWN0aW9uczogW1xuICAgICAgICAgICAgXCJjbG91ZGZvcm1hdGlvbjpBY3RpdmF0ZU9yZ2FuaXphdGlvbnNBY2Nlc3NcIixcbiAgICAgICAgICAgIFwiY2xvdWRmb3JtYXRpb246RGVzY3JpYmVPcmdhbml6YXRpb25zQWNjZXNzXCIsXG4gICAgICAgICAgICBcIm9yZ2FuaXphdGlvbnM6RW5hYmxlQVdTU2VydmljZUFjY2Vzc1wiLFxuICAgICAgICAgICAgXCJvcmdhbml6YXRpb25zOkRlc2NyaWJlT3JnYW5pemF0aW9uXCIsXG4gICAgICAgICAgICBcIm9yZ2FuaXphdGlvbnM6TGlzdFJvb3RzXCIsXG4gICAgICAgICAgICBcIm9yZ2FuaXphdGlvbnM6TGlzdEFXU1NlcnZpY2VBY2Nlc3NGb3JPcmdhbml6YXRpb25cIixcbiAgICAgICAgICAgIFwib3JnYW5pemF0aW9uczpEaXNhYmxlQVdTU2VydmljZUFjY2Vzc1wiLFxuICAgICAgICAgICAgXCJpYW06Q3JlYXRlU2VydmljZUxpbmtlZFJvbGVcIixcbiAgICAgICAgICAgIFwiaWFtOkdldFJvbGVcIlxuICAgICAgICAgIF0sXG4gICAgICAgICAgcmVzb3VyY2VzOiBbXG4gICAgICAgICAgICBcIipcIiAvLyBUT0RPOiBGaWd1cmUgb3V0IHdoYXQgYWNjZXNzIGlzIHJlcXVpcmVkIGhlcmVcbiAgICAgICAgICBdLFxuICAgICAgICAgIGVmZmVjdDogRWZmZWN0LkFMTE9XXG4gICAgICAgIH0pLFxuICAgICAgICBuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgICBhY3Rpb25zOiBbXCJjbG91ZGZvcm1hdGlvbjpBY3RpdmF0ZU9yZ2FuaXphdGlvbnNBY2Nlc3NcIl0sXG4gICAgICAgICAgcmVzb3VyY2VzOiBbXG4gICAgICAgICAgICBgYXJuOmF3czpjbG91ZGZvcm1hdGlvbjoke3Byb3BzLnJlZ2lvbn06JHtwcm9wcy5hY2NvdW50fTpzdGFja3NldC8qYFxuICAgICAgICAgIF0sXG4gICAgICAgICAgZWZmZWN0OiBFZmZlY3QuQUxMT1dcbiAgICAgICAgfSlcbiAgICAgIF0pXG4gICAgfSk7XG4gIH1cbn1cbiJdfQ==
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RamSharing = void 0;
|
|
4
|
+
const customResources = require("aws-cdk-lib/custom-resources");
|
|
5
|
+
const aws_iam_1 = require("aws-cdk-lib/aws-iam");
|
|
6
|
+
const constructs_1 = require("constructs");
|
|
7
|
+
const awsCustomResource_1 = require("../../resources/aws/utilities/awsCustomResource");
|
|
8
|
+
class RamSharing extends constructs_1.Construct {
|
|
9
|
+
constructor(scope, id) {
|
|
10
|
+
super(scope, id);
|
|
11
|
+
new awsCustomResource_1.AwsCustomResource(this, "enableRamSharing", {
|
|
12
|
+
functionName: "enableRamSharing",
|
|
13
|
+
onCreate: {
|
|
14
|
+
service: "RAM",
|
|
15
|
+
action: "enableSharingWithAwsOrganization", // https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/RAM.html#enableSharingWithAwsOrganization-property
|
|
16
|
+
parameters: {},
|
|
17
|
+
physicalResourceId: customResources.PhysicalResourceId.of("enableRamSharing")
|
|
18
|
+
},
|
|
19
|
+
resourceType: "Custom::ram",
|
|
20
|
+
policy: customResources.AwsCustomResourcePolicy.fromStatements([
|
|
21
|
+
new aws_iam_1.PolicyStatement({
|
|
22
|
+
actions: [
|
|
23
|
+
"ram:EnableSharingWithAwsOrganization",
|
|
24
|
+
"iam:CreateServiceLinkedRole",
|
|
25
|
+
"organizations:enableAWSServiceAccess",
|
|
26
|
+
"organizations:DescribeOrganization"
|
|
27
|
+
],
|
|
28
|
+
resources: ["*"] // TODO: Find out the exact pricipal for this
|
|
29
|
+
})
|
|
30
|
+
])
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.RamSharing = RamSharing;
|
|
35
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmFtU2hhcmluZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2xpYi9jb25maWcvYXdzL3JhbVNoYXJpbmcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsZ0VBQWdFO0FBQ2hFLGlEQUFzRDtBQUN0RCwyQ0FBdUM7QUFFdkMsdUZBQW9GO0FBRXBGLE1BQWEsVUFBVyxTQUFRLHNCQUFTO0lBQ3ZDLFlBQVksS0FBZ0IsRUFBRSxFQUFVO1FBQ3RDLEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFFakIsSUFBSSxxQ0FBaUIsQ0FBQyxJQUFJLEVBQUUsa0JBQWtCLEVBQUU7WUFDOUMsWUFBWSxFQUFFLGtCQUFrQjtZQUNoQyxRQUFRLEVBQUU7Z0JBQ1IsT0FBTyxFQUFFLEtBQUs7Z0JBQ2QsTUFBTSxFQUFFLGtDQUFrQyxFQUFFLDZHQUE2RztnQkFDekosVUFBVSxFQUFFLEVBQUU7Z0JBQ2Qsa0JBQWtCLEVBQ2hCLGVBQWUsQ0FBQyxrQkFBa0IsQ0FBQyxFQUFFLENBQUMsa0JBQWtCLENBQUM7YUFDNUQ7WUFDRCxZQUFZLEVBQUUsYUFBYTtZQUMzQixNQUFNLEVBQUUsZUFBZSxDQUFDLHVCQUF1QixDQUFDLGNBQWMsQ0FBQztnQkFDN0QsSUFBSSx5QkFBZSxDQUFDO29CQUNsQixPQUFPLEVBQUU7d0JBQ1Asc0NBQXNDO3dCQUN0Qyw2QkFBNkI7d0JBQzdCLHNDQUFzQzt3QkFDdEMsb0NBQW9DO3FCQUNyQztvQkFDRCxTQUFTLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyw2Q0FBNkM7aUJBQy9ELENBQUM7YUFDSCxDQUFDO1NBQ0gsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztDQUNGO0FBM0JELGdDQTJCQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGN1c3RvbVJlc291cmNlcyBmcm9tIFwiYXdzLWNkay1saWIvY3VzdG9tLXJlc291cmNlc1wiO1xuaW1wb3J0IHsgUG9saWN5U3RhdGVtZW50IH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1pYW1cIjtcbmltcG9ydCB7IENvbnN0cnVjdCB9IGZyb20gXCJjb25zdHJ1Y3RzXCI7XG5cbmltcG9ydCB7IEF3c0N1c3RvbVJlc291cmNlIH0gZnJvbSBcIi4uLy4uL3Jlc291cmNlcy9hd3MvdXRpbGl0aWVzL2F3c0N1c3RvbVJlc291cmNlXCI7XG5cbmV4cG9ydCBjbGFzcyBSYW1TaGFyaW5nIGV4dGVuZHMgQ29uc3RydWN0IHtcbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCk7XG5cbiAgICBuZXcgQXdzQ3VzdG9tUmVzb3VyY2UodGhpcywgXCJlbmFibGVSYW1TaGFyaW5nXCIsIHtcbiAgICAgIGZ1bmN0aW9uTmFtZTogXCJlbmFibGVSYW1TaGFyaW5nXCIsXG4gICAgICBvbkNyZWF0ZToge1xuICAgICAgICBzZXJ2aWNlOiBcIlJBTVwiLFxuICAgICAgICBhY3Rpb246IFwiZW5hYmxlU2hhcmluZ1dpdGhBd3NPcmdhbml6YXRpb25cIiwgLy8gaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL0FXU0phdmFTY3JpcHRTREsvbGF0ZXN0L0FXUy9SQU0uaHRtbCNlbmFibGVTaGFyaW5nV2l0aEF3c09yZ2FuaXphdGlvbi1wcm9wZXJ0eVxuICAgICAgICBwYXJhbWV0ZXJzOiB7fSxcbiAgICAgICAgcGh5c2ljYWxSZXNvdXJjZUlkOlxuICAgICAgICAgIGN1c3RvbVJlc291cmNlcy5QaHlzaWNhbFJlc291cmNlSWQub2YoXCJlbmFibGVSYW1TaGFyaW5nXCIpXG4gICAgICB9LFxuICAgICAgcmVzb3VyY2VUeXBlOiBcIkN1c3RvbTo6cmFtXCIsXG4gICAgICBwb2xpY3k6IGN1c3RvbVJlc291cmNlcy5Bd3NDdXN0b21SZXNvdXJjZVBvbGljeS5mcm9tU3RhdGVtZW50cyhbXG4gICAgICAgIG5ldyBQb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAgICAgIFwicmFtOkVuYWJsZVNoYXJpbmdXaXRoQXdzT3JnYW5pemF0aW9uXCIsXG4gICAgICAgICAgICBcImlhbTpDcmVhdGVTZXJ2aWNlTGlua2VkUm9sZVwiLFxuICAgICAgICAgICAgXCJvcmdhbml6YXRpb25zOmVuYWJsZUFXU1NlcnZpY2VBY2Nlc3NcIixcbiAgICAgICAgICAgIFwib3JnYW5pemF0aW9uczpEZXNjcmliZU9yZ2FuaXphdGlvblwiXG4gICAgICAgICAgXSxcbiAgICAgICAgICByZXNvdXJjZXM6IFtcIipcIl0gLy8gVE9ETzogRmluZCBvdXQgdGhlIGV4YWN0IHByaWNpcGFsIGZvciB0aGlzXG4gICAgICAgIH0pXG4gICAgICBdKVxuICAgIH0pO1xuICB9XG59XG4iXX0=
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Monitoring configuration for cross-account access
|
|
3
|
+
*/
|
|
4
|
+
export declare const FJALL_MONITORING_CONFIG: {
|
|
5
|
+
/**
|
|
6
|
+
* Fjall webapp AWS account ID
|
|
7
|
+
* This account will be granted permission to assume monitoring roles
|
|
8
|
+
*/
|
|
9
|
+
readonly webappAwsAccountId: "985539798308";
|
|
10
|
+
/**
|
|
11
|
+
* IAM role naming convention
|
|
12
|
+
*/
|
|
13
|
+
readonly roleNamePrefix: "FjallMonitoring";
|
|
14
|
+
/**
|
|
15
|
+
* IAM role path (for organizational structure)
|
|
16
|
+
*/
|
|
17
|
+
readonly rolePath: "/";
|
|
18
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FJALL_MONITORING_CONFIG = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Monitoring configuration for cross-account access
|
|
6
|
+
*/
|
|
7
|
+
exports.FJALL_MONITORING_CONFIG = {
|
|
8
|
+
/**
|
|
9
|
+
* Fjall webapp AWS account ID
|
|
10
|
+
* This account will be granted permission to assume monitoring roles
|
|
11
|
+
*/
|
|
12
|
+
webappAwsAccountId: "985539798308", // Fjall platform account
|
|
13
|
+
/**
|
|
14
|
+
* IAM role naming convention
|
|
15
|
+
*/
|
|
16
|
+
roleNamePrefix: "FjallMonitoring",
|
|
17
|
+
/**
|
|
18
|
+
* IAM role path (for organizational structure)
|
|
19
|
+
*/
|
|
20
|
+
rolePath: "/"
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9uaXRvcmluZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL2xpYi9jb25maWcvbW9uaXRvcmluZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQTs7R0FFRztBQUNVLFFBQUEsdUJBQXVCLEdBQUc7SUFDckM7OztPQUdHO0lBQ0gsa0JBQWtCLEVBQUUsY0FBYyxFQUFFLHlCQUF5QjtJQUU3RDs7T0FFRztJQUNILGNBQWMsRUFBRSxpQkFBaUI7SUFFakM7O09BRUc7SUFDSCxRQUFRLEVBQUUsR0FBRztDQUNMLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIE1vbml0b3JpbmcgY29uZmlndXJhdGlvbiBmb3IgY3Jvc3MtYWNjb3VudCBhY2Nlc3NcbiAqL1xuZXhwb3J0IGNvbnN0IEZKQUxMX01PTklUT1JJTkdfQ09ORklHID0ge1xuICAvKipcbiAgICogRmphbGwgd2ViYXBwIEFXUyBhY2NvdW50IElEXG4gICAqIFRoaXMgYWNjb3VudCB3aWxsIGJlIGdyYW50ZWQgcGVybWlzc2lvbiB0byBhc3N1bWUgbW9uaXRvcmluZyByb2xlc1xuICAgKi9cbiAgd2ViYXBwQXdzQWNjb3VudElkOiBcIjk4NTUzOTc5ODMwOFwiLCAvLyBGamFsbCBwbGF0Zm9ybSBhY2NvdW50XG5cbiAgLyoqXG4gICAqIElBTSByb2xlIG5hbWluZyBjb252ZW50aW9uXG4gICAqL1xuICByb2xlTmFtZVByZWZpeDogXCJGamFsbE1vbml0b3JpbmdcIixcblxuICAvKipcbiAgICogSUFNIHJvbGUgcGF0aCAoZm9yIG9yZ2FuaXphdGlvbmFsIHN0cnVjdHVyZSlcbiAgICovXG4gIHJvbGVQYXRoOiBcIi9cIlxufSBhcyBjb25zdDtcbiJdfQ==
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Static-site contact-form handler (Lambda Function URL → SES).
|
|
3
|
+
*
|
|
4
|
+
* Authored directly under asset/ as CJS — the only dependency,
|
|
5
|
+
* @aws-sdk/client-sesv2, ships in the Lambda Node 22 runtime, so there is no
|
|
6
|
+
* build step. asset/package.json pins CJS resolution.
|
|
7
|
+
*
|
|
8
|
+
* Security posture (Function URL authType NONE — see staticSite.ts). The
|
|
9
|
+
* endpoint is public and unauthenticated. Be precise about what each control
|
|
10
|
+
* actually buys, because it is easy to mistake this for authentication:
|
|
11
|
+
* - The Origin/Referer check stops a browser on another site from POSTing here
|
|
12
|
+
* (it cannot forge those headers). It does NOT stop a non-browser client,
|
|
13
|
+
* which sets them freely. It is a nuisance filter, not an auth gate.
|
|
14
|
+
* - A populated honeypot field (_gotcha) marks a bot → silent 200, no send.
|
|
15
|
+
* - What actually bounds abuse: the function's reserved concurrency (capped in
|
|
16
|
+
* staticSite.ts, so a flood cannot drain account-wide Lambda concurrency),
|
|
17
|
+
* SES account send limits, and the fact that both sender and recipient are
|
|
18
|
+
* fixed at deploy time — whatever a caller sends, the mail can only ever go
|
|
19
|
+
* from noreply@<domain> to the site owner.
|
|
20
|
+
*
|
|
21
|
+
* Logging discipline: status + requestId + SES error NAME only — never the
|
|
22
|
+
* parsed body or the recipient address (both are submitter PII).
|
|
23
|
+
*/
|
|
24
|
+
"use strict";
|
|
25
|
+
|
|
26
|
+
const { SESv2Client, SendEmailCommand } = require("@aws-sdk/client-sesv2");
|
|
27
|
+
|
|
28
|
+
const client = new SESv2Client({});
|
|
29
|
+
|
|
30
|
+
const CONTACT_TO = process.env.CONTACT_TO;
|
|
31
|
+
const CONTACT_FROM = process.env.CONTACT_FROM;
|
|
32
|
+
const ALLOWED_ORIGIN = process.env.ALLOWED_ORIGIN;
|
|
33
|
+
|
|
34
|
+
const MAX_NAME = 200;
|
|
35
|
+
const MAX_EMAIL = 320;
|
|
36
|
+
const MAX_MESSAGE = 5000;
|
|
37
|
+
|
|
38
|
+
exports.handler = async (event) => {
|
|
39
|
+
const requestId = event?.requestContext?.requestId ?? "unknown";
|
|
40
|
+
const method = event?.requestContext?.http?.method ?? "";
|
|
41
|
+
|
|
42
|
+
if (method !== "POST") {
|
|
43
|
+
return respond(405, { error: "Method not allowed" });
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const headers = normaliseHeaders(event?.headers);
|
|
47
|
+
if (!originAllowed(headers)) {
|
|
48
|
+
log("warn", "origin rejected", requestId);
|
|
49
|
+
return respond(403, { error: "Forbidden" });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
let fields;
|
|
53
|
+
try {
|
|
54
|
+
fields = parseBody(event);
|
|
55
|
+
} catch {
|
|
56
|
+
log("warn", "invalid body", requestId);
|
|
57
|
+
return respond(400, { error: "Invalid request body" });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Populated honeypot ⇒ bot: pretend success so it does not probe further.
|
|
61
|
+
if (typeof fields._gotcha === "string" && fields._gotcha.trim() !== "") {
|
|
62
|
+
return respond(200, { ok: true });
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const name = String(fields.name ?? "").slice(0, MAX_NAME);
|
|
66
|
+
const email = String(fields.email ?? "").slice(0, MAX_EMAIL);
|
|
67
|
+
const message = String(fields.message ?? "").slice(0, MAX_MESSAGE);
|
|
68
|
+
|
|
69
|
+
if (message.trim() === "") {
|
|
70
|
+
return respond(400, { error: "Message is required" });
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
await client.send(
|
|
75
|
+
new SendEmailCommand({
|
|
76
|
+
FromEmailAddress: CONTACT_FROM,
|
|
77
|
+
Destination: { ToAddresses: [CONTACT_TO] },
|
|
78
|
+
...(isValidEmail(email) && { ReplyToAddresses: [email] }),
|
|
79
|
+
Content: {
|
|
80
|
+
Simple: {
|
|
81
|
+
Subject: {
|
|
82
|
+
Data: `Contact form: ${name || "(no name)"}`.slice(0, MAX_NAME)
|
|
83
|
+
},
|
|
84
|
+
Body: { Text: { Data: buildBody(name, email, message) } }
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
})
|
|
88
|
+
);
|
|
89
|
+
log("info", "sent", requestId);
|
|
90
|
+
return respond(200, { ok: true });
|
|
91
|
+
} catch (err) {
|
|
92
|
+
log("error", "ses send failed", requestId, err?.name);
|
|
93
|
+
return respond(502, { error: "Failed to send message" });
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
function normaliseHeaders(headers) {
|
|
98
|
+
const out = {};
|
|
99
|
+
if (headers && typeof headers === "object") {
|
|
100
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
101
|
+
out[key.toLowerCase()] = value;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return out;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function originAllowed(headers) {
|
|
108
|
+
if (!ALLOWED_ORIGIN) return false;
|
|
109
|
+
const origin = headers.origin;
|
|
110
|
+
if (origin) return origin === ALLOWED_ORIGIN;
|
|
111
|
+
// Some clients omit Origin on same-site POSTs — fall back to the Referer's
|
|
112
|
+
// origin. Compare whole origins: a prefix test would accept a Referer of
|
|
113
|
+
// https://example.com.attacker.test/ for ALLOWED_ORIGIN https://example.com.
|
|
114
|
+
const referer = headers.referer;
|
|
115
|
+
if (referer) return originOf(referer) === ALLOWED_ORIGIN;
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function originOf(url) {
|
|
120
|
+
try {
|
|
121
|
+
return new URL(url).origin;
|
|
122
|
+
} catch {
|
|
123
|
+
return undefined;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function parseBody(event) {
|
|
128
|
+
const raw =
|
|
129
|
+
event?.isBase64Encoded && typeof event.body === "string"
|
|
130
|
+
? Buffer.from(event.body, "base64").toString("utf8")
|
|
131
|
+
: (event?.body ?? "");
|
|
132
|
+
const trimmed = raw.trim();
|
|
133
|
+
if (trimmed.startsWith("{")) {
|
|
134
|
+
return JSON.parse(trimmed);
|
|
135
|
+
}
|
|
136
|
+
// application/x-www-form-urlencoded fallback
|
|
137
|
+
const params = new URLSearchParams(trimmed);
|
|
138
|
+
const fields = {};
|
|
139
|
+
for (const [key, value] of params.entries()) {
|
|
140
|
+
fields[key] = value;
|
|
141
|
+
}
|
|
142
|
+
return fields;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function isValidEmail(value) {
|
|
146
|
+
return /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(value);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function buildBody(name, email, message) {
|
|
150
|
+
return [
|
|
151
|
+
`Name: ${name || "(not provided)"}`,
|
|
152
|
+
`Email: ${email || "(not provided)"}`,
|
|
153
|
+
"",
|
|
154
|
+
message
|
|
155
|
+
].join("\n");
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function respond(statusCode, body) {
|
|
159
|
+
return {
|
|
160
|
+
statusCode,
|
|
161
|
+
headers: { "content-type": "application/json" },
|
|
162
|
+
body: JSON.stringify(body)
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function log(level, msg, requestId, errorName) {
|
|
167
|
+
console.log(
|
|
168
|
+
JSON.stringify({
|
|
169
|
+
level,
|
|
170
|
+
msg,
|
|
171
|
+
requestId,
|
|
172
|
+
...(errorName && { error: errorName })
|
|
173
|
+
})
|
|
174
|
+
);
|
|
175
|
+
}
|
|
@@ -2,10 +2,11 @@ import { type Construct } from "constructs";
|
|
|
2
2
|
import { type IBucket } from "aws-cdk-lib/aws-s3";
|
|
3
3
|
import { type IApplicationLoadBalancer } from "aws-cdk-lib/aws-elasticloadbalancingv2";
|
|
4
4
|
import { type ICertificate } from "aws-cdk-lib/aws-certificatemanager";
|
|
5
|
-
import { type ICachePolicy } from "aws-cdk-lib/aws-cloudfront";
|
|
5
|
+
import { type ICachePolicy, type IResponseHeadersPolicy } from "aws-cdk-lib/aws-cloudfront";
|
|
6
6
|
import type App from "../../app.js";
|
|
7
7
|
import { CloudFrontDistribution, type CachePolicyPreset, type AccessGateConfig } from "../../resources/aws/cdn/index.js";
|
|
8
8
|
import { type ICdn } from "./interfaces/cdn.js";
|
|
9
|
+
import type { StaticSiteRouting } from "@fjall/util";
|
|
9
10
|
import { type Storage } from "./storage.js";
|
|
10
11
|
import { type AnyCompute } from "./compute.js";
|
|
11
12
|
/**
|
|
@@ -32,7 +33,24 @@ export interface S3CdnProps extends BaseCdnProps {
|
|
|
32
33
|
originType: "s3";
|
|
33
34
|
bucket: IBucket | Storage;
|
|
34
35
|
originPath?: string;
|
|
36
|
+
/** OAI (default) or OAC (single-stack only — see cloudFront.ts). */
|
|
37
|
+
originAccess?: "oai" | "oac";
|
|
38
|
+
/** Object served for `/` (static sites: "index.html"). */
|
|
39
|
+
defaultRootObject?: string;
|
|
40
|
+
/** "multipage" → clean-URL `.html` rewriting; "spa" → 403/404 fallback to index. */
|
|
41
|
+
routing?: StaticSiteRouting;
|
|
42
|
+
/** Security-headers policy (built by the caller, e.g. SecurityHeadersPolicy). */
|
|
43
|
+
responseHeadersPolicy?: IResponseHeadersPolicy;
|
|
44
|
+
/**
|
|
45
|
+
* Origin-request policy for the default behaviour. Defaults to forwarding
|
|
46
|
+
* viewer headers, as every distribution has since before the static-site
|
|
47
|
+
* pattern. `none` suits an origin that ignores them — S3 serves objects by
|
|
48
|
+
* key — but it is opt-in: flipping the default would strip
|
|
49
|
+
* `OriginRequestPolicyId` from live distributions on their next deploy.
|
|
50
|
+
*/
|
|
51
|
+
originRequestPolicy?: "all-viewer-except-host" | "none";
|
|
35
52
|
}
|
|
53
|
+
export type { StaticSiteRouting };
|
|
36
54
|
/**
|
|
37
55
|
* ALB origin CDN props - use with Application Load Balancer
|
|
38
56
|
*/
|
|
@@ -135,4 +153,3 @@ export declare class CdnFactory {
|
|
|
135
153
|
*/
|
|
136
154
|
static build(id: string, props: ICdnProps): (_app: App, scope: Construct) => Cdn;
|
|
137
155
|
}
|
|
138
|
-
export {};
|
|
@@ -71,6 +71,15 @@ export class Cdn extends CloudFrontDistribution {
|
|
|
71
71
|
(props.certificateArn
|
|
72
72
|
? Certificate.fromCertificateArn(scope, `${id}Certificate`, props.certificateArn)
|
|
73
73
|
: undefined);
|
|
74
|
+
const s3Routing = props.originType === "s3"
|
|
75
|
+
? {
|
|
76
|
+
defaultRootObject: props.defaultRootObject,
|
|
77
|
+
cleanUrls: props.routing === "multipage",
|
|
78
|
+
spaFallback: props.routing === "spa",
|
|
79
|
+
responseHeadersPolicy: props.responseHeadersPolicy,
|
|
80
|
+
originRequestPolicy: props.originRequestPolicy
|
|
81
|
+
}
|
|
82
|
+
: {};
|
|
74
83
|
return {
|
|
75
84
|
defaultOrigin,
|
|
76
85
|
defaultCachePolicy: props.cachePolicy,
|
|
@@ -83,7 +92,8 @@ export class Cdn extends CloudFrontDistribution {
|
|
|
83
92
|
logBucket: props.logBucket,
|
|
84
93
|
priceClass: props.priceClass,
|
|
85
94
|
forwardHostHeader: props.forwardHostHeader,
|
|
86
|
-
accessGate: props.accessGate
|
|
95
|
+
accessGate: props.accessGate,
|
|
96
|
+
...s3Routing
|
|
87
97
|
};
|
|
88
98
|
}
|
|
89
99
|
/**
|
|
@@ -112,7 +122,8 @@ export class Cdn extends CloudFrontDistribution {
|
|
|
112
122
|
return {
|
|
113
123
|
type: "s3",
|
|
114
124
|
bucket,
|
|
115
|
-
originPath: props.originPath
|
|
125
|
+
originPath: props.originPath,
|
|
126
|
+
originAccess: props.originAccess
|
|
116
127
|
};
|
|
117
128
|
}
|
|
118
129
|
case "alb": {
|