ResponsiblyUnranked
ResponsiblyUnranked

Reputation: 1856

How to create API Gateway Resource Policy that references itself in the Python CDK?

I'm creating an API that will ONLY accept requests made from the GitHub Webhook servers by using a Resource Policy with the GitHub IPs. I've successfully done this using the console and manually creating the Resource Policy, but I'm running into a problem when I'm using the CDK.

Here's my code:

delete_trigger_integration = aws_apigateway.LambdaIntegration(
    trigger_step_lambda, proxy=False, integration_responses=[])

api_policy_document = aws_iam.PolicyDocument()

api = aws_apigateway.RestApi(
    self,
    "GithubWebhookApi",
    rest_api_name=PROJECT_NAME + "-apigateway-trigger-delete",
    default_integration=delete_trigger_integration,
    policy=api_policy_document)

delete_execution_resource = api.root.add_resource("execution")

delete_execution_method = delete_execution_resource.add_method(
    "POST", delete_trigger_integration)
delete_execution_resource.add_cors_preflight(allow_origins=["*"])

create_repo_lambda.add_environment("API_URL",
                                   delete_execution_resource.url)

api_policy_document.add_statements(
    aws_iam.PolicyStatement(
        effect=aws_iam.Effect.ALLOW,
        principals=[aws_iam.AnyPrincipal()],
        actions=["execute-api:Invoke"],
        resources=[api.arn_for_execute_api()]))

api_policy_document.add_statements(
    aws_iam.PolicyStatement(
        effect=aws_iam.Effect.DENY,
        actions=["execute-api:Invoke"],
        conditions={
            "NotIpAddress": {
                "aws:SourceIp": [
                    "192.30.252.0/22", "185.199.108.0/22",
                    "140.82.112.0/20"
                ]
            }
        },
        principals=[aws_iam.AnyPrincipal()],
        resources=[api.arn_for_execute_api()]))

I feel like I'm very close to having a solution but I can't figure out what it is. The problem with the code above is that I get the ValidationError: Circular dependency between resources error when trying to deploy it - which I can understand, the resource policy is addressing the very resource it's inside. But I can't find a way around it in the CDK.

For other resources it's really easy to ad IAM policies after the creation using aws_iam.add_to_role_policy but I can't find the equivalent for the RestApi class in the CDK. It seems you have to add the PolicyDocument when you declare the RestApi.

Also, here's the resource policy that I'm trying to recreate in the CDK (it's those resource ARNs which are causing the problem):

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "execute-api:Invoke",
            "Resource": "arn:aws:execute-api:eu-west-1:000000000000:aaaaaaaaaa/*/*/*"
        },
        {
            "Effect": "Deny",
            "Principal": "*",
            "Action": "execute-api:Invoke",
            "Resource": "arn:aws:execute-api:eu-west-1:000000000000:aaaaaaaaaa/*/*/*",
            "Condition": {
                "NotIpAddress": {
                    "aws:SourceIp": [
                        "192.30.252.0/22",
                        "185.199.108.0/22",
                        "140.82.112.0/20"
                    ]
                }
            }
        }
    ]
}

Does anyone know a solution to my problem? Thanks in advance!

Also, you can ignore the empty integration responses - I'm still working on that.

Upvotes: 7

Views: 7406

Answers (1)

jogold
jogold

Reputation: 7417

This is related to how the underlying CloudFormation resource works.

As the Policy must be defined within the AWS::ApiGateway::RestApi resource, it cannot reference itself.

From the documentation:

To set the ARN for the policy, use the !Join intrinsic function with "" as delimiter and values of "execute-api:/" and "*".

Which translates into the following in your CDK code:

resources=[core.Fn.join('', ['execute-api:/', '*'])]

Upvotes: 4

Related Questions