@infoxchange/make-it-so 2.13.0-internal-testing-randomise-subnet.2 → 2.13.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/README.md CHANGED
@@ -250,14 +250,38 @@ new IxDnsRecord(scope, "IxDnsRecord", {
250
250
 
251
251
  #### Options:
252
252
 
253
- | Prop | Type | Description |
254
- | ------------ | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
255
- | type | "A" \| "CNAME" \| "NS" \| "SOA" \| "ALIAS" | DNS record type |
256
- | name | string | DNS record FQDN |
257
- | value | string | DNS record value |
258
- | ttl | number | (optional) TTL value for DNS record |
259
- | hostedZoneId | string | (optional) The ID of the Route53 HostedZone belonging to the dns-hosting account in which to create the DNS record. If not given the correct HostedZone will be inferred from the domain in the "value" prop. |
260
- | aliasZoneId | string | (only needed if type = "Alias") the Route53 HostedZone that the target of the alias record lives in. Generally this will be the well known ID of a HostedZone for a AWS service itself that is managed by AWS, not an end-user. |
253
+ | Prop | Type | Description |
254
+ | ------------ | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
255
+ | type | "A" \| "CNAME" \| "NS" \| "SOA" \| "ALIAS" \| "TXT" \| "MX" | DNS record type |
256
+ | name | string | DNS record FQDN |
257
+ | value | string | DNS record value |
258
+ | ttl | number | (optional) TTL value for DNS record |
259
+ | hostedZoneId | string | (optional) The ID of the Route53 HostedZone belonging to the dns-hosting account in which to create the DNS record. If not given the correct HostedZone will be inferred from the domain in the "value" prop. |
260
+ | aliasZoneId | string | (only needed if type = "Alias") the Route53 HostedZone that the target of the alias record lives in. Generally this will be the well known ID of a HostedZone for a AWS service itself that is managed by AWS, not an end-user. |
261
+ | priority | number | (only needed if type = "MX") The priority level of the MX record. |
262
+
263
+ </details>
264
+
265
+ <details>
266
+ <summary><strong>IxSESIdentity</strong> - Creates an SES domain identity for a domain managed by IX.</summary>
267
+
268
+ ```typescript
269
+ import { IxSESIdentity } from "@infoxchange/make-it-so/cdk-constructs";
270
+
271
+ new IxSESIdentity(scope, "IxSESIdentity", {
272
+ // Email identity domain will be: example.dev.ixapps.org
273
+ // Custom mail from domain will be: info.example.dev.ixapps.org
274
+ domain: "example.dev.ixapps.org",
275
+ mailFromSubdomain: "info", // optional, "mail" will be used otherwise
276
+ });
277
+ ```
278
+
279
+ #### Options:
280
+
281
+ | Prop | Type | Description |
282
+ | ----------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
283
+ | domain | string | The domain of the identity. An email address can also be provided in which case the domain will be extracted from the email. |
284
+ | mailFromSubdomain | string | (optional) by default the custom mail from domain will be `mail.${domain}`. This lets you change that. It should be given as just the subdomain part, not the fully qualified domain. |
261
285
 
262
286
  </details>
263
287
 
@@ -7,10 +7,13 @@ type Props = {
7
7
  ttl?: number;
8
8
  hostedZoneId?: string;
9
9
  } & ({
10
- type: "A" | "CNAME" | "NS" | "SOA";
10
+ type: "A" | "CNAME" | "NS" | "SOA" | "TXT";
11
11
  } | {
12
12
  type: "ALIAS";
13
13
  aliasZoneId: string;
14
+ } | {
15
+ type: "MX";
16
+ priority: number;
14
17
  });
15
18
  export declare class IxDnsRecord extends Construct {
16
19
  constructor(scope: ConstructScope, id: ConstructId, props: Props);
@@ -1 +1 @@
1
- {"version":3,"file":"IxDnsRecord.d.ts","sourceRoot":"","sources":["../../src/cdk-constructs/IxDnsRecord.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAKvC,KAAK,cAAc,GAAG,qBAAqB,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AACjE,KAAK,WAAW,GAAG,qBAAqB,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAE9D,KAAK,KAAK,GAAG;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GAAG,CACA;IACE,IAAI,EAAE,GAAG,GAAG,OAAO,GAAG,IAAI,GAAG,KAAK,CAAC;CACpC,GACD;IACE,IAAI,EAAE,OAAO,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB,CACJ,CAAC;AAEF,qBAAa,WAAY,SAAQ,SAAS;gBAC5B,KAAK,EAAE,cAAc,EAAE,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK;IAKhE,OAAO,CAAC,eAAe;CAyBxB"}
1
+ {"version":3,"file":"IxDnsRecord.d.ts","sourceRoot":"","sources":["../../src/cdk-constructs/IxDnsRecord.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAKvC,KAAK,cAAc,GAAG,qBAAqB,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AACjE,KAAK,WAAW,GAAG,qBAAqB,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAE9D,KAAK,KAAK,GAAG;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GAAG,CACA;IACE,IAAI,EAAE,GAAG,GAAG,OAAO,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK,CAAC;CAC5C,GACD;IACE,IAAI,EAAE,OAAO,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB,GACD;IACE,IAAI,EAAE,IAAI,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;CAClB,CACJ,CAAC;AAEF,qBAAa,WAAY,SAAQ,SAAS;gBAC5B,KAAK,EAAE,cAAc,EAAE,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK;IAKhE,OAAO,CAAC,eAAe;CA6CxB"}
@@ -9,14 +9,31 @@ export class IxDnsRecord extends Construct {
9
9
  }
10
10
  createDnsRecord(scope, id, constructProps) {
11
11
  const dnsRecordUpdaterLambdaArn = StringParameter.valueForStringParameter(scope, "/shared-services/route53/lambdaArn");
12
- const lambdaProps = remapKeys(constructProps, {
12
+ const keysMap = {
13
13
  name: "RecordFQDN",
14
14
  value: "RecordValue",
15
15
  ttl: "RecordTTL",
16
16
  hostedZoneId: "HostedZoneId",
17
17
  type: "RecordType",
18
18
  aliasZoneId: "AliasZoneId",
19
- });
19
+ };
20
+ let lambdaProps;
21
+ if (constructProps.type === "TXT") {
22
+ lambdaProps = remapKeys({
23
+ ...constructProps,
24
+ value: `"${constructProps.value}"`,
25
+ }, keysMap);
26
+ }
27
+ else if (constructProps.type === "MX") {
28
+ const { priority, ...rest } = constructProps;
29
+ lambdaProps = remapKeys({
30
+ ...rest,
31
+ value: `${priority} ${rest.value}`,
32
+ }, keysMap);
33
+ }
34
+ else {
35
+ lambdaProps = remapKeys(constructProps, keysMap);
36
+ }
20
37
  new CustomResource(scope, id + "-CertificateCustomResource", {
21
38
  resourceType: "Custom::DNSRecordUpdaterLambda",
22
39
  serviceToken: dnsRecordUpdaterLambdaArn,
@@ -0,0 +1,12 @@
1
+ import { Construct } from "constructs";
2
+ type ConstructScope = ConstructorParameters<typeof Construct>[0];
3
+ type ConstructId = ConstructorParameters<typeof Construct>[1];
4
+ type Props = {
5
+ domain: string;
6
+ mailFromSubdomain?: string;
7
+ };
8
+ export declare class IxSESIdentity extends Construct {
9
+ constructor(scope: ConstructScope, id: ConstructId, props: Props);
10
+ }
11
+ export {};
12
+ //# sourceMappingURL=IxSESIdentity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IxSESIdentity.d.ts","sourceRoot":"","sources":["../../src/cdk-constructs/IxSESIdentity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAKvC,KAAK,cAAc,GAAG,qBAAqB,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AACjE,KAAK,WAAW,GAAG,qBAAqB,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAE9D,KAAK,KAAK,GAAG;IACX,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,qBAAa,aAAc,SAAQ,SAAS;gBAC9B,KAAK,EAAE,cAAc,EAAE,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK;CAuDjE"}
@@ -0,0 +1,45 @@
1
+ import { Construct } from "constructs";
2
+ import { IxDnsRecord } from "./IxDnsRecord.js";
3
+ import * as ses from "aws-cdk-lib/aws-ses";
4
+ import * as cdk from "aws-cdk-lib";
5
+ export class IxSESIdentity extends Construct {
6
+ constructor(scope, id, props) {
7
+ const domain = props.domain.includes("@")
8
+ ? props.domain.split("@")[1]
9
+ : props.domain;
10
+ const mailFromDomain = `${props.mailFromSubdomain ?? "mail"}.${domain}`;
11
+ super(scope, id);
12
+ const identity = new ses.EmailIdentity(scope, `${id}EmailIdentity`, {
13
+ identity: ses.Identity.domain(domain),
14
+ mailFromDomain,
15
+ });
16
+ // Based on https://github.com/aws/aws-cdk/blob/e2ef65a26c833ecb4a29c22e070c3c5f01c31995/packages/aws-cdk-lib/aws-ses/lib/email-identity.ts#L247
17
+ for (const i of [1, 2, 3]) {
18
+ new IxDnsRecord(scope, `${id}DkimDnsToken${i}`, {
19
+ type: "CNAME",
20
+ name: identity[`dkimDnsTokenName${i}`],
21
+ value: identity[`dkimDnsTokenValue${i}`],
22
+ ttl: 1800,
23
+ });
24
+ }
25
+ // Based on
26
+ // https://github.com/aws/aws-cdk/blob/e2ef65a26c833ecb4a29c22e070c3c5f01c31995/packages/aws-cdk-lib/aws-ses/lib/email-identity.ts#L512
27
+ new IxDnsRecord(scope, `${id}MailFromMxRecord`, {
28
+ type: "MX",
29
+ name: mailFromDomain,
30
+ value: `feedback-smtp.${cdk.Stack.of(scope).region}.amazonses.com`,
31
+ priority: 10,
32
+ });
33
+ new IxDnsRecord(scope, `${id}MailFromTxtRecord`, {
34
+ type: "TXT",
35
+ name: mailFromDomain,
36
+ value: "v=spf1 include:amazonses.com ~all",
37
+ });
38
+ // Set up DMARC record
39
+ new IxDnsRecord(scope, `${id}DMARC`, {
40
+ type: "TXT",
41
+ name: `_dmarc.${domain}`,
42
+ value: "v=DMARC1; p=none;",
43
+ });
44
+ }
45
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"IxVpcDetails.d.ts","sourceRoot":"","sources":["../../src/cdk-constructs/IxVpcDetails.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,OAAO,EAAO,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAGhD,KAAK,cAAc,GAAG,qBAAqB,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AACjE,KAAK,WAAW,GAAG,qBAAqB,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAE9D,qBAAa,YAAa,SAAQ,SAAS;IAClC,GAAG,EAAE,IAAI,CAAC;gBAEL,KAAK,EAAE,cAAc,EAAE,EAAE,EAAE,WAAW;IAKlD,OAAO,CAAC,MAAM;IAad,MAAM,CAAC,eAAe,CAAC,KAAK,EAAE,cAAc,GAAG,KAAK,CAAC,MAAM,CAAC;CAmB7D"}
1
+ {"version":3,"file":"IxVpcDetails.d.ts","sourceRoot":"","sources":["../../src/cdk-constructs/IxVpcDetails.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,OAAO,EAAO,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAGhD,KAAK,cAAc,GAAG,qBAAqB,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AACjE,KAAK,WAAW,GAAG,qBAAqB,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAE9D,qBAAa,YAAa,SAAQ,SAAS;IAClC,GAAG,EAAE,IAAI,CAAC;gBAEL,KAAK,EAAE,cAAc,EAAE,EAAE,EAAE,WAAW;IAKlD,OAAO,CAAC,MAAM;IAad,MAAM,CAAC,eAAe,CAAC,KAAK,EAAE,cAAc,GAAG,KAAK,CAAC,MAAM,CAAC;CAQ7D"}
@@ -21,17 +21,6 @@ export class IxVpcDetails extends Construct {
21
21
  });
22
22
  }
23
23
  static getVpcSubnetIds(scope) {
24
- const { workloadGroup, appName } = ixDeployConfig;
25
- let suffix = "";
26
- if (workloadGroup === "ds") {
27
- const possibleSuffixes = ["", "-2"];
28
- // Randomly select a suffix to spread workload's IP usage across both sets of subnets. Use the app name as a seed
29
- // to ensure consistent selection on redeploys.
30
- const hash = appName
31
- .split("")
32
- .reduce((acc, char) => acc + char.charCodeAt(0), 0);
33
- suffix = possibleSuffixes[hash % possibleSuffixes.length];
34
- }
35
- return [1, 2, 3].map((subnetNum) => StringParameter.valueForStringParameter(scope, `/vpc/subnet/private-${workloadGroup}${suffix}/${subnetNum}/id`));
24
+ return [1, 2, 3].map((subnetNum) => StringParameter.valueForStringParameter(scope, `/vpc/subnet/private-${ixDeployConfig.workloadGroup}/${subnetNum}/id`));
36
25
  }
37
26
  }
@@ -165,7 +165,7 @@ export class SiteOidcAuth extends Construct {
165
165
  origin: new CloudFrontOrigins.HttpOrigin(CDK.Fn.parseDomainName(authRouteFunctionUrl.url)),
166
166
  allowedMethods: CloudFront.AllowedMethods.ALLOW_ALL,
167
167
  cachePolicy: new CloudFront.CachePolicy(scope, `${this.id}AllowAllCookiesPolicy`, {
168
- cachePolicyName: `${CDK.Stack.of(scope).stackName}-${this.id}-AllowAllCookiesPolicy`,
168
+ cachePolicyName: `${this.id}-AllowAllCookiesPolicy`,
169
169
  comment: "Cache policy that forwards all cookies",
170
170
  defaultTtl: CDK.Duration.seconds(1),
171
171
  minTtl: CDK.Duration.seconds(1),
@@ -1,6 +1,7 @@
1
1
  export * from "./IxVpcDetails.js";
2
2
  export * from "./IxCertificate.js";
3
3
  export * from "./IxDnsRecord.js";
4
+ export * from "./IxSESIdentity.js";
4
5
  export * from "./IxNextjsSite.js";
5
6
  export * from "./IxStaticSite.js";
6
7
  export * from "./IxElasticache.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cdk-constructs/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC;AAC3B,cAAc,4BAA4B,CAAC;AAC3C,cAAc,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cdk-constructs/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC;AAC3B,cAAc,4BAA4B,CAAC;AAC3C,cAAc,yBAAyB,CAAC"}
@@ -1,6 +1,7 @@
1
1
  export * from "./IxVpcDetails.js";
2
2
  export * from "./IxCertificate.js";
3
3
  export * from "./IxDnsRecord.js";
4
+ export * from "./IxSESIdentity.js";
4
5
  export * from "./IxNextjsSite.js";
5
6
  export * from "./IxStaticSite.js";
6
7
  export * from "./IxElasticache.js";
@@ -1,4 +1,4 @@
1
1
  export declare function remapKeys<SourceObject extends object, MapObject extends Record<keyof SourceObject, string>>(object: SourceObject, keyMap: Readonly<MapObject>): {
2
- [k in keyof SourceObject]: MapObject[k];
2
+ [k in keyof SourceObject as k extends keyof MapObject ? MapObject[k] : k]: SourceObject[k];
3
3
  };
4
4
  //# sourceMappingURL=objects.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"objects.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/objects.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,CACvB,YAAY,SAAS,MAAM,EAC3B,SAAS,SAAS,MAAM,CAAC,MAAM,YAAY,EAAE,MAAM,CAAC,EAEpD,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,QAAQ,CAAC,SAAS,CAAC,GAC1B;KAAG,CAAC,IAAI,MAAM,YAAY,GAAG,SAAS,CAAC,CAAC,CAAC;CAAE,CAQ7C"}
1
+ {"version":3,"file":"objects.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/objects.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,CACvB,YAAY,SAAS,MAAM,EAC3B,SAAS,SAAS,MAAM,CAAC,MAAM,YAAY,EAAE,MAAM,CAAC,EAEpD,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,QAAQ,CAAC,SAAS,CAAC,GAC1B;KACA,CAAC,IAAI,MAAM,YAAY,IAAI,CAAC,SAAS,MAAM,SAAS,GACjD,SAAS,CAAC,CAAC,CAAC,GACZ,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC;CACxB,CAQA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@infoxchange/make-it-so",
3
- "version": "2.13.0-internal-testing-randomise-subnet.2",
3
+ "version": "2.13.0",
4
4
  "description": "Makes deploying services to IX infra easy",
5
5
  "repository": "github:infoxchange/make-it-so",
6
6
  "type": "module",
@@ -13,12 +13,16 @@ type Props = {
13
13
  hostedZoneId?: string;
14
14
  } & (
15
15
  | {
16
- type: "A" | "CNAME" | "NS" | "SOA";
16
+ type: "A" | "CNAME" | "NS" | "SOA" | "TXT";
17
17
  }
18
18
  | {
19
19
  type: "ALIAS";
20
20
  aliasZoneId: string;
21
21
  }
22
+ | {
23
+ type: "MX";
24
+ priority: number;
25
+ }
22
26
  );
23
27
 
24
28
  export class IxDnsRecord extends Construct {
@@ -36,15 +40,35 @@ export class IxDnsRecord extends Construct {
36
40
  scope,
37
41
  "/shared-services/route53/lambdaArn",
38
42
  );
39
-
40
- const lambdaProps = remapKeys(constructProps, {
43
+ const keysMap = {
41
44
  name: "RecordFQDN",
42
45
  value: "RecordValue",
43
46
  ttl: "RecordTTL",
44
47
  hostedZoneId: "HostedZoneId",
45
48
  type: "RecordType",
46
49
  aliasZoneId: "AliasZoneId",
47
- });
50
+ };
51
+ let lambdaProps;
52
+ if (constructProps.type === "TXT") {
53
+ lambdaProps = remapKeys(
54
+ {
55
+ ...constructProps,
56
+ value: `"${constructProps.value}"`,
57
+ },
58
+ keysMap,
59
+ );
60
+ } else if (constructProps.type === "MX") {
61
+ const { priority, ...rest } = constructProps;
62
+ lambdaProps = remapKeys(
63
+ {
64
+ ...rest,
65
+ value: `${priority} ${rest.value}`,
66
+ },
67
+ keysMap,
68
+ );
69
+ } else {
70
+ lambdaProps = remapKeys(constructProps, keysMap);
71
+ }
48
72
 
49
73
  new CustomResource(scope, id + "-CertificateCustomResource", {
50
74
  resourceType: "Custom::DNSRecordUpdaterLambda",
@@ -0,0 +1,70 @@
1
+ import { Construct } from "constructs";
2
+ import { IxDnsRecord } from "./IxDnsRecord.js";
3
+ import * as ses from "aws-cdk-lib/aws-ses";
4
+ import * as cdk from "aws-cdk-lib";
5
+
6
+ type ConstructScope = ConstructorParameters<typeof Construct>[0];
7
+ type ConstructId = ConstructorParameters<typeof Construct>[1];
8
+
9
+ type Props = {
10
+ domain: string;
11
+ mailFromSubdomain?: string;
12
+ };
13
+
14
+ export class IxSESIdentity extends Construct {
15
+ constructor(scope: ConstructScope, id: ConstructId, props: Props) {
16
+ const domain = props.domain.includes("@")
17
+ ? props.domain.split("@")[1]
18
+ : props.domain;
19
+ const mailFromDomain = `${props.mailFromSubdomain ?? "mail"}.${domain}`;
20
+
21
+ super(scope, id);
22
+
23
+ const identity = new ses.EmailIdentity(scope, `${id}EmailIdentity`, {
24
+ identity: ses.Identity.domain(domain),
25
+ mailFromDomain,
26
+ });
27
+
28
+ // Based on https://github.com/aws/aws-cdk/blob/e2ef65a26c833ecb4a29c22e070c3c5f01c31995/packages/aws-cdk-lib/aws-ses/lib/email-identity.ts#L247
29
+ for (const i of [1, 2, 3]) {
30
+ new IxDnsRecord(scope, `${id}DkimDnsToken${i}`, {
31
+ type: "CNAME",
32
+ name: identity[
33
+ `dkimDnsTokenName${i}` as
34
+ | "dkimDnsTokenName1"
35
+ | "dkimDnsTokenName2"
36
+ | "dkimDnsTokenName3"
37
+ ],
38
+ value:
39
+ identity[
40
+ `dkimDnsTokenValue${i}` as
41
+ | "dkimDnsTokenValue1"
42
+ | "dkimDnsTokenValue2"
43
+ | "dkimDnsTokenValue3"
44
+ ],
45
+ ttl: 1800,
46
+ });
47
+ }
48
+
49
+ // Based on
50
+ // https://github.com/aws/aws-cdk/blob/e2ef65a26c833ecb4a29c22e070c3c5f01c31995/packages/aws-cdk-lib/aws-ses/lib/email-identity.ts#L512
51
+ new IxDnsRecord(scope, `${id}MailFromMxRecord`, {
52
+ type: "MX",
53
+ name: mailFromDomain,
54
+ value: `feedback-smtp.${cdk.Stack.of(scope).region}.amazonses.com`,
55
+ priority: 10,
56
+ });
57
+ new IxDnsRecord(scope, `${id}MailFromTxtRecord`, {
58
+ type: "TXT",
59
+ name: mailFromDomain,
60
+ value: "v=spf1 include:amazonses.com ~all",
61
+ });
62
+
63
+ // Set up DMARC record
64
+ new IxDnsRecord(scope, `${id}DMARC`, {
65
+ type: "TXT",
66
+ name: `_dmarc.${domain}`,
67
+ value: "v=DMARC1; p=none;",
68
+ });
69
+ }
70
+ }
@@ -28,21 +28,10 @@ export class IxVpcDetails extends Construct {
28
28
  }
29
29
 
30
30
  static getVpcSubnetIds(scope: ConstructScope): Array<string> {
31
- const { workloadGroup, appName } = ixDeployConfig;
32
- let suffix = "";
33
- if (workloadGroup === "ds") {
34
- const possibleSuffixes = ["", "-2"];
35
- // Randomly select a suffix to spread workload's IP usage across both sets of subnets. Use the app name as a seed
36
- // to ensure consistent selection on redeploys.
37
- const hash = appName
38
- .split("")
39
- .reduce((acc, char) => acc + char.charCodeAt(0), 0);
40
- suffix = possibleSuffixes[hash % possibleSuffixes.length];
41
- }
42
31
  return [1, 2, 3].map((subnetNum) =>
43
32
  StringParameter.valueForStringParameter(
44
33
  scope,
45
- `/vpc/subnet/private-${workloadGroup}${suffix}/${subnetNum}/id`,
34
+ `/vpc/subnet/private-${ixDeployConfig.workloadGroup}/${subnetNum}/id`,
46
35
  ),
47
36
  );
48
37
  }
@@ -274,7 +274,7 @@ export class SiteOidcAuth extends Construct {
274
274
  scope,
275
275
  `${this.id}AllowAllCookiesPolicy`,
276
276
  {
277
- cachePolicyName: `${CDK.Stack.of(scope).stackName}-${this.id}-AllowAllCookiesPolicy`,
277
+ cachePolicyName: `${this.id}-AllowAllCookiesPolicy`,
278
278
  comment: "Cache policy that forwards all cookies",
279
279
  defaultTtl: CDK.Duration.seconds(1),
280
280
  minTtl: CDK.Duration.seconds(1),
@@ -1,6 +1,7 @@
1
1
  export * from "./IxVpcDetails.js";
2
2
  export * from "./IxCertificate.js";
3
3
  export * from "./IxDnsRecord.js";
4
+ export * from "./IxSESIdentity.js";
4
5
  export * from "./IxNextjsSite.js";
5
6
  export * from "./IxStaticSite.js";
6
7
  export * from "./IxElasticache.js";
@@ -4,7 +4,11 @@ export function remapKeys<
4
4
  >(
5
5
  object: SourceObject,
6
6
  keyMap: Readonly<MapObject>,
7
- ): { [k in keyof SourceObject]: MapObject[k] } {
7
+ ): {
8
+ [k in keyof SourceObject as k extends keyof MapObject
9
+ ? MapObject[k]
10
+ : k]: SourceObject[k];
11
+ } {
8
12
  return Object.fromEntries(
9
13
  Object.entries(object).map(([key, value]) => {
10
14
  // @ts-expect-error the typing for map() reduces keys to general string