Repository: amplify-education/serverless-domain-manager (ts)

Issue:
Could not find an in-date certificate
<!--- Please keep this note for the community --->

### Community Note

* Please vote on this issue by adding a 👍 [reaction](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to the original issue to help the community and maintainers prioritize this request
* Please do not leave "+1" or "me too" comments, they generate extra noise for issue followers and do not help prioritize the request
* If you are interested in working on this issue or have submitted a pull request, please leave a comment

<!--- Thank you for keeping this note for the community --->

## Bug Report

**Error Description**

serverless domain manager fails to create sub domain even though certificate exists. 

![image](https://user-images.githubusercontent.com/5202527/179238609-a6bc25dc-cb47-4e3f-88ea-86320b1f3e23.png)


**Command Run**
`sls create_domain`

**Console Output**
```sh
Environment: linux, node 16.13.0, framework 3.21.0 (local) 3.19.0v (global), plugin 6.2.2, SDK 4.3.2
Credentials: Local, "default" profile
Docs:        docs.serverless.com
Support:     forum.serverless.com
Bugs:        github.com/serverless/serverless/issues

Error:
Error: Unable to create domain 'image-service.staging.geeiq.com':
Could not find an in-date certificate for '*.staging.geeiq.com'.
    at ServerlessCustomDomain.<anonymous> (/home/kay/checkpoint/image-service/node_modules/serverless-domain-manager/dist/src/index.js:193:23)
    at Generator.throw (<anonymous>)
    at rejected (/home/kay/checkpoint/image-service/node_modules/serverless-domain-manager/dist/src/index.js:6:65)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
```

**Domain Manager Configuration**

```typescript
      customDomain: {
            domainName: "image-service.staging.geeiq.com",
            basePath: "/",
            certificateName: "*.staging.geeiq.com",
            stage: "${opt:stage}",
            createRoute53Record: true,
        },
```

**Versions**
- Domain Manager version(s): ^6.0.3
- Node/npm version: 16.13/8.1.3
- Serverless Version: 3.21
- Lambda Code: typescript

**Possible Solution**
<!--- Only if you have suggestions on a fix for the bug -->

**Additional context/Screenshots**
Add any other context about the problem here. If applicable, add screenshots to help explain.


Pull request description:
AT-11223: Update ACM get certificate error for the Edge endpoint type
https://amplify-education.atlassian.net/browse/AT-11223

<!--- Information about referencing Github Issues: https://help.github.com/articles/basic-writing-and-formatting-syntax/#referencing-issues-and-pull-requests --->
Fixes #509

**Description of Issue Fixed**
Updated ACM get certificate error message for the `EDGE` endpoint type

**Changes proposed in this pull request**:

* Error message update

<!--- Please remember to allow edits from maintainers: https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/allowing-changes-to-a-pull-request-branch-created-from-a-fork --->


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 46b0b65..35ccbfa 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file.
 The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
 and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
 
+## [7.3.6] - 2023-02-13
+
+### Changed
+- Updated ACM get certificate error message for the endpoint type `EDGE`. More info https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-edge-optimized-custom-domain-name.html
+
 ## [7.3.5] - 2023-02-06
 
 ### Fixed 
diff --git a/README.md b/README.md
index 5ff006c..7d2d3fb 100644
--- a/README.md
+++ b/README.md
@@ -256,7 +256,8 @@ NOTE: Always test this process in a lower level staging or development environme
 * (1/17/2018) The `create_domain` command provided by this plugin does not currently update an existing Custom Domain's configuration. Instead, it only supports updating the Route 53 record pointing to the Custom Domain. For example, one must delete and recreate a Custom Domain to migrate it from regional to edge or vice versa, or to modify the certificate.
 * (8/22/2018) Creating a custom domain creates a CloudFront Distribution behind the scenes for fronting your API Gateway. This CloudFront Distribution is managed by AWS and cannot be viewed/managed by you. This is not a bug, but a quirk of how the Custom Domain feature works in API Gateway.
 * (2/12/2019) Users who upgraded from 2.x.x to version 3.0.4 (now unpublished) and then reverted back to 2.x.x will be unable to deploy because of a bug that will be fixed in 3.1.0. The workaround is to delete the basepath mapping manually, which will let them successfully revert back to 2.x.x.
-* (1/20/2022) Using `route53Profile` option requires having hosted zone for the domain in this profile and ACM certificate in the main profile (where functions are deployed).  
+* (1/20/2022) Using `route53Profile` option requires having hosted zone for the domain in this profile and ACM certificate in the main profile (where functions are deployed).
+* (2/13/2024) ACM certificate must exist in the `us-east-1` for the `EDGE` endpoint type. https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-edge-optimized-custom-domain-name.html
 
 # Responsible Disclosure
 If you have any security issue to report, contact project maintainers privately.
diff --git a/package.json b/package.json
index 111ee79..041cb99 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "serverless-domain-manager",
-  "version": "7.3.5",
+  "version": "7.3.6",
   "engines": {
     "node": ">=14"
   },
diff --git a/src/aws/acm-wrapper.ts b/src/aws/acm-wrapper.ts
index 2ec21b6..7050912 100644
--- a/src/aws/acm-wrapper.ts
+++ b/src/aws/acm-wrapper.ts
@@ -55,7 +55,12 @@ class ACMWrapper {
       throw Error(`Could not search certificates in Certificate Manager.\n${err.message}`);
     }
     if (certificateArn == null) {
-      throw Error(`Could not find an in-date certificate for '${certificateName}'.`);
+      let errorMessage = `Could not find an in-date certificate for '${certificateName}'.`;
+      if (domain.endpointType === Globals.endpointTypes.edge) {
+        errorMessage += ` The endpoint type '${Globals.endpointTypes.edge}' is used. ` +
+          `Make sure the needed ACM certificate exists in the '${Globals.defaultRegion}' region.`;
+      }
+      throw Error(errorMessage);
     }
     return certificateArn;
   }
diff --git a/src/globals.ts b/src/globals.ts
index baded5f..880ef22 100644
--- a/src/globals.ts
+++ b/src/globals.ts
@@ -76,7 +76,7 @@ export default class Globals {
       return await fromIni({ profile })();
     }
 
-    public static getRetryStrategy (attempts: number = 3, delay: number = 3000, backoff: number = 500) {
+    public static getRetryStrategy (attempts: number = 5, delay: number = 3000, backoff: number = 500) {
       return new ConfiguredRetryStrategy(
         attempts, // max attempts.
         // This example sets the backoff at 500ms plus 3s per attempt.


Test patch:
diff --git a/test/unit-tests/aws/acm-wrapper.test.ts b/test/unit-tests/aws/acm-wrapper.test.ts
index 18b8ab4..704e63b 100644
--- a/test/unit-tests/aws/acm-wrapper.test.ts
+++ b/test/unit-tests/aws/acm-wrapper.test.ts
@@ -170,4 +170,23 @@ describe("ACM Wrapper checks", () => {
     }
     expect(errored).to.equal(true);
   });
+
+  it("getCertArn failure for Edge", async () => {
+    const ACMCMock = mockClient(ACMClient);
+    ACMCMock.on(ListCertificatesCommand).resolves({ CertificateSummaryList: [] });
+
+    const acmWrapper = new ACMWrapper(null, Globals.endpointTypes.edge);
+    const dc = new DomainConfig(getDomainConfig({ domainName: "test_domain" }));
+
+    let errored = false;
+    try {
+      await acmWrapper.getCertArn(dc);
+    } catch (err) {
+      errored = true;
+      expect(err.message).to.contains(
+        `Make sure the needed ACM certificate exists in the '${Globals.defaultRegion}' region`
+      );
+    }
+    expect(errored).to.equal(true);
+  });
 });