Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug: Invalid CORS origin header sent with sam local start-api #7848

Open
cwinters8 opened this issue Jan 24, 2025 · 3 comments
Open

Bug: Invalid CORS origin header sent with sam local start-api #7848

cwinters8 opened this issue Jan 24, 2025 · 3 comments
Labels
stage/needs-investigation Requires a deeper investigation

Comments

@cwinters8
Copy link

Description:

When a browser makes a request to a service I have running locally using sam local start-api and I have the Cors property configured for the AWS::Serverless::Api resource, the local service sends the exact value of Cors.AllowOrigin (which is required to be in this "'http://localhost:3000, https://someservice.dev'" format) as the Access-Control-Allow-Origin header, which the browser (Chrome in this case) reports as an invalid value:

Access to fetch at 'http://127.0.0.1:8080/sentry' from origin 'http://localhost:3000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values 'https://*.someservice.dev, https://someservice.com', but only one is allowed. Have the server send the header with a valid value, or, if an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

My function code returns these exact headers with every response:

"headers": {
    "Access-Control-Allow-Origin": "*",
    "Access-Control-Allow-Headers": "*",
    "Access-Control-Allow-Methods": "POST",
    "Content-Type": "application/json",
}

which are being used with the deployed service, because my live service returns "Access-Control-Allow-Origin": "*" instead of the multi-value one.

Steps to reproduce:

SAM template:

AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Parameters:
  Env:
    Description: Environment name
    Type: String
    AllowedValues:
      - dev
      - staging
      - prod
    Default: dev
  Name:
    Description: Resource name, used as a prefix for most resources.
    Type: String
    Default: sentry-tunnel
  AllowedOrigin:
    Description: CORS allowed origin(s)
    Type: String
    Default: "https://*.someservice.dev, https://someservice.com"

Mappings:
  Domain:
    dev:
      Name: metrics.dev.someservice.dev
      HostedZone: someservice.dev.
    staging:
      Name: metrics.staging.someservice.dev
      HostedZone: staging.someservice.dev.
    prod:
      Name: metrics.someservice.com
      HostedZone: someservice.com.

Resources:
  Api:
    Type: AWS::Serverless::Api
    Properties:
      Name: !Ref Name
      StageName: release
      BinaryMediaTypes:
        - "*~1*"
      Cors:
        AllowOrigin: !Sub "'${AllowedOrigin}'"
        AllowHeaders: "'*'"
        AllowMethods: "'POST'"
      Domain:
        BasePath: /
        DomainName:
          Fn::FindInMap:
            - Domain
            - !Ref Env
            - Name
        CertificateArn: "{{resolve:ssm:/someservice/metrics/certificate-arn}}"
        Route53:
          HostedZoneName:
            Fn::FindInMap:
              - Domain
              - !Ref Env
              - HostedZone

  SentryTunnelFunc:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub "${Name}-handler"
      CodeUri: ./
      Handler: lambda.handler
      Runtime: python3.12
      Architectures:
        - x86_64
      Role: !GetAtt LambdaRole.Arn
      Events:
        PostEvent:
          Type: Api
          Properties:
            RestApiId: !Ref Api
            Path: /sentry
            Method: POST
      Environment:
        Variables:
          ENV: !Ref Env

  LambdaRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub "${Name}-handler"
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

Python function that returns this http response:

{
    "statusCode": status_code,
    "headers": {
        "Access-Control-Allow-Origin": "*",
        "Access-Control-Allow-Headers": "*",
        "Access-Control-Allow-Methods": "POST",
        "Content-Type": "application/json",
    },
    "body": json.dumps(body),
}

Build and run:

sam build --parallel
sam local start-api --port 8080

Make an appropriate request to http://127.0.0.1:8080/sentry from the browser.

Observed result:

The request results in status 200, but the browser console shows the errors:

Access to fetch at 'http://127.0.0.1:8080/sentry' from origin 'http://localhost:3000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values 'https://*.someservice.dev, https://someservice.com', but only one is allowed. Have the server send the header with a valid value, or, if an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

POST http://127.0.0.1:8080/sentry net::ERR_FAILED 200 (OK)

Expected result:

The Access-Control-Allow-Origin header should reflect the same as the live service ("Access-Control-Allow-Origin": "*" in this case), which would prevent the errors in the browser.

Additional environment details (Ex: Windows, Mac, Amazon Linux etc)

Output of sam --info:

{
  "version": "1.132.0",
  "system": {
    "python": "3.11.10",
    "os": "macOS-15.2-x86_64-i386-64bit"
  },
  "additional_dependencies": {
    "docker_engine": "27.4.0",
    "aws_cdk": "Not available",
    "terraform": "1.10.2"
  },
  "available_beta_feature_env_vars": [
    "SAM_CLI_BETA_FEATURES",
    "SAM_CLI_BETA_BUILD_PERFORMANCE",
    "SAM_CLI_BETA_TERRAFORM_SUPPORT",
    "SAM_CLI_BETA_RUST_CARGO_LAMBDA"
  ]
}
@cwinters8 cwinters8 added the stage/needs-triage Automatically applied to new issues and PRs, indicating they haven't been looked at. label Jan 24, 2025
@roger-zhangg
Copy link
Member

Thanks for reporting, just to confirm did you see CORS Property AllowOrigins was not fully resolved. Will proceed as if the Property was not defined. in the log? It seems CommaDelimitedList is not supported in sam local currently.

If this is the case, maybe we can track this as a feature request

@roger-zhangg roger-zhangg added blocked/more-info-needed More info is needed from the requester. If no response in 14 days, it will become stale. stage/needs-investigation Requires a deeper investigation and removed stage/needs-triage Automatically applied to new issues and PRs, indicating they haven't been looked at. labels Jan 24, 2025
@cwinters8
Copy link
Author

@roger-zhangg I'm not seeing the CORS Property AllowOrigins was not fully resolved warning when running sam build or sam local start-api. I would suspect if it was treating the property as undefined the origin header probably wouldn't get sent with the response?

@roger-zhangg
Copy link
Member

Thanks for the context, will try to reproduce

@roger-zhangg roger-zhangg removed the blocked/more-info-needed More info is needed from the requester. If no response in 14 days, it will become stale. label Jan 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stage/needs-investigation Requires a deeper investigation
Projects
None yet
Development

No branches or pull requests

2 participants