@fjall/components-infrastructure 2.27.0 → 2.30.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/app.d.ts +8 -4
- package/dist/lib/app.js +24 -6
- package/dist/lib/config/aws/oidcConnector.js +4 -4
- 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/account.js +3 -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/interfaces/pattern.d.ts +134 -5
- package/dist/lib/patterns/aws/interfaces/pattern.js +6 -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/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/compute/lambda.d.ts +7 -0
- package/dist/lib/resources/aws/database/rdsHelpers.js +4 -1
- package/dist/lib/resources/aws/networking/domainCertificate.d.ts +7 -0
- package/dist/lib/resources/aws/networking/domainCertificate.js +9 -7
- package/dist/lib/utils/databaseTypes.d.ts +6 -0
- package/package.json +7 -5
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { Duration } from "aws-cdk-lib";
|
|
2
|
+
import { ResponseHeadersPolicy as CdkResponseHeadersPolicy, HeadersFrameOption, HeadersReferrerPolicy } from "aws-cdk-lib/aws-cloudfront";
|
|
3
|
+
const REFERRER_POLICY_MAP = {
|
|
4
|
+
"no-referrer": HeadersReferrerPolicy.NO_REFERRER,
|
|
5
|
+
"no-referrer-when-downgrade": HeadersReferrerPolicy.NO_REFERRER_WHEN_DOWNGRADE,
|
|
6
|
+
origin: HeadersReferrerPolicy.ORIGIN,
|
|
7
|
+
"origin-when-cross-origin": HeadersReferrerPolicy.ORIGIN_WHEN_CROSS_ORIGIN,
|
|
8
|
+
"same-origin": HeadersReferrerPolicy.SAME_ORIGIN,
|
|
9
|
+
"strict-origin": HeadersReferrerPolicy.STRICT_ORIGIN,
|
|
10
|
+
"strict-origin-when-cross-origin": HeadersReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN,
|
|
11
|
+
"unsafe-url": HeadersReferrerPolicy.UNSAFE_URL
|
|
12
|
+
};
|
|
13
|
+
const DEFAULT_HSTS_MAX_AGE_DAYS = 730;
|
|
14
|
+
const DEFAULT_COMMENT = "Fjall security headers policy";
|
|
15
|
+
/**
|
|
16
|
+
* Fjall wrapper for `aws-cdk-lib/aws-cloudfront.ResponseHeadersPolicy`.
|
|
17
|
+
*
|
|
18
|
+
* Wrapped on the description + SOC2-defaults trigger (NOT taggability — the
|
|
19
|
+
* resource is not taggable): it owns Fjall's uniform security-header defaults
|
|
20
|
+
* so every consumer inherits the same posture in one edit. Per
|
|
21
|
+
* `.claude/rules/generator-standards.md § Wrapper Routing Discipline`,
|
|
22
|
+
* `lib/{config,patterns}/` instantiate this class, never the raw L2.
|
|
23
|
+
*
|
|
24
|
+
* Defaults (all `override:true`): HSTS 730d+includeSubdomains+preload,
|
|
25
|
+
* X-Content-Type-Options: nosniff, X-Frame-Options: DENY,
|
|
26
|
+
* Referrer-Policy: strict-origin-when-cross-origin. CSP is opt-in only (§5.5).
|
|
27
|
+
*/
|
|
28
|
+
export class SecurityHeadersPolicy extends CdkResponseHeadersPolicy {
|
|
29
|
+
constructor(scope, id, props) {
|
|
30
|
+
const securityHeadersBehavior = SecurityHeadersPolicy.buildSecurityHeaders(props);
|
|
31
|
+
const customHeaders = SecurityHeadersPolicy.buildCustomHeaders(props.customHeaders);
|
|
32
|
+
super(scope, id, {
|
|
33
|
+
responseHeadersPolicyName: props.policyName,
|
|
34
|
+
comment: props.comment ?? DEFAULT_COMMENT,
|
|
35
|
+
securityHeadersBehavior,
|
|
36
|
+
...(customHeaders.length > 0 && {
|
|
37
|
+
customHeadersBehavior: { customHeaders }
|
|
38
|
+
})
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
static buildSecurityHeaders(props) {
|
|
42
|
+
const behaviour = {};
|
|
43
|
+
if (props.hsts !== false) {
|
|
44
|
+
const hsts = props.hsts ?? {};
|
|
45
|
+
behaviour.strictTransportSecurity = {
|
|
46
|
+
accessControlMaxAge: Duration.days(hsts.maxAgeDays ?? DEFAULT_HSTS_MAX_AGE_DAYS),
|
|
47
|
+
includeSubdomains: hsts.includeSubdomains ?? true,
|
|
48
|
+
preload: hsts.preload ?? true,
|
|
49
|
+
override: true
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
if (props.contentTypeOptions !== false) {
|
|
53
|
+
behaviour.contentTypeOptions = { override: true };
|
|
54
|
+
}
|
|
55
|
+
if (props.frameOptions !== false) {
|
|
56
|
+
behaviour.frameOptions = {
|
|
57
|
+
frameOption: props.frameOptions === "SAMEORIGIN"
|
|
58
|
+
? HeadersFrameOption.SAMEORIGIN
|
|
59
|
+
: HeadersFrameOption.DENY,
|
|
60
|
+
override: true
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
if (props.referrerPolicy !== false) {
|
|
64
|
+
behaviour.referrerPolicy = {
|
|
65
|
+
referrerPolicy: REFERRER_POLICY_MAP[props.referrerPolicy ?? "strict-origin-when-cross-origin"],
|
|
66
|
+
override: true
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
// CSP is opt-in — only emitted when a policy string is supplied (§5.5).
|
|
70
|
+
if (props.contentSecurityPolicy !== undefined) {
|
|
71
|
+
behaviour.contentSecurityPolicy = {
|
|
72
|
+
contentSecurityPolicy: props.contentSecurityPolicy,
|
|
73
|
+
override: true
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
return behaviour;
|
|
77
|
+
}
|
|
78
|
+
static buildCustomHeaders(customHeaders) {
|
|
79
|
+
if (customHeaders === undefined) {
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
return Object.entries(customHeaders).map(([header, value]) => ({
|
|
83
|
+
header,
|
|
84
|
+
value,
|
|
85
|
+
override: true
|
|
86
|
+
}));
|
|
87
|
+
}
|
|
88
|
+
/** The underlying policy, for wiring into a distribution behaviour. */
|
|
89
|
+
getPolicy() {
|
|
90
|
+
return this;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -32,6 +32,13 @@ export interface LambdaFunctionProps {
|
|
|
32
32
|
vpc?: IVpc;
|
|
33
33
|
timeout?: number;
|
|
34
34
|
memorySize?: number;
|
|
35
|
+
/**
|
|
36
|
+
* Cap on concurrent executions. Set this on any Lambda reachable without
|
|
37
|
+
* authentication (a public Function URL): it bounds both the function's own
|
|
38
|
+
* spend and the share of account-wide concurrency it can take from every
|
|
39
|
+
* other function.
|
|
40
|
+
*/
|
|
41
|
+
reservedConcurrentExecutions?: number;
|
|
35
42
|
/** Ephemeral storage size in MiB */
|
|
36
43
|
ephemeralStorageSize?: number;
|
|
37
44
|
/**
|
|
@@ -82,7 +82,10 @@ export function warnIfSnapshotUsernameAssumed(params) {
|
|
|
82
82
|
* warning surfaces this to anyone opting in.
|
|
83
83
|
*/
|
|
84
84
|
export function addMultiUserSecretRotation(params) {
|
|
85
|
-
const rotationPeriod = params.rotationConfig.automaticallyAfter ??
|
|
85
|
+
const rotationPeriod = params.rotationConfig.automaticallyAfter ??
|
|
86
|
+
(params.rotationConfig.automaticallyAfterDays !== undefined
|
|
87
|
+
? Duration.days(params.rotationConfig.automaticallyAfterDays)
|
|
88
|
+
: Duration.days(30));
|
|
86
89
|
const masterSecret = new Secret(params.scope, `${params.databaseName}MasterSecret`, {
|
|
87
90
|
secretName: ResourceNaming.masterSecretName(params.constructId)
|
|
88
91
|
});
|
|
@@ -9,6 +9,13 @@ export interface DomainCertificateProps {
|
|
|
9
9
|
readonly transparencyLogging?: boolean;
|
|
10
10
|
readonly costAllocationEnvironment?: string;
|
|
11
11
|
readonly costAllocationDomain?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Publish the `${domain}-certificate-arn` CloudFormation export. Default true.
|
|
14
|
+
* Set false when the cert is consumed in-stack (single-stack patterns) to
|
|
15
|
+
* avoid an export collision with a managed-domain/apex stack that also owns
|
|
16
|
+
* the domain's exports.
|
|
17
|
+
*/
|
|
18
|
+
readonly exportCertificateArn?: boolean;
|
|
12
19
|
}
|
|
13
20
|
export declare class DomainCertificate extends Construct {
|
|
14
21
|
readonly certificate: ICertificate;
|
|
@@ -26,12 +26,14 @@ export class DomainCertificate extends Construct {
|
|
|
26
26
|
domain: props.costAllocationDomain ?? props.domainName,
|
|
27
27
|
environment: props.costAllocationEnvironment
|
|
28
28
|
});
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
29
|
+
if (props.exportCertificateArn !== false) {
|
|
30
|
+
const safeKey = toPascalCase(props.domainName.split(".").join(""));
|
|
31
|
+
const exports = getDomainExportNames(props.domainName);
|
|
32
|
+
new CfnOutput(this, `${safeKey}CertificateArn`, {
|
|
33
|
+
key: `${safeKey}CertificateArn`,
|
|
34
|
+
value: this.certificateArn,
|
|
35
|
+
exportName: exports.certificateArn
|
|
36
|
+
});
|
|
37
|
+
}
|
|
36
38
|
}
|
|
37
39
|
}
|
|
@@ -45,6 +45,12 @@ export interface CredentialsConfig {
|
|
|
45
45
|
}
|
|
46
46
|
export interface SecretRotationConfig {
|
|
47
47
|
automaticallyAfter?: Duration;
|
|
48
|
+
/**
|
|
49
|
+
* Rotation period in whole days — the JSON-friendly form the generator
|
|
50
|
+
* scaffolds (`secretRotation: { automaticallyAfterDays: 30 }`). Ignored
|
|
51
|
+
* when `automaticallyAfter` is also set. Default: 30 days.
|
|
52
|
+
*/
|
|
53
|
+
automaticallyAfterDays?: number;
|
|
48
54
|
}
|
|
49
55
|
/**
|
|
50
56
|
* Resolve the opt-in rotation gate once at the construct boundary. Returns
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fjall/components-infrastructure",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.30.0",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -34,7 +34,8 @@
|
|
|
34
34
|
"clean": "rm -rf ./dist",
|
|
35
35
|
"clean:node": "rm -rf ./node_modules",
|
|
36
36
|
"build:cert-gen-lambda": "node lib/lambda-assets/cert-generator/src/build.mjs",
|
|
37
|
-
"build": "npm run build:cert-gen-lambda && tsc && cp -r lib/layers dist/lib/layers && mkdir -p dist/lib/lambda-assets/cert-generator/asset && cp lib/lambda-assets/cert-generator/asset/index.js dist/lib/lambda-assets/cert-generator/asset/index.js && cp lib/lambda-assets/cert-generator/asset/package.json dist/lib/lambda-assets/cert-generator/asset/package.json && mkdir -p dist/lib/lambda-assets/identity-store-user/asset && cp lib/lambda-assets/identity-store-user/asset/index.js dist/lib/lambda-assets/identity-store-user/asset/index.js && cp lib/lambda-assets/identity-store-user/asset/package.json dist/lib/lambda-assets/identity-store-user/asset/package.json && cp lib/resources/aws/compute/lifecycleHookLambda.source.cjs dist/lib/resources/aws/compute/lifecycleHookLambda.source.cjs && cp lib/resources/aws/compute/ec2GracefulTerminationLambda.source.cjs dist/lib/resources/aws/compute/ec2GracefulTerminationLambda.source.cjs && cp lib/resources/aws/compute/persistentDataVolumeLambda.source.cjs dist/lib/resources/aws/compute/persistentDataVolumeLambda.source.cjs",
|
|
37
|
+
"build": "npm run build:cert-gen-lambda && tsc && cp -r lib/layers dist/lib/layers && mkdir -p dist/lib/lambda-assets/cert-generator/asset && cp lib/lambda-assets/cert-generator/asset/index.js dist/lib/lambda-assets/cert-generator/asset/index.js && cp lib/lambda-assets/cert-generator/asset/package.json dist/lib/lambda-assets/cert-generator/asset/package.json && mkdir -p dist/lib/lambda-assets/identity-store-user/asset && cp lib/lambda-assets/identity-store-user/asset/index.js dist/lib/lambda-assets/identity-store-user/asset/index.js && cp lib/lambda-assets/identity-store-user/asset/package.json dist/lib/lambda-assets/identity-store-user/asset/package.json && mkdir -p dist/lib/lambda-assets/static-site-forms/asset && cp lib/lambda-assets/static-site-forms/asset/index.js dist/lib/lambda-assets/static-site-forms/asset/index.js && cp lib/lambda-assets/static-site-forms/asset/package.json dist/lib/lambda-assets/static-site-forms/asset/package.json && cp lib/resources/aws/compute/lifecycleHookLambda.source.cjs dist/lib/resources/aws/compute/lifecycleHookLambda.source.cjs && cp lib/resources/aws/compute/ec2GracefulTerminationLambda.source.cjs dist/lib/resources/aws/compute/ec2GracefulTerminationLambda.source.cjs && cp lib/resources/aws/compute/persistentDataVolumeLambda.source.cjs dist/lib/resources/aws/compute/persistentDataVolumeLambda.source.cjs",
|
|
38
|
+
"prepack": "node ../../scripts/check-dist-freshness.mjs",
|
|
38
39
|
"watch": "tsc -w",
|
|
39
40
|
"watch:only": "tsc -w",
|
|
40
41
|
"test": "vitest run",
|
|
@@ -52,6 +53,7 @@
|
|
|
52
53
|
"@aws-sdk/client-elastic-load-balancing-v2": "^3.1045.0",
|
|
53
54
|
"@aws-sdk/client-iam": "^3.1038.0",
|
|
54
55
|
"@aws-sdk/client-identitystore": "^3.1038.0",
|
|
56
|
+
"@aws-sdk/client-sesv2": "^3.1087.0",
|
|
55
57
|
"@peculiar/x509": "2.0.0",
|
|
56
58
|
"@types/aws-lambda": "^8.10.161",
|
|
57
59
|
"@types/node": "^26.0.0",
|
|
@@ -65,8 +67,8 @@
|
|
|
65
67
|
},
|
|
66
68
|
"dependencies": {
|
|
67
69
|
"@aws-sdk/client-organizations": "^3.1038.0",
|
|
68
|
-
"@fjall/generator": "^2.
|
|
69
|
-
"@fjall/util": "^2.
|
|
70
|
+
"@fjall/generator": "^2.30.0",
|
|
71
|
+
"@fjall/util": "^2.30.0",
|
|
70
72
|
"constructs": "^10.6.0"
|
|
71
73
|
},
|
|
72
74
|
"overrides": {
|
|
@@ -80,5 +82,5 @@
|
|
|
80
82
|
"engines": {
|
|
81
83
|
"node": ">=18.0.0"
|
|
82
84
|
},
|
|
83
|
-
"gitHead": "
|
|
85
|
+
"gitHead": "ec35b16db566dfa5feb714c16f132c55b4663c86"
|
|
84
86
|
}
|