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

Fn::If intrinsic function inside Auth property of "AWS::Serverless::Api" #1859

Closed
maslakov opened this issue Dec 11, 2020 · 14 comments
Closed
Labels
area/intrinsics Ref, If, Sub, GetAtt, ... stage/pm-review Waiting for review by our Product Manager, please don't work on this yet type/feature

Comments

@maslakov
Copy link

maslakov commented Dec 11, 2020

Description:

In the AWS::Serverless::Api resource I want to specify optional authorizer. For this purpose I try to use Conditions and "!If" intrinsic function. SAM doees not consider such a template as a valid one. I tried already all combinations with "!If" and "Fn::If" and indentation - it does not work.

Steps to reproduce the issue:

  1. Create new template with the following content
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  Sample SAM Template for test

Parameters:
  ExternalAuthorizerArn:
    Type: String

Conditions:
  ExternalAuthorizer: !Not [!Equals [ !Ref ExternalAuthorizerArn, '' ]]

Resources:

  ApiGatewayApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: Test
      Auth:
        ApiKeyRequired: false
        Fn::If:
        - ExternalAuthorizer
        -
          Authorizers:
            ApiKeyAuth:
              FunctionPayloadType: TOKEN
              FunctionArn: !Ref ExternalAuthorizerArn
              Identity:
                Header: x-api-key
                ReauthorizeEvery: 300
        - !Ref "AWS::NoValue"
  1. try to deploy or just validate it:

sam validate

Observed result:

Template provided at '/Users/xxx/tmp/test/template.yaml' was invalid SAM Template.
Error: [InvalidResourceException('ApiGatewayApi', "Invalid value for 'Auth' property")] ('ApiGatewayApi', "Invalid value for 'Auth' property")

Expected result:

Template is considered as valid and can be deployed with optional parameter ExternalAuthorizerArn set to either empty string or to the specific value.

@mndeveci mndeveci added type/feature stage/pm-review Waiting for review by our Product Manager, please don't work on this yet labels Dec 21, 2020
@tjcarrel
Copy link

tjcarrel commented Feb 18, 2021

Would love to see this added. Currently trying to configure an optional Authorizer for my prod stack but not my dev and unable to.

@wchengru wchengru added the area/intrinsics Ref, If, Sub, GetAtt, ... label Mar 10, 2021
@ngalchemist
Copy link

This also seems to relate to my issue with the Domain property on the AWS::Serverless::Api resource. My template looks like below.

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Test template
Parameters:
  AddApiMapping:
    Default: n
    Type: String
    AllowedValues: [y,n]
    Description: 'y/N'
Conditions:
  AddApiMappingCondition:
    !Or [!Equals ['y', !Ref AddApiMapping], !Equals ['Y', !Ref AddApiMapping]]
Resources:
  ApiGateway:
    Type: AWS::Serverless::Api
    Properties:
      Name: TestApi
      ..
      Domain:
        !If
        - AddApiMappingCondition
        - CertificateArn: !Ref CertificateArn
          DomainName: !Ref ApiMappingDomainName
        - !Ref "AWS::NoValue"    

Running sam validate yields the following:

Error: [InvalidResourceException('ApiGateway', 'Custom Domains only works if both DomainName and CertificateArn are provided.')] ('ApiGateway', 'Custom Domains only works if both DomainName and CertificateArn are provided.')

@piersf
Copy link

piersf commented Apr 23, 2021

Any updates on this?

We ran into this issue as well. We're trying to deploy an API Gateway in the Beijing region where Cognito User Pools are not supported, and we're trying to add a condition in the Auth property that when the region is cn-north-1 the DefaultAuthorizer and Authorizers properties is not included:

Conditions: 
  IsStandardPartition: !Equals [ !Ref AWS::Partition, "aws" ]

