serverless-heaven / serverless-aws-alias

Alias support for Serverless 1.x
MIT License
189 stars 68 forks source link

Authorizer name must be unique. Authorizer already exists in this RestApi #168

Open clethrill opened 5 years ago

clethrill commented 5 years ago

I have a serverless.yml that looks like

service: myapp-${opt:stage, self:provider.stage}

custom:
  serverless-offline:
    port: 3001
  myStage: ${opt:stage, self:provider.stage}
  myEnvironment: 
    ENV_VAR:
      DEV: "dev value" 
      PROD: "prod value"
  output:
    file: ../controller/constants/application-aws.json # toml, yaml, yml, and json format is available

plugins:
  - serverless-offline
  - serverless-plugin-typescript
  - serverless-aws-alias
  - serverless-stack-output

provider:
  name: aws
  runtime: nodejs10.x
  stage: DEV
  region: ap-southeast-1
  profile: myprofile
  environment: 
    ENV_VAR: ${self:custom.myEnvironment.ENV_VAR.${self:custom.myStage}}

resources: 
  - ${file(../resources/cognito-resource.yml)}

functions:
  hello:
    description: 'Says Hello'
    handler: functions/handler.hello
    events:
      - http:
          method: GET
          path: /hello
          authorizer:
            type: COGNITO_USER_POOLS 
            authorizerId:
              Ref: ApiGatewayAuthorizer
          cors:
            origin: 
              - '*'
            headers:
              - Content-Type
              - X-Amz-Date
              - Authorization
              - X-Api-Key
              - X-Amz-Security-Token
              - X-Amz-User-Agent
            allowCredentials: true

cognito-resource.yml looks like

Resources:
  CognitoUserPool:
    Type: AWS::Cognito::UserPool
    Properties:
      # Generate a name based on the stage
      UserPoolName: cognito-userpool-${self:custom.myStage}
      # Set email as an alias
      UsernameAttributes:
        - email
      Policies:
        PasswordPolicy:
          MinimumLength: 6
          RequireLowercase: False
          RequireNumbers: False
          RequireSymbols: False
          RequireUppercase: False

  CognitoUserPoolClient:
    Type: AWS::Cognito::UserPoolClient
    Properties:
      # Generate an app client name based on the stage
      ClientName: cognito-userpoolclient-${self:custom.myStage}
      UserPoolId:
        Ref: CognitoUserPool
      GenerateSecret: false

  ApiGatewayAuthorizer:
    DependsOn:
      - ApiGatewayRestApi
    Type: AWS::ApiGateway::Authorizer
    Properties:
      Name: cognito-authorizer
      IdentitySource: method.request.header.Authorization
      RestApiId:
        Ref: ApiGatewayRestApi
      Type: COGNITO_USER_POOLS
      ProviderARNs:
        - Fn::GetAtt: [CognitoUserPool, Arn]

# Print out the Id of the User Pool that is created
Outputs:
  UserPoolId:
    Value:
      Ref: CognitoUserPool
  UserPoolClientId:
    Value:
      Ref: CognitoUserPoolClient
  CognitoUserPoolArn:
    Value:
      Fn::GetAtt:
        - CognitoUserPool
        - Arn
    Export:
      Name: CognitoUserPoolArn-${self:custom.myStage}

and when I run sls deploy --alias my_name I get the error:

An error occurred: ApiGatewayAuthorizermy_name - Authorizer name must be unique. Authorizer cognito-authorizer already exists in this RestApi. (Service: AmazonApiGateway; Status Code: 400; Error Code: BadRequestException; Request ID: 79c6f96b-855e-44d1-8e96-3862bc3577bf).

clethrill commented 5 years ago

@HyperBrain Is my set up correct or is this an issue with serverless-aws-alias?

Enase commented 5 years ago

All the resources must be unique per stage/alias. As I can see, you've already deployed the main stage with sls deploy or sls deploy --stage your-stage, so that you have created all the resources and now you cannot deploy the copies. Try to create unique names like:

Resources:
    ApiGatewayAuthorizer${stage}${alias}:
    ...
    CognitoUserPool${stage}${alias}:

As I remember, variables are not supported for Resources, so you can try serverless-plugin-ifelse plugin.