serverless / serverless

⚡ Serverless Framework – Effortlessly build apps that auto-scale, incur zero costs when idle, and require minimal maintenance using AWS Lambda and other managed cloud services.
https://serverless.com
MIT License
46.46k stars 5.72k forks source link

Default CloudFront CachePolicyId clashes with named cache policies #11378

Open antoniocaiazzo opened 2 years ago

antoniocaiazzo commented 2 years ago

Are you certain it's a bug?

Is the issue caused by a plugin?

Are you using the latest v3 release?

Is there an existing issue for this?

Issue description

I've been getting an error while deploying a service with CloudFront configuration:

`CREATE_FAILED: CloudFrontDistribution (AWS::CloudFront::Distribution) Properties validation failed for resource CloudFrontDistribution with message:

/DistributionConfig/DefaultCacheBehavior/CachePolicyId: expected type: String, found: JSONObject`

Digging into the code the problem seems to arise when some functions use cachePolicy with a name from the ones configured under provider.cloudFront.cachePolicies and others don't. See service configuration for an example.

This is the problematic part of the generated CloudFront template: "CachePolicyId": { "0": "6", "1": "5", "2": "8", "3": "3", "4": "2", "5": "7", "6": "e", "7": "a", "8": "-", "9": "f", "10": "8", "11": "9", "12": "d", "13": "-", "14": "4", "15": "f", "16": "a", "17": "b", "18": "-", "19": "a", "20": "6", "21": "3", "22": "d", "23": "-", "24": "7", "25": "e", "26": "8", "27": "8", "28": "6", "29": "3", "30": "9", "31": "e", "32": "5", "33": "8", "34": "f", "35": "6", "Ref": "CloudFrontCachePolicyDefaultCachePolicy" },

As you can see from the serverless configuration, the headers function doesn't use a cachePolicy, so it gets assigned the default CachePolicyId: '658327ea-f89d-4fab-a63d-7e88639e58f6'. After this step, the behavior is then merged into an existing one, which already has a CachePolicyId: { "Ref": "CloudFrontCachePolicyDefaultCachePolicy" } property, causing the extendDeep() function to try and merge a string with an object.

