From 108e8d7a6a4bfe8133147db1ccb7c693dfdce577 Mon Sep 17 00:00:00 2001 From: Eric Johnson Date: Tue, 17 Jan 2023 12:03:30 -0700 Subject: [PATCH] Closes #935. Fixes issue with overly permissive policy on CDK example for API Gateway --- .../src/api/dist/index.js | 2 +- apigw-to-private-apig-cdk/src/api/index.ts | 127 ++++++++++-------- 2 files changed, 70 insertions(+), 59 deletions(-) diff --git a/apigw-to-private-apig-cdk/src/api/dist/index.js b/apigw-to-private-apig-cdk/src/api/dist/index.js index 2dc4c07b6..8728b12c4 100644 --- a/apigw-to-private-apig-cdk/src/api/dist/index.js +++ b/apigw-to-private-apig-cdk/src/api/dist/index.js @@ -12,7 +12,7 @@ __export(exports, { }); // api/config.json -var prefix = "PrivateAPIGateway"; +var prefix = "APIGateway"; var description = "A VPC Lambda to get request from API Gateway Private API with CDK"; var api = { handler: "ProxyLambda" diff --git a/apigw-to-private-apig-cdk/src/api/index.ts b/apigw-to-private-apig-cdk/src/api/index.ts index a26722fbe..dad69e718 100644 --- a/apigw-to-private-apig-cdk/src/api/index.ts +++ b/apigw-to-private-apig-cdk/src/api/index.ts @@ -13,22 +13,22 @@ export class ApiStack extends cdk.Stack { constructor(scope: cdk.App, id: string, vpc: ec2.Vpc) { super(scope, id); -/* Create Security group */ + /* Create Security group */ const apiGatewayEndpointSG = new ec2.SecurityGroup(this, "apiGatewayEndpointSG", { - description: "Security Group for Api Gateway Endpoint", - vpc: vpc + description: "Security Group for Api Gateway Endpoint", + vpc: vpc }); apiGatewayEndpointSG.addIngressRule(ec2.Peer.ipv4('10.0.0.0/8'), ec2.Port.tcp(443)); -/* Create API Gateway Interface VPC Endpoint */ + /* Create API Gateway Interface VPC Endpoint */ const endpointAPIGateway = new ec2.InterfaceVpcEndpoint(this, "endpointAPIGateway", { - service: ec2.InterfaceVpcEndpointAwsService.APIGATEWAY, - vpc: vpc, - subnets: vpc.selectSubnets({ - subnetType: ec2.SubnetType.PRIVATE - }), - privateDnsEnabled: true, - securityGroups: [apiGatewayEndpointSG] + service: ec2.InterfaceVpcEndpointAwsService.APIGATEWAY, + vpc: vpc, + subnets: vpc.selectSubnets({ + subnetType: ec2.SubnetType.PRIVATE + }), + privateDnsEnabled: true, + securityGroups: [apiGatewayEndpointSG] }); const handler = new lambda.Function(this, "handler", { @@ -41,11 +41,22 @@ export class ApiStack extends cdk.Stack { }) }); -/* Grant api gateway invoke permission on lambda */ + /* Grant api gateway invoke permission on lambda */ handler.grantInvoke(new iam.ServicePrincipal('apigateway.amazonaws.com')); - + const apiResourcePolicy = new iam.PolicyDocument({ statements: [ + new iam.PolicyStatement({ + effect: iam.Effect.DENY, + actions: ['execute-api:Invoke'], + principals: [new iam.AnyPrincipal()], + resources: ['execute-api:/*/*/*'], + conditions: { + StringNotEquals: { + "aws:sourceVpce": endpointAPIGateway.vpcEndpointId + } + } + }), new iam.PolicyStatement({ effect: iam.Effect.ALLOW, actions: ['execute-api:Invoke'], @@ -54,67 +65,67 @@ export class ApiStack extends cdk.Stack { }) ] }); - - const restapi = new apigateway.LambdaRestApi(this, config.prefix, { + + const restapi = new apigateway.LambdaRestApi(this, config.prefix, { handler, description: config.description, - endpointConfiguration: {types: [apigateway.EndpointType.PRIVATE], vpcEndpoints: [endpointAPIGateway]}, + endpointConfiguration: { types: [apigateway.EndpointType.PRIVATE], vpcEndpoints: [endpointAPIGateway] }, policy: apiResourcePolicy }); -/* Create Load Balancer Target Group */ + /* Create Load Balancer Target Group */ const targetGroup = new elb.NetworkTargetGroup(this, 'TargetGroup', { - port: 443, + port: 443, vpc, targetType: elb.TargetType.IP }); for (let counter = 0; counter < vpc.availabilityZones.length; counter++) { const getEndpointIp = new customResource.AwsCustomResource(this, `GetEndpointIp${counter}`, { - onUpdate: { - service: 'EC2', - action: 'describeNetworkInterfaces', - outputPath: `NetworkInterfaces.${counter}.PrivateIpAddress`, - parameters: { NetworkInterfaceIds: endpointAPIGateway.vpcEndpointNetworkInterfaceIds }, - physicalResourceId: customResource.PhysicalResourceId.of(`NetworkInterfaces.${counter}.PrivateIpAddress`) - }, - policy: customResource.AwsCustomResourcePolicy.fromSdkCalls({resources: customResource.AwsCustomResourcePolicy.ANY_RESOURCE}) + onUpdate: { + service: 'EC2', + action: 'describeNetworkInterfaces', + outputPath: `NetworkInterfaces.${counter}.PrivateIpAddress`, + parameters: { NetworkInterfaceIds: endpointAPIGateway.vpcEndpointNetworkInterfaceIds }, + physicalResourceId: customResource.PhysicalResourceId.of(`NetworkInterfaces.${counter}.PrivateIpAddress`) + }, + policy: customResource.AwsCustomResourcePolicy.fromSdkCalls({ resources: customResource.AwsCustomResourcePolicy.ANY_RESOURCE }) }); targetGroup.addTarget(new elbTarget.IpTarget(cdk.Token.asString(getEndpointIp.getResponseField(`NetworkInterfaces.${counter}.PrivateIpAddress`)), 443)); - } -/* End Create Load Balancer Target Group */ -/* Start Create Private Network Load Balancer */ - let privateAPGNLB = new elb.NetworkLoadBalancer(this, 'internalAPIGNLB', { - vpc: vpc, - internetFacing: false, - }); + } + /* End Create Load Balancer Target Group */ + /* Start Create Private Network Load Balancer */ + let privateAPGNLB = new elb.NetworkLoadBalancer(this, 'internalAPIGNLB', { + vpc: vpc, + internetFacing: false, + }); - privateAPGNLB.addListener('listner',{ - port: 443, - protocol: elb.Protocol.TCP, - defaultTargetGroups: [targetGroup] - } + privateAPGNLB.addListener('listner', { + port: 443, + protocol: elb.Protocol.TCP, + defaultTargetGroups: [targetGroup] + } ); -/* End Create Private Network Load Balancer */ -/* Create VPC Link in API Gateway */ -let vpcLink = new apigateway.VpcLink(this, 'vpclink', { - targets: [privateAPGNLB], - vpcLinkName: 'apigconnectvpclink' -}); -/* End Create VPC Link in API Gateway */ -/* Create Public API Gateway */ -const publicapi = new apigateway.RestApi(this, 'public-api'); -const integration = new apigateway.Integration({ - integrationHttpMethod: "ANY", - type: apigateway.IntegrationType.HTTP_PROXY, - uri: `https://${restapi.restApiId}-${endpointAPIGateway.vpcEndpointId}.execute-api.${this.region}.amazonaws.com/prod`, - options: { - connectionType: apigateway.ConnectionType.VPC_LINK, - vpcLink: vpcLink, - }, -}); -publicapi.root.addMethod('GET', integration); -/* End Create Public API Gateway */ + /* End Create Private Network Load Balancer */ + /* Create VPC Link in API Gateway */ + let vpcLink = new apigateway.VpcLink(this, 'vpclink', { + targets: [privateAPGNLB], + vpcLinkName: 'apigconnectvpclink' + }); + /* End Create VPC Link in API Gateway */ + /* Create Public API Gateway */ + const publicapi = new apigateway.RestApi(this, 'public-api'); + const integration = new apigateway.Integration({ + integrationHttpMethod: "ANY", + type: apigateway.IntegrationType.HTTP_PROXY, + uri: `https://${restapi.restApiId}-${endpointAPIGateway.vpcEndpointId}.execute-api.${this.region}.amazonaws.com/prod`, + options: { + connectionType: apigateway.ConnectionType.VPC_LINK, + vpcLink: vpcLink, + }, + }); + publicapi.root.addMethod('GET', integration); + /* End Create Public API Gateway */ const tags = config.tags