Manage IP Addressing with Virtual Private Clouds in Amazon Web Services

In this article, I’ll show you how to provision a Windows Server 2012 R2 virtual machine (EC2 instance) with a static private IP address in a Virtual Private Cloud (VPC), all with the help of Windows PowerShell.

In a previous article, Provision Windows Server in Amazon Web Services using PowerShell, I walked through provisioning Windows Server EC2-Classic instances in Amazon Web Services (AWS), but there are two major limitations to this approach. The first is that when stopped, classic instances lose their private internal IP address, meaning that they can’t be used for workloads, such as Active Directory domain controllers. Secondly, classic instances always use shared resources and can’t be configured on single-tenant hardware.

Manage IP Addressing with Virtual Private Clouds in AWS

The other type of instance is Virtual Private Cloud (VPC). An AWS VPC is the equivalent of an Azure virtual network (VNET), and any instances provisioned in VPCs automatically acquire static internal IP addresses. The only real difference between provisioning EC2-Classic and VPC instances is that for the latter, you must specify a subnet associated with a VPC, otherwise the provisioning process is identical.

Prerequisites

Before continuing, you’ll need to be familiar with the process of provisioning an EC2-Classic instance as described in Provision Windows Server in Amazon Web Services using PowerShell on the Petri IT Knowledgebase. The article includes information about setting up and configuring the AWS Tools for Windows PowerShell on your PC, how to get an image name for the –ImageId parameter of the New-EC2Instance cmdlet, and creating a key pair, which is required to retrieve the administrator account password.

Do I Have a Default VPC?

Depending on when your AWS account was created, you may have a default VPC in which you can launch instances. Unlike the default VPC, custom, non-default VPCs don’t have connectivity to the Internet by default, but this can be achieved with a little extra configuration. To determine if you have a default VPC:

  • Open a PowerShell console with local administrator privileges.
  • In the console, type get-ec2vpc and press ENTER.
  • Look for a VPC in the output where the IsDefault field is set to True, and make a note of the VPC’s VpcId.
  • Now type get-ec2subnet and press ENTER.
Checking if you have a default VPC in your AWS subscription. (Image Credit: Russell Smith)
Checking if you have a default VPC in your AWS subscription. (Image Credit: Russell Smith)

Check the output for subnets associated with your default VPC, and make a note of the SubnetId in the region you’d like to use.

Launch an Instance in the Default VPC

If you have a default VPC and are happy to use the private address range assigned to it, then you can skip the remainder of this article and run the code below to launch a new instance. All you need to do is replace subnet-915ab0f4 with the subnet ID you want to use.

Launching a new instance in the default VPC. (Image Credit: Russell Smith)
Launching a new instance in the default VPC. (Image Credit: Russell Smith)
A security group exists for the default VPC, but it doesn't permit inbound RDP traffic, so we'll need to add a rule to the group that permits inbound traffic from any IP address on TCP port 3389:
​
$ipPermissions = New-Object Amazon.EC2.Model.IpPermission –Property @{IpProtocol = “tcp”; FromPort = “3389”; ToPort = “3389”; IpRanges = $cidrBlocks}

Grant-EC2SecurityGroupIngress -GroupName “default” -IpPermissions @($ipPermissions)

Check in the AWS management console that the status checks for the new instance have completed, and then connect using RDP.

Create a New VPC and Internet Gateway

You will need to create a new, non-default VPC if your AWS subscription doesn’t have a default VPC. You’ll also need to create a new non-default VPC if you want to use an address space different from the one that’s configured for the default VPC. To create a non-default VPC, run the following PowerShell cmdlet, replacing 10.0.0.0/16 with the private address block that you’d like to assign to the VPC. Make a note of the VpcId in the output as we’ll need it later.

​
$vpcId = $newvpc.VpcId 
​
The next cmdlet is optional, but to assign instances with an external DNS hostname, we need to enable that feature for the new VPC:
Creating a non-default VPC. (Image Credit: Russell Smith)
Creating a non-default VPC. (Image Credit: Russell Smith)
To check if the new VPC is ready to use, type get-ec2vpc and press ENTER. Once the VPC is available, the State field will be set to available. Now we need to create an Internet gateway and attach it to the new VPC.

Create a New Subnet

For the purposes of this demonstration, let's create a subnet that uses the whole address space assigned to the VPC.
​
$subnetid = $newsubnetid.subnetid 
write-host $subnetid

Make a note of the Subnet ID in the command’s output. To check progress, type Get-EC2Subnet -SubnetIds $subnetid and press ENTER. Once the subnet is available, the State field will be set to available.

Configuring the new VPC with a subnet and Internet gateway. (Image Credit: Russell Smith)
Configuring the new VPC with a subnet and Internet gateway. (Image Credit: Russell Smith)

The default route table for the new subnet won’t contain a route to the Internet, so we need to create a custom route table with a route to the Internet.

​
$routetable = $newroutetable.routetableid 
New-EC2Route –routetableid $routetable –DestinationCidrBlock 0.0.0.0/0 –GatewayId $inetgate 
Register-EC2RouteTable -RouteTableId $routetable -SubnetId $subnetid
Adding a custom route table and routing to the Internet. (Image Credit: Russell Smith)
Adding a custom route table and routing to the Internet. (Image Credit: Russell Smith)

And finally, make sure there’s a public IP address available for when we launch the new instance:

Create a Security Group

A security group is needed to configure remote access to the VPC. In this example, I'll give all remote IP addresses (0.0.0.0/0) access on RDP port 3389.
​
$cidrBlocks = New-Object 'collections.generic.list[string]' $cidrBlocks.add("0.0.0.0/0")
$ipPermissions = New-Object Amazon.EC2.Model.IpPermission –Property @{IpProtocol = “tcp”; FromPort = “3389”; ToPort = “3389”; IpRanges = $cidrBlocks}

Grant-EC2SecurityGroupIngress -GroupId $groupid -IpPermissions @($ipPermissions)
Creating a new security group with inbound access on TCP port 3389. (Image Credit: Russell Smith)
Creating a new security group with inbound access on TCP port 3389. (Image Credit: Russell Smith)

Create a New Instance

Now we’re ready to launch a new VPC instance running Windows Server 2012 R2. The values for ImageId and KeyName have already been determined as per the instructions for launching an EC2-Classic instance in the article link above.

​
To get information about the status of the new instance, use the code below, replacing r-ee901de1 with the reservation ID from the output of the New-EC2Instance cmdlet.
​
$reservation.add("r-ee901de1")
$filter_reservation = New-Object Amazon.EC2.Model.Filter -Property @{Name = "reservation-id"; Values = $reservation}

(Get-EC2Instance -Filter $filter_reservation).Instances
Launching a new instance in the non-default VPC, and checking its status. (Image Credit: Russell Smith)
Launching a new instance in the non-default VPC, and checking its status. (Image Credit: Russell Smith)

Refer to the aforementioned article on the Petri IT Knowledgebase to learn how to retrieve the administrator password for the instance and connect using Remote Desktop. When you stop and restart the instance, notice that it retains the private IP address that it was initially assigned.