AccountManagementApi:
  Type: "AWS::Serverless::Api"
  Properties:
    Name: !Sub "${environment}-${ApiName}-${ApiGatewayConvention}"
    StageName: !Ref ApiStageName
    Auth: 
      !If
        - IsStandardPartition
        -
          ApiKeyRequired: true
          DefaultAuthorizer: AccountManagementCognitoAuthorizer
          UsagePlan:
            UsagePlanName: !Sub "${environment}-${ApiName}-${ApiGatewayConvention}-usage-plan"
            CreateUsagePlan: PER_API
            Quota:
              Limit: !Ref ApiGatewayRequestQuota
              Period: DAY
            Throttle:
              BurstLimit: !Ref ApiGatewayRequestBurstLimit
              RateLimit: !Ref ApiGatewayRequestRateLimit
          Authorizers:
            AccountManagementCognitoAuthorizer:
              UserPoolArn:
                Fn::ImportValue: !Sub "stack-${environment}-AccountManagementCognitoUserPoolArn"
              AuthorizationScopes:
                - !Sub "${environment}-account-management-api-cognito-user-pool-resource-server/aws.account.management.create_account"
          ResourcePolicy:
            IpRangeWhitelist: !Ref AllowedIpsWhitelist
        -
          ApiKeyRequired: true
          UsagePlan:
            UsagePlanName: !Sub "${environment}-${ApiName}-${ApiGatewayConvention}-usage-plan"
            CreateUsagePlan: PER_API
            Quota:
              Limit: !Ref ApiGatewayRequestQuota
              Period: DAY
            Throttle:
              BurstLimit: !Ref ApiGatewayRequestBurstLimit
              RateLimit: !Ref ApiGatewayRequestRateLimit
          ResourcePolicy:
            IpRangeWhitelist: !Ref AllowedIpsWhitelist

But the above fails with the following error:

Waiter ChangeSetCreateComplete failed: Waiter encountered a terminal failure state Status: FAILED. Reason: Transform AWS::Serverless-2016-10-31 failed with: Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [AccountManagementApi] is invalid. Invalid value for 'Auth' property

The related line in the code where it fails is

raise InvalidResourceException(self.logical_id, "Invalid value for 'Auth' property")

@dkwgit
Copy link

dkwgit commented May 9, 2021

Having same issue. Cannot make a resource policy conditional.

@singhsoldier13
Copy link

Having the same issue. Is there a workaround?

@matthewhembree
Copy link

Off topic:
@ngalchemist @m-chandler This workaround will solve your issue with conditional domain:

Parameters:
  CustomDomainName:
    Type: String
    Description: Domain name for api (e.g. my_service.<environment>.example.com)
    Default: 'false'
  ZoneId:
    Type: AWS::SSM::Parameter::Value<String>
    Description: Route53 zone ID from SSM Parameter Store.
    Default: external-route53-zone-id

Conditions:
  ApiCustomDomain: !Not
    - !Equals
      - 'false'
      - !Ref CustomDomainName

Resources:
  ApiSSLCertificate:
    Type: AWS::CertificateManager::Certificate
    Properties:
      CertificateTransparencyLoggingPreference: DISABLED
      DomainName: !Ref CustomDomainName
      ValidationMethod: DNS
      DomainValidationOptions:
        DomainName: !Ref CustomDomainName
        HostedZoneId: !Ref ZoneId
    Condition: ApiCustomDomain
  ApiCustomDomain:
    Type: AWS::ApiGateway::DomainName
    Properties:
      DomainName: !Ref CustomDomainName
      EndpointConfiguration:
        Types:
          - REGIONAL
      RegionalCertificateArn: !Ref ApiSSLCertificate
      SecurityPolicy: TLS_1_2
    Condition: ApiCustomDomain
  ApiCustomDomainRecord:
    Type: AWS::Route53::RecordSet
    Properties:
      HostedZoneId: !Ref ZoneId
      Name: !Ref CustomDomainName
      ResourceRecords:
        - !GetAtt ApiCustomDomain.RegionalDomainName
      TTL: 900
      Type: CNAME
    Condition: ApiCustomDomain
  ApiCustomDomainMapping:
    Type: AWS::ApiGateway::BasePathMapping
    Properties:
      DomainName: !Ref ApiCustomDomain
      RestApiId: !Ref Api
      Stage: !Ref Api.Stage  # This is a resource generated when the stack is deployed.
    Condition: ApiCustomDomain
  Api:
    Type: AWS::Serverless::Api
    Properties:
      ... # Don't specify `Domain:`. It's handled with `ApiCustomDomainMapping`.
    

