Product
Introducing Ruby Support in Socket
Socket is launching Ruby support for all users. Enhance your Rails projects with AI-powered security scans for vulnerabilities and supply chain threats. Now in Beta!
@aws-cdk/aws-ec2
Advanced tools
@aws-cdk/aws-ec2 is an AWS Cloud Development Kit (CDK) library that allows you to define and manage Amazon EC2 instances and related networking infrastructure using code. This package provides a high-level, object-oriented abstraction to create and configure EC2 instances, VPCs, security groups, and other networking components in a programmatic way.
Create a VPC
This code sample demonstrates how to create a Virtual Private Cloud (VPC) with the maximum number of Availability Zones (AZs) in the region. The VPC is a logically isolated network that you can use to launch AWS resources.
const ec2 = require('@aws-cdk/aws-ec2');
const cdk = require('@aws-cdk/core');
class MyStack extends cdk.Stack {
constructor(scope, id, props) {
super(scope, id, props);
const vpc = new ec2.Vpc(this, 'MyVpc', {
maxAzs: 3 // Default is all AZs in the region
});
}
}
const app = new cdk.App();
new MyStack(app, 'MyStack');
app.synth();
Create an EC2 Instance
This code sample demonstrates how to create an EC2 instance within a VPC. The instance is of type 't2.micro' and uses the Amazon Linux AMI.
const ec2 = require('@aws-cdk/aws-ec2');
const cdk = require('@aws-cdk/core');
class MyStack extends cdk.Stack {
constructor(scope, id, props) {
super(scope, id, props);
const vpc = new ec2.Vpc(this, 'MyVpc');
const instance = new ec2.Instance(this, 'MyInstance', {
vpc,
instanceType: new ec2.InstanceType('t2.micro'),
machineImage: new ec2.AmazonLinuxImage(),
});
}
}
const app = new cdk.App();
new MyStack(app, 'MyStack');
app.synth();
Create a Security Group
This code sample demonstrates how to create a Security Group within a VPC. The Security Group allows inbound SSH access (port 22) from any IPv4 address.
const ec2 = require('@aws-cdk/aws-ec2');
const cdk = require('@aws-cdk/core');
class MyStack extends cdk.Stack {
constructor(scope, id, props) {
super(scope, id, props);
const vpc = new ec2.Vpc(this, 'MyVpc');
const securityGroup = new ec2.SecurityGroup(this, 'MySecurityGroup', {
vpc,
description: 'Allow ssh access to ec2 instances',
allowAllOutbound: true
});
securityGroup.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(22), 'allow ssh access from the world');
}
}
const app = new cdk.App();
new MyStack(app, 'MyStack');
app.synth();
The aws-sdk package is the official AWS SDK for JavaScript, which allows you to interact with various AWS services, including EC2. Unlike @aws-cdk/aws-ec2, which is used for defining infrastructure as code, aws-sdk is used for making API calls to manage AWS resources at runtime.
Terraform is an open-source infrastructure as code software tool created by HashiCorp. It allows you to define and provision data center infrastructure using a high-level configuration language. While @aws-cdk/aws-ec2 is specific to AWS and uses TypeScript/JavaScript, Terraform is cloud-agnostic and uses its own configuration language called HCL.
Pulumi is an infrastructure as code tool that allows you to define cloud resources using general-purpose programming languages like TypeScript, JavaScript, Python, and Go. Similar to @aws-cdk/aws-ec2, Pulumi provides a way to define AWS resources programmatically, but it supports multiple cloud providers and languages.
The @aws-cdk/aws-ec2
package contains primitives for setting up networking and
instances.
import ec2 = require('@aws-cdk/aws-ec2');
Most projects need a Virtual Private Cloud to provide security by means of
network partitioning. This is achieved by creating an instance of
Vpc
:
const vpc = new ec2.Vpc(this, 'VPC');
All default constructs require EC2 instances to be launched inside a VPC, so you should generally start by defining a VPC whenever you need to launch instances for your project.
A VPC consists of one or more subnets that instances can be placed into. CDK distinguishes three different subnet types:
A default VPC configuration will create public and private subnets, but not isolated subnets. See Advanced Subnet Configuration below for information on how to change the default subnet configuration.
Constructs using the VPC will "launch instances" (or more accurately, create
Elastic Network Interfaces) into one or more of the subnets. They all accept
a property called subnetSelection
(sometimes called vpcSubnets
) to allow
you to select in what subnet to place the ENIs, usually defaulting to
private subnets if the property is omitted.
If you would like to save on the cost of NAT gateways, you can use
isolated subnets instead of private subnets (as described in Advanced
Subnet Configuration). If you need private instances to have
internet connectivity, another option is to reduce the number of NAT gateways
created by setting the natGateways
property to a lower value (the default
is one NAT gateway per availability zone). Be aware that this may have
availability implications for your application.
By default, a VPC will spread over at most 3 Availability Zones available to
it. To change the number of Availability Zones that the VPC will spread over,
specify the maxAzs
property when defining it.
The number of Availability Zones that are available depends on the region and account of the Stack containing the VPC. If the region and account are specified on the Stack, the CLI will look up the existing Availability Zones and get an accurate count. If region and account are not specified, the stack could be deployed anywhere and it will have to make a safe choice, limiting itself to 2 Availability Zones.
Therefore, to get the VPC to spread over 3 or more availability zones, you must specify the environment where the stack will be deployed.
By default, the Vpc
construct will create NAT gateways for you, which
are managed by AWS. If you would prefer to use your own managed NAT
instances instead, specify a different value for the natGatewayProvider
property, as follows:
The construct will automatically search for the most recent NAT gateway AMI.
If you prefer to use a custom AMI, use machineImage: MachineImage.genericLinux({ ... })
and configure the right AMI ID for the
regions you want to deploy to.
If the default VPC configuration (public and private subnets spanning the
size of the VPC) don't suffice for you, you can configure what subnets to
create by specifying the subnetConfiguration
property. It allows you
to configure the number and size of all subnets. Specifying an advanced
subnet configuration could look like this:
const vpc = new ec2.Vpc(this, 'TheVPC', {
// 'cidr' configures the IP range and size of the entire VPC.
// The IP space will be divided over the configured subnets.
cidr: '10.0.0.0/21',
// 'maxAzs' configures the maximum number of availability zones to use
maxAzs: 3,
// 'subnetConfiguration' specifies the "subnet groups" to create.
// Every subnet group will have a subnet for each AZ, so this
// configuration will create `3 groups × 3 AZs = 9` subnets.
subnetConfiguration: [
{
// 'subnetType' controls Internet access, as described above.
subnetType: ec2.SubnetType.PUBLIC,
// 'name' is used to name this particular subnet group. You will have to
// use the name for subnet selection if you have more than one subnet
// group of the same type.
name: 'Ingress',
// 'cidrMask' specifies the IP addresses in the range of of individual
// subnets in the group. Each of the subnets in this group will contain
// `2^(32 address bits - 24 subnet bits) - 2 reserved addresses = 254`
// usable IP addresses.
//
// If 'cidrMask' is left out the available address space is evenly
// divided across the remaining subnet groups.
cidrMask: 24,
},
{
cidrMask: 24,
name: 'Application',
subnetType: ec2.SubnetType.PRIVATE,
},
{
cidrMask: 28,
name: 'Database',
subnetType: ec2.SubnetType.ISOLATED,
// 'reserved' can be used to reserve IP address space. No resources will
// be created for this subnet, but the IP range will be kept available for
// future creation of this subnet, or even for future subdivision.
reserved: true
}
],
});
The example above is one possible configuration, but the user can use the constructs above to implement many other network configurations.
The Vpc
from the above configuration in a Region with three
availability zones will be the following:
Subnet Name | Type | IP Block | AZ | Features |
---|---|---|---|---|
IngressSubnet1 | PUBLIC | 10.0.0.0/24 | #1 | NAT Gateway |
IngressSubnet2 | PUBLIC | 10.0.1.0/24 | #2 | NAT Gateway |
IngressSubnet3 | PUBLIC | 10.0.2.0/24 | #3 | NAT Gateway |
ApplicationSubnet1 | PRIVATE | 10.0.3.0/24 | #1 | Route to NAT in IngressSubnet1 |
ApplicationSubnet2 | PRIVATE | 10.0.4.0/24 | #2 | Route to NAT in IngressSubnet2 |
ApplicationSubnet3 | PRIVATE | 10.0.5.0/24 | #3 | Route to NAT in IngressSubnet3 |
DatabaseSubnet1 | ISOLATED | 10.0.6.0/28 | #1 | Only routes within the VPC |
DatabaseSubnet2 | ISOLATED | 10.0.6.16/28 | #2 | Only routes within the VPC |
DatabaseSubnet3 | ISOLATED | 10.0.6.32/28 | #3 | Only routes within the VPC |
There are situations where the IP space for a subnet or number of subnets
will need to be reserved. This is useful in situations where subnets would
need to be added after the vpc is originally deployed, without causing IP
renumbering for existing subnets. The IP space for a subnet may be reserved
by setting the reserved
subnetConfiguration property to true, as shown
below:
const vpc = new ec2.Vpc(this, 'TheVPC', {
natGateways: 1,
subnetConfiguration: [
{
cidrMask: 26,
name: 'Public',
subnetType: ec2.SubnetType.PUBLIC,
},
{
cidrMask: 26,
name: 'Application1',
subnetType: ec2.SubnetType.PRIVATE,
},
{
cidrMask: 26,
name: 'Application2',
subnetType: ec2.SubnetType.PRIVATE,
reserved: true, // <---- This subnet group is reserved
},
{
cidrMask: 27,
name: 'Database',
subnetType: ec2.SubnetType.ISOLATED,
}
],
});
In the example above, the subnet for Application2 is not actually provisioned
but its IP space is still reserved. If in the future this subnet needs to be
provisioned, then the reserved: true
property should be removed. Reserving
parts of the IP space prevents the other subnets from getting renumbered.
If you are creating multiple Stack
s inside the same CDK application, you
can reuse a VPC defined in one Stack in another by simply passing the VPC
instance around:
If your VPC is created outside your CDK app, you can use Vpc.fromLookup()
.
The CDK CLI will search for the specified VPC in the the stack's region and
account, and import the subnet configuration. Looking up can be done by VPC
ID, but more flexibly by searching for a specific tag on the VPC.
Subnet types will be determined from the aws-cdk:subnet-type
tag on the
subnet if it exists, or the presence of a route to an Internet Gateway
otherwise. Subnet names will be determined from the aws-cdk:subnet-name
tag
on the subnet if it exists, or will mirror the subnet type otherwise (i.e.
a public subnet will have the name "Public"
).
Here's how Vpc.fromLookup()
can be used:
In AWS, all network traffic in and out of Elastic Network Interfaces (ENIs)
is controlled by Security Groups. You can think of Security Groups as a
firewall with a set of rules. By default, Security Groups allow no incoming
(ingress) traffic and all outgoing (egress) traffic. You can add ingress rules
to them to allow incoming traffic streams. To exert fine-grained control over
egress traffic, set allowAllOutbound: false
on the SecurityGroup
, after
which you can add egress traffic rules.
You can manipulate Security Groups directly:
const mySecurityGroup = new ec2.SecurityGroup(this, 'SecurityGroup', {
vpc,
description: 'Allow ssh access to ec2 instances',
allowAllOutbound: true // Can be set to false
});
mySecurityGroup.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(22), 'allow ssh access from the world');
All constructs that create ENIs on your behalf (typically constructs that create EC2 instances or other VPC-connected resources) will all have security groups automatically assigned. Those constructs have an attribute called connections, which is an object that makes it convenient to update the security groups. If you want to allow connections between two constructs that have security groups, you have to add an Egress rule to one Security Group, and an Ingress rule to the other. The connections object will automatically take care of this for you:
// Allow connections from anywhere
loadBalancer.connections.allowFromAnyIpv4(ec2.Port.tcp(443), 'Allow inbound HTTPS');
// The same, but an explicit IP address
loadBalancer.connections.allowFrom(ec2.Peer.ipv4('1.2.3.4/32'), ec2.Port.tcp(443), 'Allow inbound HTTPS');
// Allow connection between AutoScalingGroups
appFleet.connections.allowTo(dbFleet, ec2.Port.tcp(443), 'App can call database');
There are various classes that implement the connection peer part:
// Simple connection peers
let peer = ec2.Peer.ipv4("10.0.0.0/16");
peer = ec2.Peer.anyIpv4();
peer = ec2.Peer.ipv6("::0/0");
peer = ec2.Peer.anyIpv6();
peer = ec2.Peer.prefixList("pl-12345");
appFleet.connections.allowTo(peer, ec2.Port.tcp(443), 'Allow outbound HTTPS');
Any object that has a security group can itself be used as a connection peer:
// These automatically create appropriate ingress and egress rules in both security groups
fleet1.connections.allowTo(fleet2, ec2.Port.tcp(80), 'Allow between fleets');
appFleet.connections.allowFromAnyIpv4(ec2.Port.tcp(80), 'Allow from load balancer');
The connections that are allowed are specified by port ranges. A number of classes provide the connection specifier:
ec2.Port.tcp(80)
ec2.Port.tcpRange(60000, 65535)
ec2.Port.allTcp()
ec2.Port.allTraffic()
NOTE: This set is not complete yet; for example, there is no library support for ICMP at the moment. However, you can write your own classes to implement those.
Some Constructs have default ports associated with them. For example, the listener of a load balancer does (it's the public port), or instances of an RDS database (it's the port the database is accepting connections on).
If the object you're calling the peering method on has a default port associated with it, you can call
allowDefaultPortFrom()
and omit the port specifier. If the argument has an associated default port, call
allowDefaultPortTo()
.
For example:
// Port implicit in listener
listener.connections.allowDefaultPortFromAnyIpv4('Allow public');
// Port implicit in peer
appFleet.connections.allowDefaultPortTo(rdsDatabase, 'Fleet can access database');
AMIs control the OS that gets launched when you start your EC2 instance. The EC2 library contains constructs to select the AMI you want to use.
Depending on the type of AMI, you select it a different way. Here are some examples of things you might want to use:
NOTE: The AMIs selected by
MachineImage.lookup()
will be cached incdk.context.json
, so that your AutoScalingGroup instances aren't replaced while you are making unrelated changes to your CDK app.To query for the latest AMI again, remove the relevant cache entry from
cdk.context.json
, or use thecdk context
command. For more information, see Runtime Context in the CDK developer guide.
Create your VPC with VPN connections by specifying the vpnConnections
props (keys are construct id
s):
const vpc = new ec2.Vpc(this, 'MyVpc', {
vpnConnections: {
dynamic: { // Dynamic routing (BGP)
ip: '1.2.3.4'
},
static: { // Static routing
ip: '4.5.6.7',
staticRoutes: [
'192.168.10.0/24',
'192.168.20.0/24'
]
}
}
});
To create a VPC that can accept VPN connections, set vpnGateway
to true
:
const vpc = new ec2.Vpc(this, 'MyVpc', {
vpnGateway: true
});
VPN connections can then be added:
vpc.addVpnConnection('Dynamic', {
ip: '1.2.3.4'
});
Routes will be propagated on the route tables associated with the private subnets.
VPN connections expose metrics (cloudwatch.Metric) across all tunnels in the account/region and per connection:
// Across all tunnels in the account/region
const allDataOut = ec2.VpnConnection.metricAllTunnelDataOut();
// For a specific vpn connection
const vpnConnection = vpc.addVpnConnection('Dynamic', {
ip: '1.2.3.4'
});
const state = vpnConnection.metricTunnelState();
A VPC endpoint enables you to privately connect your VPC to supported AWS services and VPC endpoint services powered by PrivateLink without requiring an internet gateway, NAT device, VPN connection, or AWS Direct Connect connection. Instances in your VPC do not require public IP addresses to communicate with resources in the service. Traffic between your VPC and the other service does not leave the Amazon network.
Endpoints are virtual devices. They are horizontally scaled, redundant, and highly available VPC components that allow communication between instances in your VPC and services without imposing availability risks or bandwidth constraints on your network traffic.
example of setting up VPC endpoints
By default, interface VPC endpoints create a new security group and traffic is not automatically allowed from the VPC CIDR.
Use the connections
object to allow traffic to flow to the endpoint:
myEndpoint.connections.allowDefaultPortFromAnyIpv4();
Alternatively, existing security groups can be used by specifying the securityGroups
prop.
A VPC endpoint service enables you to expose a Network Load Balancer(s) as a provider service to consumers, who connect to your service over a VPC endpoint. You can restrict access to your service via whitelisted principals (anything that extends ArnPrincipal), and require that new connections be manually accepted.
new VpcEndpointService(this, "EndpointService", {
vpcEndpointServiceLoadBalancers: [networkLoadBalancer1, networkLoadBalancer2],
acceptanceRequired: true,
whitelistedPrincipals: [new ArnPrincipal("arn:aws:iam::123456789012:root")]
});
A bastion host functions as an instance used to access servers and resources in a VPC without open up the complete VPC on a network level. You can use bastion hosts using a standard SSH connection targetting port 22 on the host. As an alternative, you can connect the SSH connection feature of AWS Systems Manager Session Manager, which does not need an opened security group. (https://aws.amazon.com/about-aws/whats-new/2019/07/session-manager-launches-tunneling-support-for-ssh-and-scp/)
A default bastion host for use via SSM can be configured like:
const host = new ec2.BastionHostLinux(this, 'BastionHost', { vpc });
If you want to connect from the internet using SSH, you need to place the host into a public subnet. You can then configure allowed source hosts.
const host = new ec2.BastionHostLinux(this, 'BastionHost', {
vpc,
subnetSelection: { subnetType: ec2.SubnetType.PUBLIC },
});
host.allowSshAccessFrom(ec2.Peer.ipv4('1.2.3.4/32'));
As there are no SSH public keys deployed on this machine, you need to use EC2 Instance Connect
with the command aws ec2-instance-connect send-ssh-public-key
to provide your SSH public key.
To add EBS block device mappings, specify the blockDeviceMappings
property. The follow example sets the EBS-backed
root device (/dev/sda1
) size to 50 GiB, and adds another EBS-backed device mapped to /dev/sdm
that is 100 GiB in
size:
new ec2.Instance(this, 'Instance', {
// ...
blockDeviceMappings: [
{
deviceName: '/dev/sda1',
volume: ec2.BlockDeviceVolume.ebs(50),
},
{
deviceName: '/dev/sdm',
volume: ec2.BlockDeviceVolume.ebs(100),
},
],
});
1.23.0 (2020-02-07)
MachineImage
factory, document instance replacement (#6065) (435d810), closes #5675 #6025FAQs
The CDK Construct Library for AWS::EC2
The npm package @aws-cdk/aws-ec2 receives a total of 111,055 weekly downloads. As such, @aws-cdk/aws-ec2 popularity was classified as popular.
We found that @aws-cdk/aws-ec2 demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 4 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Product
Socket is launching Ruby support for all users. Enhance your Rails projects with AI-powered security scans for vulnerabilities and supply chain threats. Now in Beta!
Product
Ensure open-source compliance with Socket’s License Enforcement Beta. Set up your License Policy and secure your software!
Product
We're launching a new set of license analysis and compliance features for analyzing, managing, and complying with licenses across a range of supported languages and ecosystems.