Repository: serverless/serverless (JavaScript)
Date: 2021-01-25 14:27:27+00:00
Task type: Bug Fix

Issue:
CloudFront CachePolicy is not uniquely named
According to [CloudFomation document](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-cachepolicy-cachepolicyconfig.html), CachePolicy must have _unique_ name.

However, serverless generates CachePolicy name by key of `provider.cloudFront.cachePolicies` simply.
It makes deployment to fail when deploying to multiple stage.

<details>
<summary><code>serverless.yml</code></summary>

```yaml
service: cloudfront-cache-policy-test

provider:
  name: aws
  region: us-east-1
  runtime: nodejs12.x
  lambdaHashingVersion: 20201221
  cloudFront:
    cachePolicies:
      myCachePolicy:
        MinTTL: 0
        MaxTTL: 86000
        DefaultTTL: 3600
        ParametersInCacheKeyAndForwardedToOrigin:
          EnableAcceptEncodingGzip: true
          EnableAcceptEncodingBrotli: true
          CookiesConfig:
            CookieBehavior: none
          HeadersConfig:
            HeaderBehavior: none
          QueryStringsConfig:
            QueryStringBehavior: none

functions:
  lambdaAtEdge:
    handler: index.handler
    events:
      - cloudFront:
          eventType: viewer-request
          origin:
            DomainName: mybucket.s3.amazonaws.com
            S3OriginConfig:
              OriginAccessIdentity: origin-access-identity/cloudfront/XXXXXXXXXXXXXX
          cachePolicy:
            name: myCachePolicy
```

</details>

<details>
<summary><b><code>sls deploy</code> output</b></summary>

```
$ sls deploy
Serverless: Configuration warning at 'functions.lambdaAtEdge.events[0].cloudFront.origin': should have required property 'Id'
Serverless:  
Serverless: Learn more about configuration validation here: http://slss.io/configuration-validation
Serverless:  
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
........
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service cloudfront-cache-policy-test.zip file to S3 (257 B)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
........................
Serverless: Stack update finished...
Service Information
service: cloudfront-cache-policy-test
stage: dev
region: us-east-1
stack: cloudfront-cache-policy-test-dev
resources: 9
api keys:
  None
endpoints:
  CloudFront - xxxxxxxxxxxxxx.cloudfront.net
functions:
  lambdaAtEdge: cloudfront-cache-policy-test-dev-lambdaAtEdge
layers:
  None
```

```
$ npx sls deploy --stage prd
Serverless: Configuration warning at 'functions.lambdaAtEdge.events[0].cloudFront.origin': should have required property 'Id'
Serverless:  
Serverless: Learn more about configuration validation here: http://slss.io/configuration-validation
Serverless:  
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
........
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service cloudfront-cache-policy-test.zip file to S3 (257 B)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
...............
Serverless: Operation failed!
Serverless: View the full error output: https://us-east-1.console.aws.amazon.com/cloudformation/home?region=us-east-1#/stack/detail?stackId=arn%3Aaws%3Acloudformation%3Aus-east-1%XXXXXXXXXXXXXX%3Astack%2Fcloudfront-cache-policy-test-prd%2Fxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

  Serverless Error ---------------------------------------

  An error occurred: CloudFrontCachePolicyMyCachePolicy - Internal error reported from downstream service during operation 'AWS::CloudFront::CachePolicy'..

  Get Support --------------------------------------------
     Docs:          docs.serverless.com
     Bugs:          github.com/serverless/serverless/issues
     Issues:        forum.serverless.com

  Your Environment Information ---------------------------
     Operating System:          win32
     Node Version:              12.15.0
     Framework Version:         2.20.1 (local)
     Plugin Version:            4.4.2
     SDK Version:               2.3.2
     Components Version:        3.5.1
```

</details>

<b>Installed version</b>

```
Framework Core: 2.20.1 (local)
Plugin: 4.4.2
SDK: 2.3.2
Components: 3.5.1
```



Issue discussion:
Can confirm, I was just running into the same issue – I seem to run into all the issues right now :D

Solution patch:
diff --git a/docs/providers/aws/events/cloudfront.md b/docs/providers/aws/events/cloudfront.md
index 637b782c847..29e1fe521bb 100644
--- a/docs/providers/aws/events/cloudfront.md
+++ b/docs/providers/aws/events/cloudfront.md
@@ -222,6 +222,8 @@ functions:
             name: myCachePolicy
 ```
 
+This configuration will create a Cache Policy named `servicename-stage-myCachePolicy`.
+
 You can reference [AWS Managed Policies](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-managed-cache-policies.html#managed-cache-policies-list) using an `id` property instead of `name`
 
 ```yml
diff --git a/lib/plugins/aws/lib/naming.js b/lib/plugins/aws/lib/naming.js
index 535a89597ea..7221b86bc61 100644
--- a/lib/plugins/aws/lib/naming.js
+++ b/lib/plugins/aws/lib/naming.js
@@ -605,6 +605,11 @@ module.exports = {
   getCloudFrontCachePolicyLogicalId(cachePolicyName) {
     return `CloudFrontCachePolicy${this.getNormalizedFunctionName(cachePolicyName)}`;
   },
+  getCloudFrontCachePolicyName(cachePolicyName) {
+    const serviceName = this.provider.serverless.service.getServiceName();
+    const stage = this.provider.getStage();
+    return `${serviceName}-${stage}-${cachePolicyName}`;
+  },
 
   // HTTP API
   getHttpApiName() {
diff --git a/lib/plugins/aws/package/compile/events/cloudFront.js b/lib/plugins/aws/package/compile/events/cloudFront.js
index 5cd8b7bb46a..55473f9825f 100644
--- a/lib/plugins/aws/package/compile/events/cloudFront.js
+++ b/lib/plugins/aws/package/compile/events/cloudFront.js
@@ -296,7 +296,7 @@ class AwsCompileCloudFrontEvents {
             Properties: {
               CachePolicyConfig: {
                 ...cachePolicyConfig,
-                Name: name,
+                Name: this.provider.naming.getCloudFrontCachePolicyName(name),
               },
             },
           },


Test patch:
diff --git a/test/unit/lib/plugins/aws/package/compile/events/cloudFront.test.js b/test/unit/lib/plugins/aws/package/compile/events/cloudFront.test.js
index 046a3f0e986..e112057d369 100644
--- a/test/unit/lib/plugins/aws/package/compile/events/cloudFront.test.js
+++ b/test/unit/lib/plugins/aws/package/compile/events/cloudFront.test.js
@@ -2078,7 +2078,7 @@ describe('lib/plugins/aws/package/compile/events/cloudFront/index.new.test.js',
       const cachePolicyConfigProperties =
         cfResources[cachePolicyLogicalId].Properties.CachePolicyConfig;
       expect(cachePolicyConfigProperties).to.deep.eq({
-        Name: cachePolicyName,
+        Name: `${serviceName}-${stage}-${cachePolicyName}`,
         ...cachePolicyConfig,
       });
     });