diff --git a/src/routes/formsg/formsgSiteLaunch.ts b/src/routes/formsg/formsgSiteLaunch.ts index 2fdba9420..ef736ffd2 100644 --- a/src/routes/formsg/formsgSiteLaunch.ts +++ b/src/routes/formsg/formsgSiteLaunch.ts @@ -22,6 +22,7 @@ import { getDNSRecordsEmailBody, getErrorEmailBody, } from "@root/services/utilServices/SendDNSRecordEmailClient" +import TRUSTED_AMPLIFY_CAA_RECORDS from "@root/types/caaAmplify" import { DigResponse, DigType } from "@root/types/dig" import UsersService from "@services/identity/UsersService" import InfraService from "@services/infra/InfraService" @@ -231,7 +232,7 @@ export class FormsgSiteLaunchRouter { await mailer.sendMail(email, subject, html) } - private digDomainForQuadARecords = async ( + digDomainRecords = async ( domain: string, digType: DigType ): Promise => @@ -332,13 +333,18 @@ export class FormsgSiteLaunchRouter { for (const launchResult of launchResults) { if (launchResult.isOk()) { // check for AAAA records - const digResponse = await this.digDomainForQuadARecords( + const quadADigResponse = await this.digDomainRecords( launchResult.value.primaryDomainSource, "AAAA" ) + const caaDigResponse = await this.digDomainRecords( + launchResult.value.primaryDomainSource, + "CAA" + ) + const successResult: DnsRecordsEmailProps = launchResult.value - if (digResponse && digResponse.answer) { - const quadARecords = digResponse.answer + if (quadADigResponse && quadADigResponse.answer) { + const quadARecords = quadADigResponse.answer successResult.quadARecords = quadARecords.map((record) => ({ domain: record.domain, class: record.class, @@ -350,6 +356,35 @@ export class FormsgSiteLaunchRouter { `Unable to get dig response for domain: ${launchResult.value.primaryDomainSource}. Skipping check for AAAA records` ) } + + if (!caaDigResponse) { + logger.info( + `Unable to get dig response for domain: ${launchResult.value.primaryDomainSource}. Skipping check for CAA records` + ) + } else if (caaDigResponse.answer) { + const caaRecords = caaDigResponse.answer + + /** + * NOTE: If there exists more than one CAA Record, we need to + * 1. check if they have whitelisted Amazon CAA + * 2. if not, send email to inform them to whitelist Amazon CAA + */ + const hasAmazonCAAWhitelisted = caaRecords.some((record) => { + const isAmazonCAA = TRUSTED_AMPLIFY_CAA_RECORDS.some( + (trustedCAA) => trustedCAA === record.value + ) + return isAmazonCAA + }) + if (caaRecords.length > 0 && !hasAmazonCAAWhitelisted) { + successResult.addCAARecord = true + } else { + successResult.addCAARecord = false + } + } else { + logger.info( + `${launchResult.value.primaryDomainSource} Domain does not have any CAA records.` + ) + } // Create better uptime monitor await this.createMonitor(launchResult.value.primaryDomainSource) successResults.push(successResult) diff --git a/src/services/utilServices/SendDNSRecordEmailClient.ts b/src/services/utilServices/SendDNSRecordEmailClient.ts index 9593394fa..ca9bd3641 100644 --- a/src/services/utilServices/SendDNSRecordEmailClient.ts +++ b/src/services/utilServices/SendDNSRecordEmailClient.ts @@ -2,12 +2,13 @@ import { groupBy } from "lodash" import { DigType } from "@root/types/dig" -export interface QuadARecord { +export interface DigDNSRecord { domain: string class: string type: DigType value: string } + export interface DnsRecordsEmailProps { requesterEmail: string repoName: string @@ -18,7 +19,8 @@ export interface DnsRecordsEmailProps { indirectionDomain: string redirectionDomainSource?: string redirectionDomainTarget?: string - quadARecords?: QuadARecord[] + quadARecords?: DigDNSRecord[] + addCAARecord?: boolean } export interface LaunchFailureEmailProps { @@ -109,7 +111,43 @@ export function getDNSRecordsEmailBody( ` Object.keys(groupedDnsRecords).forEach((repoName) => { - const allQuadARecordsForRepo: QuadARecord[] = [] + groupedDnsRecords[repoName].forEach((dnsRecord) => { + if (dnsRecord.addCAARecord) { + html += `

Please add CAA records for the following repo: ${repoName}.` + + html += ` + + + + + + + + + + + + + + + + + + + + + + + + + +
Repo NameTypeFlagsTagValue
${repoName}${dnsRecord.primaryDomainSource}0issueamazontrust.com
${dnsRecord.primaryDomainSource}0issueamazontrust.com
` + } + }) + }) + + Object.keys(groupedDnsRecords).forEach((repoName) => { + const allQuadARecordsForRepo: DigDNSRecord[] = [] groupedDnsRecords[repoName].forEach((dnsRecord) => { if (dnsRecord.quadARecords) { allQuadARecordsForRepo.push(...dnsRecord.quadARecords) @@ -147,7 +185,6 @@ export function getDNSRecordsEmailBody( }) html += `

This email was sent from the Isomer CMS backend.

` - return html } diff --git a/src/types/caaAmplify.ts b/src/types/caaAmplify.ts new file mode 100644 index 000000000..54607dbfb --- /dev/null +++ b/src/types/caaAmplify.ts @@ -0,0 +1,11 @@ +/** + * This is taken from https://docs.aws.amazon.com/acm/latest/userguide/setup-caa.html + */ +const TRUSTED_AMPLIFY_CAA_RECORDS = [ + "amazon.com", + "amazontrust.com", + "awstrust.com", + "amazonaws.com", +] + +export default TRUSTED_AMPLIFY_CAA_RECORDS diff --git a/src/types/dig.ts b/src/types/dig.ts index 3b8d91643..9cf4f352e 100644 --- a/src/types/dig.ts +++ b/src/types/dig.ts @@ -23,3 +23,4 @@ export type DigType = | "SOA" | "SRV" | "TXT" + | "CAA"