VPC Endpoints on-demand with CloudFormation
Cloud DevOps @ smallfries.digital
Date: 2024-07-01
In modern cloud architectures, it's essential to secure communication between your resources within a Virtual Private Cloud (VPC) and other AWS services. VPC Endpoints provide a secure and scalable way to connect your VPC to AWS services without traversing the public internet, reducing the risk of data exposure and improving network performance.
This blog post will walk you through a CloudFormation template that creates multiple VPC Endpoints for popular AWS services like Amazon S3, DynamoDB, CloudWatch Logs, and AWS Systems Manager (SSM). We'll also cover the necessary security groups and policies to control access to these endpoints.
The CloudFormation Template
The provided YAML template creates the following resources:
-
Gateway VPC Endpoints: For Amazon S3 and DynamoDB, allowing private connectivity from your VPC to these services.
-
Interface VPC Endpoints: For CloudWatch Monitoring, CloudWatch Logs, SSM, and SSM Messages, enabling private access to these services from your VPC.
-
Security Groups: A default security group for the interface endpoints, and a separate security group for EC2 Instance Connect.
Here's a breakdown of the key sections in the template:
Parameters:
VpcId:
Type: String
Description: VPC ID
VpcCIDR:
Type: String
Description: VPC CIDR to associate with VPC Endpoint security group
SubnetIds:
Type: List<String>
Description: Comma-separated list of subnet IDs
RouteTableIds:
Type: List<String>
Description: Comma-separated list of route table IDs
The template accepts four parameters: the VPC ID, the VPC CIDR block (optional), a list of subnet IDs, and a list of route table IDs. These parameters allow you to customize the deployment to your specific VPC and network configuration.
Resources:
VPCEndpointSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: VPC Endpoint Security Group
VpcId: !Ref VpcId
This section creates a security group for the interface VPC Endpoints. You can modify the security group rules to control inbound and outbound traffic to these endpoints.
S3Endpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal: "*"
Action:
- s3:*
Resource:
- "*"
RouteTableIds: !Ref RouteTableIds
ServiceName: !Sub "com.amazonaws.${AWS::Region}.s3"
VpcId: !Ref VpcId
VpcEndpointType: Gateway
PrivateDnsEnabled: false
This resource creates a Gateway VPC Endpoint for Amazon S3. Note the PolicyDocument property, which allows all actions (s3:*) on all S3 resources (*). You can modify this policy to restrict access as needed.
The template includes similar resources for creating VPC Endpoints for DynamoDB, CloudWatch Monitoring, CloudWatch Logs, SSM, and SSM Messages.
Deploying the Template
To deploy this CloudFormation template, you'll need to provide the required parameters (VPC ID, subnet IDs, and route table IDs) specific to your AWS account and VPC configuration. You can deploy the template using the AWS Management Console, AWS CLI, or AWS CloudFormation APIs.
Once deployed, your VPC will have secure, private connectivity to the specified AWS services, without the need for internet gateways, NAT gateways, or public IP addresses.
Conclusion
VPC Endpoints are a powerful tool for securing communication between your VPC resources and AWS services. By using CloudFormation templates like the one provided, you can streamline the deployment of VPC Endpoints across multiple accounts and environments, ensuring consistent and secure network configurations.
Remember to review and customize the security group rules and endpoint policies to align with your organization's security requirements and access controls. Additionally, consider automating the deployment process using CI/CD pipelines or infrastructure-as-code tools for efficient and repeatable infrastructure provisioning.
Original Complete Template:
AWSTemplateFormatVersion: 2010-09-09
Description: Create Gateway VPC Endpoints for S3 and DynamoDB. Interface VPC Endpoints for CloudWatch Monitoring/Logs, EC2 Instance Connect and SSM with a default SG.
Parameters:
VpcId:
Type: String
Description: VPC ID
VpcCIDR:
Type: String
Description: VPC CIDR to associate with VPC Endpoint security group (if not provided 0.0.0.0/0 will be used instead)
SubnetIds:
Type: List<String>
Description: Comma separated list of subnet IDs
RouteTableIds:
Type: List<String>
Description: Comma separated list of route table IDs
Conditions:
HasVpcCIDR: !Not
- !Equals
- ""
- !Ref VpcCIDR
Resources:
VPCEndpointSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: VPC Endpoint Security Group
VpcId: !Ref VpcId
VPCEndpointSecurityGroupIngress:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: !Ref VPCEndpointSecurityGroup
FromPort: 443
ToPort: 443
IpProtocol: tcp
SourceSecurityGroupId: !Ref VPCEndpointSecurityGroup
VPCEndpointSecurityGroupIngress2:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: !Ref VPCEndpointSecurityGroup
FromPort: 443
ToPort: 443
IpProtocol: tcp
CidrIp: !If
- HasVpcCIDR
- !Ref VpcCIDR
- "0.0.0.0/0"
S3Endpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal: "*"
Action:
- s3:*
Resource:
- "*"
RouteTableIds: !Ref RouteTableIds
ServiceName: !Sub "com.amazonaws.${AWS::Region}.s3"
VpcId: !Ref VpcId
VpcEndpointType: Gateway
PrivateDnsEnabled: false
DynamoDbEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal: "*"
Action:
- dynamodb:*
Resource:
- "*"
RouteTableIds: !Ref RouteTableIds
ServiceName: !Sub "com.amazonaws.${AWS::Region}.dynamodb"
VpcId: !Ref VpcId
VpcEndpointType: Gateway
PrivateDnsEnabled: false
CloudWatchEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal: "*"
Action:
- logs:*
Resource:
- "*"
SubnetIds: !Ref SubnetIds
SecurityGroupIds: !Split
- ","
- !Join
- ","
- - !GetAtt VPCEndpointSecurityGroup.GroupId
VpcId: !Ref VpcId
ServiceName: !Sub "com.amazonaws.${AWS::Region}.logs"
VpcEndpointType: Interface
PrivateDnsEnabled: false
MonitoringEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal: "*"
Action:
- cloudwatch:*
Resource:
- "*"
SubnetIds: !Ref SubnetIds
SecurityGroupIds: !Split
- ","
- !Join
- ","
- - !GetAtt VPCEndpointSecurityGroup.GroupId
VpcId: !Ref VpcId
ServiceName: !Sub "com.amazonaws.${AWS::Region}.monitoring"
VpcEndpointType: Interface
PrivateDnsEnabled: false
SsmEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal: "*"
Action:
- ssm:*
Resource:
- "*"
SubnetIds: !Ref SubnetIds
SecurityGroupIds: !Split
- ","
- !Join
- ","
- - !GetAtt VPCEndpointSecurityGroup.GroupId
VpcId: !Ref VpcId
ServiceName: !Sub "com.amazonaws.${AWS::Region}.ssm"
VpcEndpointType: Interface
PrivateDnsEnabled: false
SsmMessagesEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal: "*"
Action:
- ssmmessages:*
Resource:
- "*"
SubnetIds: !Ref SubnetIds
SecurityGroupIds: !Split
- ","
- !Join
- ","
- - !GetAtt VPCEndpointSecurityGroup.GroupId
VpcId: !Ref VpcId
ServiceName: !Sub "com.amazonaws.${AWS::Region}.ssmmessages"
VpcEndpointType: Interface
PrivateDnsEnabled: false
VPCEndpointEC2ICSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: VPC Endpoint Security Group for EC2 Instance Connect
VpcId: !Ref VpcId
VPCEndpointEC2ICSecurityGroupEgress:
Type: AWS::EC2::SecurityGroupEgress
Properties:
GroupId: !Ref VPCEndpointEC2ICSecurityGroup
FromPort: 22
ToPort: 22
IpProtocol: tcp
DestinationSecurityGroupId: !Ref VPCEndpointEC2ICSecurityGroup
VPCEndpointEC2ICSecurityGroupEgress2:
Type: AWS::EC2::SecurityGroupEgress
Properties:
GroupId: !Ref VPCEndpointEC2ICSecurityGroup
FromPort: 22
ToPort: 22
IpProtocol: tcp
CidrIp: !If
- HasVpcCIDR
- !Ref VpcCIDR
- "0.0.0.0/0"
EC2InstanceConnectEndpoint:
Type: AWS::EC2::InstanceConnectEndpoint
UpdateReplacePolicy: "Delete"
Properties:
SubnetId: !Select
- 0
- !Ref SubnetIds
SecurityGroupIds: !Split
- ","
- !Join
- ","
- - !GetAtt VPCEndpointEC2ICSecurityGroup.GroupId
PreserveClientIp: false