Conditional Resource Policy on AWS SAM with Inline Swagger

Cathy
2 min readJun 3, 2019

--

I have been looking for a way to make my resource policy dependent on the stage. We have 3 environments (test, sandbox, and prod). In the test setup, our lambda functions are public for easier testing. While in sandbox and prod, the functions are private. Previously, we have defined the resource policy of our API gateway directly in the AWS console. The next deployments after that worked fine without having to define again the resource policy until yesterday.

Private REST API doesn’t have a resource policy attached to it (Service: AmazonApiGateway; Status Code: 400; Error Code: BadRequestException; Request ID: — — — — — — — -)

We encountered the error above after deployment. We have noticed that the resource policy defined in the AWS Console gets removed few minutes after the deployment started. A workaround to fix this is refresh the resource policy while deploying until the resource policy becomes blank and quickly add it again before the deployment finishes. This is risky and I wouldn’t recommend for you to keep on doing this.

With the problem at hand, I started to look around for solutions. We already have an existing condition that returns true when the stage is sandbox or production in the template.yaml. For further information on how to make use of conditions, you can check out this documentation from AWS: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/conditions-section-structure.html.

Conditions:
PrivateApiGateway: !Or [!Equals [!Ref Stage, sandbox], !Equals [!Ref Stage, production]]

We used the condition above to determine the endpoint configuration for our API Gateway:

EndpointConfiguration: !If [PrivateApiGateway, PRIVATE, REGIONAL]

Depending on the stage, the endpoint configuration for the API Gateway will either be private or regional. If API Gateway is private, I want it to use a resource policy. Our endpoints are restricted depending on the SourceVPCe. See https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-resource-policies-examples.html for more examples.

x-amazon-apigateway-policy:
- Version: “2012–10–17”
Statement:
- Effect: “Allow”
Principal: “*”
Action:
- “execute-api:Invoke”
Resource: “execute-api:/*”
- Effect: “Deny”
Principal: “*”
Action:
- “execute-api:Invoke”
Resource: “execute-api:/*”
Condition:
StringNotEquals:
aws:SourceVpce: !Ref SourceVpce

The resource policy above already works for Private API Gateway, however, I didn’t know how to remove the x-amazon-apigateway-policy property if our API Gateway is public. I came across this blog: https://blog.reachforce.com/api-gateway-resource-policy-in-cloudformation-with-conditional-nested-property and realized how I can format the if condition and use AWS::NoValue to remove a property that I didn’t want.

Here is our final resource policy definition:

x-amazon-apigateway-policy:
!If
- PrivateApiGateway
- Version: “2012–10–17”
Statement:
- Effect: “Allow”
Principal: “*”
Action:
- “execute-api:Invoke”
Resource: “execute-api:/*”
- Effect: “Deny”
Principal: “*”
Action:
- “execute-api:Invoke”
Resource: “execute-api:/*”
Condition:
StringNotEquals:
aws:SourceVpce: !Ref SourceVpce
- !Ref "AWS::NoValue"

I hope I was able to help you in making some parts of your template be conditional. There’s some information about the AWS::NoValue in the Fn::If section of the AWS documentation for intrinsic functions: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-conditions.html.

--

--