Cost explorer will help you dig into the usage type and resources used.
$34 screams “NAT Gateway.” Are you SURE you don’t have one? I’d bet a beer on it.
I did cloudformation stack deployments in December to my account. I am pretty sure that it is the ipv6 egress , which is supposed to be serverless and hence cheaper that NAT, that is responsible.
Here is my cloudformation template for VPC:
Resources: # VPC with IPv4 CIDR block BatchVpc: Type: AWS::EC2::VPC Properties: CidrBlock: 10.0.0.0/16 EnableDnsHostnames: true EnableDnsSupport: true InstanceTenancy: default Tags: - Key: Name Value: !Sub '${AWS::StackName}-BatchVpc' - Key: stack Value: !Sub '${AWS::StackName}'
# IPv6 CIDR Block for the VPC
BatchVpcIpv6CidrBlock:
Type: AWS::EC2::VPCCidrBlock
Properties:
VpcId: !Ref BatchVpc
AmazonProvidedIpv6CidrBlock: true
# Egress Only Internet Gateway for IPv6 traffic
BatchEgressIgw:
Type: AWS::EC2::EgressOnlyInternetGateway
Properties:
VpcId: !Ref BatchVpc
# Security Group for SQS access
BatchSgSqs:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Security group for SQS access
VpcId: !Ref BatchVpc
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 10.0.0.0/16
Tags: # Added tags
- Key: Name
Value: !Sub '${AWS::StackName}-BatchSgSqs'
- Key: stack
Value: !Sub '${AWS::StackName}'
# Subnet for Batch instances (public subnet with IPv6)
BatchSubnetPublicA:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref BatchVpc
AvailabilityZone: !Select [ 0, !GetAZs ]
CidrBlock: 10.0.1.0/24
Ipv6CidrBlock: !Select [ 0, !Cidr [ !Select [ 0, !GetAtt BatchVpc.Ipv6CidrBlocks ], 1, 64 ] ]
AssignIpv6AddressOnCreation: true
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-BatchSubnetPublicA'
- Key: stack
Value: !Sub '${AWS::StackName}'
# Route table for the subnet
BatchRtbPublicA:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref BatchVpc
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-BatchRtbPublicA'
- Key: stack
Value: !Sub '${AWS::StackName}'
# Associate subnet with route table
BatchSubnetRtbAssocA:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref BatchSubnetPublicA
RouteTableId: !Ref BatchRtbPublicA
# Route for IPv6 internet traffic
BatchRouteIpv6Internet:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref BatchRtbPublicA
DestinationIpv6CidrBlock: ::/0
EgressOnlyInternetGatewayId: !Ref BatchEgressIgw
# VPC Endpoint for S3
BatchEpS3:
Type: AWS::EC2::VPCEndpoint
Properties:
VpcId: !Ref BatchVpc
ServiceName: !Sub 'com.amazonaws.${AWS::Region}.s3'
RouteTableIds:
- !Ref BatchRtbPublicA
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal: '*'
Action:
- 's3:*'
Resource: '*'
# VPC Endpoint for SQS
BatchEpSqs:
Type: AWS::EC2::VPCEndpoint
Properties:
VpcId: !Ref BatchVpc
VpcEndpointType: Interface
ServiceName: !Sub 'com.amazonaws.${AWS::Region}.sqs'
SubnetIds:
- !Ref BatchSubnetPublicA
SecurityGroupIds:
- !Ref BatchSgSqs
PrivateDnsEnabled: true
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal: '*'
Action:
- 'sqs:*'
Resource: '*'
# for ECS
BatchEpEcs:
Type: AWS::EC2::VPCEndpoint
Properties:
VpcId: !Ref BatchVpc
VpcEndpointType: Interface
ServiceName: !Sub 'com.amazonaws.${AWS::Region}.ecs'
SubnetIds:
- !Ref BatchSubnetPublicA
SecurityGroupIds:
- !Ref BatchSgSqs
PrivateDnsEnabled: true
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal: ''
Action: 'ecs:'
Resource: '' BatchEpEcsAgent:
Type: AWS::EC2::VPCEndpoint
Properties:
VpcId: !Ref BatchVpc
VpcEndpointType: Interface
ServiceName: !Sub 'com.amazonaws.${AWS::Region}.ecs-agent'
SubnetIds:
- !Ref BatchSubnetPublicA
SecurityGroupIds:
- !Ref BatchSgSqs
PrivateDnsEnabled: true
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal: '*'
Action: 'ecs:*'
Resource: '*'
BatchEpEcrApi:
Type: AWS::EC2::VPCEndpoint
Properties:
VpcId: !Ref BatchVpc
VpcEndpointType: Interface
ServiceName: !Sub 'com.amazonaws.${AWS::Region}.ecr.api'
SubnetIds:
- !Ref BatchSubnetPublicA
SecurityGroupIds:
- !Ref BatchSgSqs
PrivateDnsEnabled: true
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal: '*'
Action:
- ecr:GetAuthorizationToken
- ecr:BatchCheckLayerAvailability
- ecr:GetDownloadUrlForLayer
- ecr:BatchGetImage
Resource: '*'
BatchEpEcrDkr:
Type: AWS::EC2::VPCEndpoint
Properties:
VpcId: !Ref BatchVpc
VpcEndpointType: Interface
ServiceName: !Sub 'com.amazonaws.${AWS::Region}.ecr.dkr'
SubnetIds:
- !Ref BatchSubnetPublicA
SecurityGroupIds:
- !Ref BatchSgSqs
PrivateDnsEnabled: true
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal: '*'
Action:
- ecr:GetAuthorizationToken
- ecr:BatchCheckLayerAvailability
- ecr:GetDownloadUrlForLayer
- ecr:BatchGetImage
Resource: '*'
# VPC Endpoint for CloudWatch Logs
BatchEpCloudWatchLogs:
Type: AWS::EC2::VPCEndpoint
Properties:
VpcId: !Ref BatchVpc
VpcEndpointType: Interface
ServiceName: !Sub 'com.amazonaws.${AWS::Region}.logs'
SubnetIds:
- !Ref BatchSubnetPublicA
SecurityGroupIds:
- !Ref BatchSgSqs
PrivateDnsEnabled: true
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal: '*'
Action:
- 'logs:CreateLogGroup'
- 'logs:CreateLogStream'
- 'logs:PutLogEvents'
- 'logs:DescribeLogGroups'
- 'logs:DescribeLogStreams'
Resource: '*'
Outputs:
BatchVpcId:
Value: !Ref BatchVpc
Export:
Name: sandbox-infra-lite-CustomJob-batch-network:VpcId BatchSubnetId:
Value: !Ref BatchSubnetPublicA
Export:
Name: sandbox-infra-lite-CustomJob-batch-network:BatchSubnetId
BatchSgId:
Value: !Ref BatchSgSqs
Export:
Name: sandbox-infra-lite-CustomJob-batch-network:BatchSgId
I had a $5 a month VPS that cost $300 a month to run because it didn't have enough RAM and was swap-happy and running up incredible I/O costs against EBS. The $10 a month VPS was a lot cheaper.
In your case a Lambda could be cheaper still.