@ghost
Copy link

ghost commented Apr 26, 2022

When will this issue be addressed?
I cannot specify different Auth.ResourcePolicy for API gateway depending on different environments.
As a workaround, I had to deploy different API gateway for different environments using Condition.

Then, due to the issue that AWS::Serverless::Function Property "RestApiId" does not support If either.
I end up with 2 Lambda & 2 API gateway with different configurations in the CFN for dev and non-dev environments.
Which is not very nice at all. Can this be addressed sooner, please?

@hoffa
Copy link
Contributor

hoffa commented Oct 17, 2022

You might be able to get this to work by adding AWS::LanguageExtensions to Transform as such:

Transform:
  - AWS::LanguageExtensions
  - AWS::Serverless-2016-10-31

AWS::LanguageExtensions resolves intrinsic functions if the value is known when Transforms are run.

See #2533 for more information.

@hoffa
Copy link
Contributor

hoffa commented Nov 3, 2022

Closing in favor of #2533.

@hoffa hoffa closed this as completed Nov 3, 2022
@maciejmesjasz
Copy link

maciejmesjasz commented Dec 12, 2022

@hoffa Even with AWS::LanguageExtensions, it's not deployable because both SAM CLI and AWS detects that if is not supported

@hoffa
Copy link
Contributor

hoffa commented Dec 12, 2022

@hoffa Even with AWS::LanguageExtensions, it's not deployable because both SAM CLI and AWS detects that if is not supported

Do you have a reproducible template? I did something similar in #214 (comment).

@maciejmesjasz
Copy link

I've tried implementing If to conditionally add (or not to add) Auth section for AWS::Serverless:API but even after adding this extra macro (obviously, before the Serverless) - I got an error that If is not a supported property for the resource.

I'm currently writing a custom macro that is removing that Auth section from the template if it detects a certain environment, but native intrinsic functions support would be great to see in the near future :)

@hoffa
Copy link
Contributor

hoffa commented Dec 12, 2022

I've tried implementing If to conditionally add (or not to add) Auth section for AWS::Serverless:API but even after adding this extra macro (obviously, before the Serverless) - I got an error that If is not a supported property for the resource.

I'm currently writing a custom macro that is removing that Auth section from the template if it detects a certain environment, but native intrinsic functions support would be great to see in the near future :)

I tried by creating the following template template.yaml:

Transform:
  - AWS::LanguageExtensions
  - AWS::Serverless-2016-10-31

Parameters:
  WithAuth:
    Type: String

Conditions:
  WithAuthCondition: !Equals [!Ref WithAuth, "yes"]

Resources:
  MyFunction:
    Type: AWS::Serverless::Function
    Properties:
      Runtime: python3.8
      Handler: foo
      InlineCode: bar
      Events:
        ApiEvent:
          Type: Api
          Properties:
            Method: get
            Path: /
            RestApiId: !Ref MyApi

  MyApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: prod
      Auth:
        Authorizers:
          Fn::If:
            - WithAuthCondition
            - LambdaRequestAuthorizer:
                FunctionArn: !GetAtt MyFunction.Arn
            - !Ref AWS::NoValue

Then deploying without authorizer:

sam deploy --region us-west-2 --resolve-s3 --capabilities CAPABILITY_IAM --stack-name test-1859 --template template.yaml --parameter-overrides WithAuth=no

And with authorizer:

sam deploy --region us-west-2 --resolve-s3 --capabilities CAPABILITY_IAM --stack-name test-1859 --template template.yaml --parameter-overrides WithAuth=yes

And it seems to work as expected.

@maciejmesjasz
Copy link

Wow, Thank you @hoffa it's working as expected!!!
Turned out I've been using "!If" rather than "Fn::If:"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/intrinsics Ref, If, Sub, GetAtt, ... stage/pm-review Waiting for review by our Product Manager, please don't work on this yet type/feature
Projects
None yet
Development

No branches or pull requests