I'm not sure of the right way to fix this, so I've opened a new issue (didn't find a similar one already opened). In my case I had forgotten to add the cachePolicy name to one of my functions, but I imagine the default cache policy id it's a feature that's supposed to work for the people of need it.

Service configuration (serverless.yml) content

frameworkVersion: '>=3.0.0 <4.0.0'
configValidationMode: off

service: ziggy-admin-edge

provider:
  name: aws
  stage: dev
  region: eu-west-1
  runtime: python3.9
  deploymentBucket:
    name: lambda-${self:config.stage}-edge-reservoir
    blockPublicAccess: true
  cloudFront:
    cachePolicies:
      defaultCachePolicy:
        MinTTL: 0
        MaxTTL: ${self:custom.cf.ttl.max.${self:config.stage}}
        DefaultTTL: ${self:custom.cf.ttl.default.${self:config.stage}}
        ParametersInCacheKeyAndForwardedToOrigin: ${self:custom.cf.forward}
      disabledCachePolicy:
        MinTTL: 0
        MaxTTL: 1
        DefaultTTL: 0
        ParametersInCacheKeyAndForwardedToOrigin: ${self:custom.cf.forward}

functions:
  authorizer:
    handler: authorizer.handler
    module: authorizer
    timeout: 1
    events:
      - cloudFront:
          eventType: viewer-request
          isDefaultOrigin: true
          origin: ${self:custom.origins.ngApp}
          cachePolicy:
            name: defaultCachePolicy
          behavior: ${self:custom.behaviours.readOnly}

  headers:
    handler: headers.handler
    module: headers
    events:
      - cloudFront:
          eventType: origin-response
          isDefaultOrigin: true
          origin: ${self:custom.origins.ngApp}
#          cachePolicy:
#            name: defaultCachePolicy
          behavior: ${self:custom.behaviours.readOnly}

custom:
  appBucketName: ${file(../.sls-outputs/${self:config.stage}-admin.yml):NgAdminPortalBucketName}

  origins:
    ngApp:
      DomainName: ${self:custom.appBucketName}.s3.amazonaws.com
      OriginPath: ${ssm:/ziggy-${self:config.stage}/ng-apps/buckets-path}
      S3OriginConfig:
        OriginAccessIdentity: ${self:custom.cf.oai}

  behaviours:
    readOnly:
      ViewerProtocolPolicy: redirect-to-https
      Compress: true
      AllowedMethods:
        - GET
        - HEAD
        - OPTIONS
      CachedMethods:
        - GET
        - HEAD

  cf:
    oai:
      Fn::Join: ['', ['origin-access-identity/cloudfront/', Ref: CloudFrontAdminOAI]]
    ttl:
      default:
        dev: 3600 # 1 hour
        staging:  3600  # 1 hour
        prod: 86400   # 1 day
      max:
        dev: 86400  # 1 day
        staging: 86400  # 1 day
        prod: 2592000   # 1 month
    forward:
      CookiesConfig:
        CookieBehavior: whitelist
        Cookies:
          - Authorization
          - Redirect
      EnableAcceptEncodingBrotli: true
      EnableAcceptEncodingGzip: true
      HeadersConfig:
        HeaderBehavior: whitelist
        Headers:
          - X-Forwarded-Origin
          - X-Forwarded-User
          - X-Secret
      QueryStringsConfig:
        QueryStringBehavior: all

resources:
  Resources:
    CloudFrontDistribution:
      Type: AWS::CloudFront::Distribution
      Properties:
        DistributionConfig:
          Enabled: true
          DefaultRootObject: index.html
          PriceClass: PriceClass_100
          IPV6Enabled: true
          HttpVersion: http2
          Aliases:
            - admin${self:config.domainExtension.${self:config.stage}}.${self:config.domain}
          ViewerCertificate:
            AcmCertificateArn: ${self:custom.acm.${self:config.stage}}
            MinimumProtocolVersion: TLSv1.2_2018
            SslSupportMethod: sni-only
          CustomErrorResponses:
            - ErrorCachingMinTTL: 0
              ErrorCode: 400
            - ErrorCachingMinTTL: 0
              ErrorCode: 403
            - ErrorCachingMinTTL: 0
              ErrorCode: 404
            - ErrorCachingMinTTL: 0
              ErrorCode: 405
            - ErrorCachingMinTTL: 0
              ErrorCode: 414
            - ErrorCachingMinTTL: 0
              ErrorCode: 416
            - ErrorCachingMinTTL: 0
              ErrorCode: 500
            - ErrorCachingMinTTL: 0
              ErrorCode: 501
            - ErrorCachingMinTTL: 0
              ErrorCode: 502
            - ErrorCachingMinTTL: 0
              ErrorCode: 503
            - ErrorCachingMinTTL: 0
              ErrorCode: 504

Command name and used flags

sls --stage staging deploy

Command output

Deploying ziggy-admin-edge to stage dev (us-east-1)

✖ Stack ziggy-admin-edge-dev failed to deploy (75s)
Environment: linux, node 18.8.0, framework 3.22.0 (local) 3.22.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:
CREATE_FAILED: CloudFrontDistribution (AWS::CloudFront::Distribution)
Properties validation failed for resource CloudFrontDistribution with message:
#/DistributionConfig/DefaultCacheBehavior/CachePolicyId: expected type: String, found: JSONObject

Environment information

Framework Core: 3.22.0
Plugin: 6.2.2
SDK: 4.3.2
medikoo commented 2 years ago

Update configValidationMode: off to configValidationMode: error, and see what happens then

antoniocaiazzo commented 2 years ago

Same error. It happens during the creation of the CloudFormation stack on AWS, the serverless.yml schema checks all passes.

On Wed, 7 Sept 2022 at 16:14, Mariusz Nowak @.***> wrote:

Assigned #11378 https://github.com/serverless/serverless/issues/11378 to @antoniocaiazzo https://github.com/antoniocaiazzo.

— Reply to this email directly, view it on GitHub https://github.com/serverless/serverless/issues/11378#event-7339329132, or unsubscribe https://github.com/notifications/unsubscribe-auth/AANGMYUNE5JC5I7ZBJ6IQOTV5CPKZANCNFSM6AAAAAAQGZX4KU . You are receiving this because you were assigned.Message ID: @.***>

--

Antonio Caiazzo Senior Fullstack Software Engineer

+44 78030 99033 LinkedIn http://www.linkedin.com/in/antoniocaiazzo