© Brian Beach, Steven Armentrout, Rodney Bozo, Emmanuel Tsouris 2019
B. Beach et al.Pro PowerShell for Amazon Web Serviceshttps://doi.org/10.1007/978-1-4842-4850-8_6

6. Advanced Instance Management

Brian Beach1 , Steven Armentrout2, Rodney Bozo3 and Emmanuel Tsouris4
(1)
Raleigh, NC, USA
(2)
Mountlake Terrace, WA, USA
(3)
Sterling, VA, USA
(4)
North Bend, WA, USA
 

In the last chapter, we learned how to create a Virtual Private Cloud (VPC) and specify our network topology. In this chapter, we are going to build on the VPC concepts by discussing how we can configure our instances in a VPC.

Before launching our instances, we first need to understand and configure the appropriate security groups. Security groups protect the Elastic Network Interface (ENI) attached to each of our instances, which is how they differ from the network access control lists (ACLs) discussed in Chapter 5.

In this chapter, we are going to learn how to create and manage rules, discuss the differences between security groups and traditional firewalls, and walk through the process of adding servers to a security group.

Once we have our security groups configured, we can launch our instances into one of our VPCs. We will discuss managing private IP addresses and assigning public IP addresses. Finally, we will wrap up the chapter with a look at creating, attaching, and managing Elastic Network Interfaces (ENIs).

Managing Security Groups

A security group is a stateful virtual firewall that protects the ENI attached to our instance. Traditionally, firewalls protect trusted networks from untrusted ones, creating security zones. For example, a firewall protects our private network from the Internet, but the machines on the private network may have no restrictions when communicating with others on that same private network.

In recent years, firewall costs have decreased dramatically, and we have begun to use them to protect much smaller segments of our networks. For example, we may use a firewall to separate the finance department from the rest of the organization or to protect a single application that hosts sensitive data.

Amazon EC2 security groups take this idea to the next level. An EC2 security group is similar to having a firewall in front of each network interface attached to our instances. No two instances can communicate without traversing that firewall, not even if they are in the same subnet or security group. In other words, the security group is part of our instances network interface, rather than part of the network itself. We can even attach multiple ENIs to our instances, each with multiple security groups associated with it!

Our security group allows us to control the flow of traffic to and from our instances. This includes controlling the type of traffic (e.g., TCP, UDP, or ICMP) allowed, port ranges to allow, and the source and destination addresses permitted to communicate.

We refer to the rules controlling traffic flow into our instances as ingress (inbound) rules, while the rules controlling the traffic flowing away from our instances are called egress (outbound) rules. When we define our security group rules later, we will see the terms ingress and egress used to describe these inbound and outbound rules, respectively.

Note

While there were security groups in EC2 Classic, you could only filter inbound traffic. With VPC, security groups filter both inbound and outbound traffic.

When we launch a new instance using PowerShell and do not specify a security group, the instance will be associated with our default security group. The default group allows an instance to communicate freely with any other instance in the same default security group. It does this because the security group itself is included in the inbound rules for all protocols over any port. In order to connect to our new instance using RDP, we will need to add an inbound (or ingress) rule allowing incoming connections over the RDP port (3389).

Caution

If you use the Create EC2 Instance Wizard in the AWS Management Console, it will give you an option to create a new security group for each instance or select an existing group. When choosing the default option to create a new group, the wizard sets an ingress rule allowing the port to be open to the world (0.0.0.0/0). You should change this rule before proceeding with the wizard, unless you truly want it open to the world. It is a good idea to only allow RDP or SSH connections from trusted IP addresses or network address ranges. So, be sure and restrict the inbound security group rules when using the wizard.

Displaying Security Groups

We can find our security groups by opening up the AWS Management Console, finding the EC2 service, and then looking for the Network & Security heading in the left pane. We will go ahead and start by looking at our default security group. In Figure 6-1 you can see that there is only one inbound rule.
../images/319650_2_En_6_Chapter/319650_2_En_6_Fig1_HTML.jpg
Figure 6-1

Inbound security group rules

Notice that this inbound rule allows all traffic, for all protocols, on any port from the security group sg-b3c79dd7, the same security group we are already looking at. In other words, this rule allows any instance in the security group to communicate with any other instance in the group. The security group blocks other inbound traffic by default.

Now we will look at the outbound rules in Figure 6-2. Again, there is only a single rule. This rule allows outbound traffic for any protocol, on any port, to any destination. Specifically, the security group allows all outbound traffic by default.
../images/319650_2_En_6_Chapter/319650_2_En_6_Fig2_HTML.jpg
Figure 6-2

Outbound security group rules

Unlike traditional firewall rules, we are not specifying individual instances by IP address. In fact, we might not even have an instance in our VPC yet. The security architect can define all of the rules necessary before adding instances. We can then give developers permission to add instances to security groups that have been predefined, and our developers will not have to wait for a change request approval to open the firewall ports later.

Returning to PowerShell, we can list the security groups using the Get-EC2SecurityGroup command .
Get-EC2SecurityGroup | Select-Object Description, GroupId | Format-Table
This command returns a list of security groups for all our VPCs.
Description                            GroupId
-----------                            -------
default VPC security group             sg-b3c79dd7

Now, take note of your specific GroupID for the default VPC. In the next section, we will use that GroupID to modify the security group.

Adding and Removing Rules

We are now going to add an inbound rule to our default VPC security group, allowing us to access our Windows instances with Remote Desktop Protocol (RDP).

To add inbound rules to the group, we use the now-common pattern of creating a .Net object to describe the rule and then call Grant-EC2SecurityGroupIngress .

Tip

The IpRanges property expects IP ranges specified with CIDR notation. While the FromPort and ToPort properties specify a range of destination ports, not the source and destination port.

RDP runs on TCP port 3389; therefore, the PowerShell command is the following:
$RDPRule = New-Object Amazon.EC2.Model.IpPermission
$RDPRule.IpProtocol='tcp'
$RDPRule.FromPort = 3389
$RDPRule.ToPort = 3389

We could use '0.0.0.0/0' and open up traffic to the whole world, but we should take a more secure and least access approach by narrowing down the range needed for our environment. To do this, we would use a specific IP address or subnet range for IpRanges.

For this next example, use your IP address to set the IP range. Replace the IP address in the following CIDR with your specific IP address:
$RDPRule.IpRanges = '99.86.37.184/32'

Tip

If you do not know your IP address, you can try searching Google for “My IP Address,” and Google will display your outbound IP address.

However, if we really needed to open up this rule to the whole world (or entire Internet), then we could use that special '0.0.0.0/0' value.
$RDPRule.IpRanges = '0.0.0.0/0'

Caution

Using '0.0.0.0/0' for the IpRanges property goes against numerous best practices since you are enabling all IP addresses on the Internet to access that port on your instance. For RDP and SSH, the recommendation is always to limit the exposure of these ports to only those who need the access. While opening up these ports may be needed for a short time during testing, troubleshooting, or development, when it comes to your production configuration, you will want to authorize only trusted IP addresses or subnet ranges to access these ports on your instances.

Now that we have defined our IpPermission object, we can create our ingress rule:

Note

Replace the security group ID in the following examples with your own specific security group ID.

Grant-EC2SecurityGroupIngress -GroupId 'sg-b3c79dd7' -IpPermissions $RDPRule
The process to add an outbound rule is almost identical, but we would use the Grant-EC2SecurityGroupEgress command . Note that there is no need to add outbound rules because the default group already allows all traffic outbound.
Grant-EC2SecurityGroupEgress -GroupId 'sg-b3c79dd7' -IpPermissions $RDPRule

We can easily create a security group using the New-EC2SecurityGroup command . For example, if we were developing a web application, we might create a security group allowing HTTP and HTTPS requests from the Internet.

Note

Replace the VPC ID in the following example with your own specific VPC ID.

$GroupId = New-EC2SecurityGroup -VpcId 'vpc-881acde9' -GroupName 'Web' -GroupDescription
     "Allows HTTP/S traffic from the internet."
New security groups allow all outbound traffic by default, but do not allow any inbound traffic. With this rule, we will allow any IP address to reach our instance using TCP over ports 80 (HTTP) and 443 (HTTPS):
$HTTPRule = New-Object Amazon.EC2.Model.IpPermission
$HTTPRule.IpProtocol='tcp'
$HTTPRule.FromPort = 80
$HTTPRule.ToPort = 80
$HTTPRule.IpRanges = '0.0.0.0/0'
$HTTPSRule = New-Object Amazon.EC2.Model.IpPermission
$HTTPSRule.IpProtocol='tcp'
$HTTPSRule.FromPort = 443
$HTTPSRule.ToPort = 443
$HTTPSRule.IpRanges = '0.0.0.0/0'
Grant-EC2SecurityGroupIngress -GroupId $GroupId -IpPermissions $HTTPRule, $HTTPSRule

We can also remove inbound and outbound rules using Revoke-EC2SecurityGroupIngress and Revoke-EC2SecurityGroupEgress , respectively. For example, we might want to remove the default rule that allows all outbound traffic from our web group.

Unlike ACLs, security groups are stateful, so we do not need rules explicitly allowing return traffic. Our security group knows that the originating HTTP request is going to have a corresponding response and will automatically allow it. We only need the outbound rule when the instance is acting as the client, surfing the Web, or downloading software. For our new group, we want to prevent any unauthorized outbound traffic from our instance. Therefore, we will not need the default outbound rule and will remove it.
$Rule = New-Object Amazon.EC2.Model.IpPermission
$Rule.IpProtocol='-1'
$Rule.IpRanges = '0.0.0.0/0'
Revoke-EC2SecurityGroupEgress -GroupId $GroupId -IpPermissions $Rule

Note

We used an IpProtocol of "-1", which means all protocols. We can create security group rules by either specifying the name or IP protocol number, for example, ICMP (protocol 1), TCP (protocol 6), and UDP (protocol 17). For convenience, we can use the name or the number for these common protocols. However, for less common protocols, we must specify the protocol number.

As we saw in Figure 6-1, we can create rules based on other security groups. For example, imagine our web application has an SQL database. The web servers must be able to access the SQL Server. However, the number of web servers will change throughout the day depending on the load.

For this scenario, we will create a new SQL group for our SQL Servers.

Note

Replace the VPC and Security Group IDs in the following example with your own specific IDs.

$GroupId = New-EC2SecurityGroup -VpcId vpc-881acde9 -GroupName SQL -GroupDescription
     "Allows SQL Queries from the web server."
Next, we need to create a UserIdGroupPair object to hold our security group ID.
$WebGroup = New-Object Amazon.EC2.Model.UserIdGroupPair
$WebGroup.GroupId = 'sg-0c3b9863'
Then we will grant access to any instance in the web security group we created. Since we are using Microsoft SQL Server, we will specify TCP port 1433.
$SQLRule = New-Object Amazon.EC2.Model.IpPermission
$SQLRule.IpProtocol='tcp'
$SQLRule.FromPort = 1433
$SQLRule.ToPort = 1433
$SQLRule.UserIdGroupPair = $WebGroup
Finally, we pass the GroupId and $SQLRule to Grant-EC2SecurityGroupIngress in order to apply the rule to the security group.
Grant-EC2SecurityGroupIngress -GroupId $GroupId -IpPermissions $SQLRule

With this new security group in place, all we have to do is add new web servers to our web security group and AWS will allow our instances to communicate with the SQL Server. When launching new instances, there is no need to update the security group rules.

Before we close this section, we should look at a scenario where we might want to create an ICMP rule, for example, being able to ping all of our instances from outside of our VPC.

Caution

Allowing ping from outside a VPC is not recommended and poses a security risk, but is covered here to illustrate how ICMP rules work.

Say we like throwing caution to the wind and decide to add a new rule to our default security group allowing ICMP Echo Request messages from anywhere. ICMP uses message types rather than ports. To enable an ICMP message, you use an IpProtocol of "icmp" and then put the message type in FromPort. For example, an ICMP Echo Request is message type 8. Note that the ToPort is not used and should be set to -1.

In this section, we discussed security groups and security group rules. We learned how a security group is similar in concept to a firewall, but in reality, the rules apply to an instances network interface rather than the network segment. Finally, we looked at how we can add or remove various security group rules to fit the needs of our applications. Now, we will move on to launching an instance into our VPC.

Launching Instances into a VPC

VPC gives us considerable control over network configuration of our EC2 instances. We are going to start by launching a new instance into the VPC we created in Chapter 5. If you have not created a VPC, use the script from Exercise 5.1.

We are going to begin by looking at the Launch Instance Wizard. From the Amazon EC2 Console, when we click the Launch Instance button, it takes us into the Launch Instance Wizard. On the third step, Configure Instance Details, if we select a specific subnet, a new Network Interfaces section appears. Notice the network configuration options shown in Figure 6-3. This section allows us add additional network interfaces to our instance. It also allows us to choose a subnet and specify an IP address. In addition, we can add secondary IP addresses to our instance.
../images/319650_2_En_6_Chapter/319650_2_En_6_Fig3_HTML.jpg
Figure 6-3

Network options in the Launch Instances Wizard

Launching an instance into our VPC with PowerShell is almost how we launched an instance in Chapter 3. Once again, we will use the New-EC2Instance command , but this time we add one new parameter: the ID of the subnet to launch our instance in. Note that we can only connect with RDP to instances in a public subnet, so we will use a public subnet here.

Note

Key pair names are case sensitive.

$AMI = Get-EC2ImageByName -Name 'WINDOWS_2016_BASE'
New-EC2Instance -ImageId $AMI[0].ImageId -KeyName 'MyKey' -InstanceType 't2.micro' -SubnetId subnet-7922ea18

That is all it takes to launch an instance into our VPC. The instance we just launched has a random public IP address assigned by EC2, along with a randomly assigned private IP address for use within our VPC. This private IP falls within the CIDR range of the subnet we specified and is assigned using DHCP.

If we need to control the private IP address of the instance, we can specify an IP address to set at launch, using the PrivateIPAddress parameter . This is similar to setting a static DHCP address (or DHCP reservation).

Note

Your private IP range might be different.

$AMI = Get-EC2ImageByName -Name 'WINDOWS_2016_BASE'
New-EC2Instance -ImageId $AMI[0].ImageId -KeyName 'MyKey' -InstanceType 't2.micro' -SubnetId subnet-7922ea18 -PrivateIpAddress 192.168.1.5

Note that the IP address must fall within the CIDR range configured within the subnet and is immutable. We can set it when launching a new instance, but cannot change it once the instance is running. Also, remember that the first four IP addresses and the last IP address of each subnet are reserved.

Of course, we can also select existing security groups when launching an instance. As we can see in Figure 6-4, when we choose to select an existing security group, we have the option of selecting more than one group. For example, we can associate our new instance to the web and default groups that we discussed earlier. Our web group allows HTTP traffic and our default group allows RDP.
../images/319650_2_En_6_Chapter/319650_2_En_6_Fig4_HTML.jpg
Figure 6-4

Security groups in the Launch Instance Wizard

To add an instance to a security group using PowerShell, we use the SecurityGroupId parameter and pass an array of security group IDs.
$AMI = Get-EC2ImageByName -Name 'WINDOWS_2016_BASE'
New-EC2Instance -ImageId $AMI[0].ImageId -KeyName 'MyKey' -InstanceType 't2.micro' -SubnetId subnet-7922ea18 -SecurityGroupId sg-b3c79dd7, sg-07b5a276da8f0588c

As we have just seen, launching instances into a specific VPC gives us the ability to control the private network configuration of our instances. We launched an instance into our public subnet and enabled HTTP and RDP traffic from the Internet using security groups.

Subnets and Public IP Addresses

For instances to be public, we launch them in a public subnet (one with a route to the Internet gateway), and it must have a public IP address associated with it. Our default VPC already has both an Internet gateway and subnets that automatically map a public IP address to our EC2 instance when we launch it.

We can use this public IP address to connect to our instances with RDP. However, when we stop our instance and restart it, this auto-assigned public IP address will change. The public IP address changes because EC2 randomly assigns it when we start our instance. We can look at any of our running EC2 instances and their PublicIpAddress by examining the RunningInstance property of the Get-EC2Instance cmdlet:
$RunningInstances = (Get-EC2Instance).RunningInstance
$RunningInstances.PublicIpAddress

EC2 knows when to assign a public IP address because subnets have a property, MapPublicOnLaunch. This property tells EC2 if it should auto-assign a public IP address to instances when launched in this subnet. We can also create subnets with this property set to false, which would result in our instances not getting a public IP address assigned. This is useful for our database servers, which only need to talk to our frontend web servers. However, keep in mind, to RDP (or SSH) to instances with only private IP addresses, we must use a bastion host (or jump box) that has a public IP and can talk to our instance via subnet, VPC, and security group configuration.

To view our subnets and see which ones have this property assigned, we can use Get-EC2Subnet and look at the MapPublicOnLaunch property:

Get-EC2Subnet | Select-Object SubnetId, MapPublicIpOnLaunch

We can see from the output which subnets have the MapPublicIpOnLaunch property set to true.

SubnetId                  MapPublicIpOnLaunch
--------                  -------------------
subnet-600e232a                True
subnet-842dcded                True
subnet-59858621                True
When launching a new instance, even if our subnet has the MapPublicOnLaunch property set to true, we can still choose whether to auto-assign it a public IP or not. We do that by calling New-EC2Instance and specify $true or $false for the AssociatePublicIp property:
$AMI = Get-EC2ImageByName -Name 'WINDOWS_2016_BASE'
New-EC2Instance -ImageId $AMI[0].ImageId -KeyName 'MyKey' -InstanceType 't2.micro' -SubnetId subnet-7922ea18 -AssociatePublicIp $false

As we talked about before, the public IP address will change when our instance stops and starts again. There will be times when we need a public IP address that does not change, for example, when we want to be able to stop and start an instance, but ensure it always uses the same IP address for RDP, or is associated with a domain name. For these scenarios, we can use an elastic IP address.

Managing Elastic IP Addresses

For cases when a random public IP address is not what we need, but would like to associate a fixed public IP address with our instance, we have the ability to create an Elastic IP (EIP) address.

AWS uses Network Address Translation (NAT) to map traffic between the private IP and the EIP. The NAT is implemented in the Internet gateway.

To create an EIP address, we use New-EC2Address and specify VPC for the Domain property, which tells EC2 that we are going to use the EIP in a VPC rather than with EC2 Classic. For example:
$EIP = New-EC2Address -Domain vpc

EC2 will randomly assign an EIP. In order to associate the EIP to our instance, we use the Register-EC2PrivateIpAddress cmdlet .

Note

Replace InstanceId with your own Instance ID.

Register-EC2Address -InstanceId i-1234567890 -AllocationId $EIP.AllocationId

Logging Into a VPC Instance

At this point, we have learned that we can open the AWS Web Console, decrypt our password using our key pair, and click the connect link to log into our instance using Remote Desktop. If this does not sound familiar, jump back to Chapter 3 and review.

If you have any issues, walk through these troubleshooting steps:
  1. 1.

    Check your VPC, and make sure it has an Internet gateway.

     
  2. 2.

    The public subnet has a route to the Internet gateway.

     
  3. 3.

    The subnet has an ACL allowing RDP in from the Internet.

     
  4. 4.

    The subnet has an ACL allowing a reply in from the ephemeral ports.

     
  5. 5.

    The instance is in a public subnet.

     
  6. 6.

    The default security group allows RDP in from your computer or the Internet.

     
  7. 7.

    The instance is a member of the default security group.

     
  8. 8.

    The instance has either a public IP or an EIP address assigned.

     

VPC is a powerful feature that gives you a lot of control over your environment, but as a result, it can also be complicated. If you run into trouble seting up new VPCs initially,  don’t worry, you will get very good at diagnosing issues as you learn more about VPCs.

It is common to reassign an EIP as part of a disaster recovery plan. If the EIP is already associated with another instance, EC2 returns an error when we try to reassign it. We can avoid this error by passing $true to the AllowReassign attribute, which allows us to reassign an EIP that is assigned to another instance.
Register-EC2Address -InstanceId i-1234567890 -AllocationId $EIP.AllocationId
     -AllowReassociation:$true

We can remove the EIP address from an instance using the Unregister-EC2Address command. First, we get a reference to the EIP using Get-EC2Address. Then, we call Unregister-EC2Instance and pass the association ID.

Note

Specify the public IP for your specific EIP.

$EIP = Get-EC2Address -PublicIp '54.208.194.131'
Unregister-EC2Address -AssociationId $EIP.AssociationId

Caution

AWS charges a small hourly fee for any EIP that is not associated with a running instance.

If you no longer need an EIP or intend to stop your instance for a while, consider disassociating the EIP by using the Remove-EC2Address command to avoid paying any extra fees.
$EIP = Get-EC2Address -PublicIp '54.208.194.131'
Remove-EC2Address -AllocationId $EIP.AllocationId -Force

Now that we know how to manage our IP addresses, we will look more closely at private IP addresses. As you will see in the next section, spending a little extra time planning can make your application easier to manage.

Managing Private IPs

In the previous sections, we referred to the private IP as an attribute of an instance. This was oversimplification. In reality, an instance can have many network interfaces and each interface can have many IP addresses. We will look at adding network interfaces in the next section. For now, we will focus on IP addresses.

When AWS displays the private IP address of an instance, we see the first IP address of the first network interface. Earlier, we discussed we could not change the private IP address of an instance. Specifically, this means we can not change the first IP address of a network interface. What we can do, however, is add additional IP addresses to an interface.

One common use is for disaster recovery. We could easily move a secondary IP between instances. If we have a critical application that relies on a single instance, we might want to keep a second instance on standby. If we detect a failure on our primary instance, we could then move the IP address to a secondary instance.

To add a secondary IP address to an instance, first we must find the network interface. All of the network interfaces are available from the NetworkInterfaces property of the Instance object.
$Reservation = Get-EC2Instance -Instance i-b67722cd
$Instance = $Reservation.RunningInstance[0]
$ENI = $Instance.NetworkInterfaces[0]

Now that we have the network interface, we can use the Register-EC2PrivateIpAddress method to add a secondary IP address. For example:

Note

When specifying a private IP address, you must use a valid IP address within the subnet range associated with your ENI.

Register-EC2PrivateIpAddress -NetworkInterfaceId $ENI.NetworkInterfaceId
     -PrivateIpAddresses '192.168.1.6'

Unfortunately, DHCP will not configure secondary IP addresses. In order to use secondary IPs, you must disable DHCP and configure the network interface manually. Luckily, there are PowerShell commands for this. The following example will configure an instance with a static network configuration.

Note

Log in to the instance to configure and execute these commands locally.

#Disable DHCP
Set-NetIPInterface -InterfaceAlias 'Ethernet' -Dhcp Disabled
#Configure the primary IP
New-NetIPAddress -InterfaceAlias 'Ethernet' -IPAddress '192.168.1.5' -PrefixLength 24
     –DefaultGateway '192.168.1.1'
#Configure DNS
Set-DnsClientServerAddress -InterfaceAlias 'Ethernet' -ServerAddresses '192.168.0.2'
#Add the secondary IP address
New-NetIPAddress -InterfaceAlias 'Ethernet' -IPAddress '192.168.1.6' -PrefixLength 24

Caution

Static network configurations can be dangerous. You must be careful to ensure that the IP addresses assigned within Windows match those assigned in AWS. Remember that EC2 implements security groups at the network interface attached to the instance. This means that if you assign a different IP address, the security groups may not allow traffic to flow to the instance. Taking a snapshot before manually configuring the security groups is highly recommended to give yourself a way to back out any breaking changes.

Now that we know how to manage IP addresses, let’s take a closer look at the network interfaces.

Managing Elastic Network Interfaces

As we have covered so far, an EC2 instance can have multiple network interfaces. Amazon calls these interfaces Elastic Network Interfaces (ENIs). The maximum number of interfaces varies with the instance type. Unlike secondary IP addresses, we can assign different subnets to each network interface. See Figure 6-5.
../images/319650_2_En_6_Chapter/319650_2_En_6_Fig5_HTML.png
Figure 6-5

A multihomed instance

Every instance has at least one ENI, but we can add additional interfaces when launching an instance. Remember that the SubnetId, PrivateIpAddress, and SecurityGroupId attributes of the New-EC2Instance command act on the default ENI. We cannot use these parameters to launch instances with multiple interfaces.

If we want to add multiple interfaces to an instance, we would use a .Net object to describe them. Then, we pass an array of interfaces to the New-EC2Instance command using the NetworkInterfaces attribute . Each ENI has its own IP address and can be in a different subnet. In addition, each ENI can be in a different set of security groups. To launch the instance pictured in Figure 6-5, I used the following PowerShell script:
$ENI0 = New-Object Amazon.EC2.Model.InstanceNetworkInterfaceSpecification
$ENI0.PrivateIpAddress = '192.168.1.10'
$ENI0.SubnetId = 'subnet-7922ea18'
$ENI0.DeviceIndex = 0
$ENI0.Groups.Add('sg-e775d688')
$ENI1 = New-Object Amazon.EC2.Model.InstanceNetworkInterfaceSpecification
$ENI1.PrivateIpAddress = '192.168.2.10'
$ENI1.SubnetId = 'subnet-2f22ea4e'
$ENI1.DeviceIndex = 1
$ENI1.Groups.Add('sg-e775d688')
$AMI = Get-EC2ImageByName -Name 'WINDOWS_2016_BASE'
New-EC2Instance -ImageId $AMI[0].ImageId -KeyName 'MyKey' -InstanceType 't2.micro' -NetworkInterfaces $ENI0, $ENI1
Unfortunately, the reservation returned from New-EC2Instance does not include the network interfaces. The command returns asynchronously, and it takes a few seconds for the interfaces to attach. To see the details, we will have to wait a few seconds and then run Get-EC2Instance to refresh our copy of the metadata. For example:
$Reservation = Get-EC2Instance -Instance i-b67722cd
$Instance = $Reservation.RunningInstance[0]
$Instance.NetworkInterfaces | Format-Table
This command returns
NetworkInterfaceId SubnetId        MacAddress       PrivateIpAddress
------------------ --------------- ---------------- ----------------
eni-cc478fad       subnet-7922ea18 2a:5b:de:70:8... 192.168.1.10
eni-cf478fae       subnet-2f22ea4e 2a:5b:de:7b:8... 192.168.2.10
If we would like to add an interface to an existing instance, we can. First, we create a new ENI using the New-EC2NetworkInterface command . Then, attach it to an instance using the Add-EC2NetworkInterface command. For example:
$NIC = New-EC2NetworkInterface -SubnetId subnet-1619ce77 -PrivateIpAddress 192.168.1.15
     -GroupId sg-d23596bd
Add-EC2NetworkInterface -NetworkInterfaceId $NIC.NetworkInterfaceId -InstanceId i-c829b8b3
     -DeviceIndex 1
If we want to remove an ENI, we detach it using Dismount-EC2NetworkInterface . First, we get the attachment ID and then pass that to the Dismount-EC2NetworkInterface command .
$NIC = Get-EC2NetworkInterface eni-c00ad7a1
Dismount-EC2NetworkInterface -AttachmentId $NIC.Attachment.AttachmentId

There are a few reasons that we might choose to add multiple interfaces to a server. On physical machines, we often include multiple interfaces to increase reliability and bandwidth. In EC2, and all virtual machine environments, the interfaces all share the same physical interface in the hypervisor. Therefore, there is no real reliability or bandwidth gain.

Another reason for multiple interfaces is to allow a machine to span multiple subnets. Again, there are multiple reasons we may choose this. One common practice is to have a management subnet used for administration and backup that is separate from the primary subnet. Again, this is likely not valuable with EC2. Security groups allow us to control administrative traffic, and backups do not use our private network.

We might choose to span subnets to allow our instance to route traffic from one subnet to another. We could launch an application firewall that does traffic inspection or data loss prevention. The instance would have an interface in the private and public subnets, and we would configure the route table to route all Internet traffic through the application firewall.

Note that if we want use an instance to route traffic, we first must disable the source/destination check. Typically, AWS will discard any traffic sent to an instance where the instance’s IP address is not the source or destination. In order for the instance to forward traffic, we must disable this check. (We will do this in Exercise 6-1.)
Edit-EC2NetworkInterfaceAttribute -NetworkInterfaceId eni-c00ad7a1 -SourceDestCheck:$false

One other reason to use multiple interfaces is disaster recovery. Just as you might move a secondary IP from the primary to standby instance, you could move the ENI. There are two advantages of moving an ENI rather than a secondary IP. First, route tables refer to the interface rather than IP. If your disaster recovery plan involves an instance that is routing traffic, you should use an ENI. Second, we can use DHCP to configure multiple ENIs, but not multiple IP addresses on the same interface.

At this point, we know how to manage security groups, private IPs, EIPs, and ENIs. Finally, let us test our knowledge with a couple of examples.

Exercise 6.1: Managing Private Instances

In Chapter 5, we created a private subnet. Remember that instances in a private subnet are not accessible from the Internet. While this is a good security practice, it introduces some new challenges.

The obvious issue is how we administer the private instances. How do we log in to a private instance to configure it, debug issues, and so on? One way to address this is to launch a Remote Desktop Gateway (RDGW) server in the public subnet and use it as a proxy to access the private instances.

In addition, the private instances are not able to access the Internet. This means that they cannot connect to the Internet resources to get patches, antivirus definitions, and so on. A common solution to this problem is to launch a proxy server in the public subnet and configure the route table to route traffic from the private subnet through this proxy.

Figure 6-6 describes the complete solution. We will launch two new instances in a new subnet. Administrative traffic comes in through the RDP gateway, and outbound web traffic goes out through the NAT gateway.
../images/319650_2_En_6_Chapter/319650_2_En_6_Fig6_HTML.png
Figure 6-6

VPC with a NAT gateway and RDP gateway

This example is, by far, the most complicated example in the book. Don’t worry if you have to read through it more than once. We could have simply put all the instances in a public subnet or left the ACLs and security groups open to all traffic. However, this is a common pattern for a real-world enterprise VPC architecture. These security controls are very likely to please any enterprise security architect.

Let’s begin by altering our network configuration. This exercise assumes you already have a VPC that we can use. If you would like to create a new VPC, and leave your existing ones alone, use Exercise 5.1 to create one. We are going to add a new public subnet to host our resources (the NAT and RDP gateways) with the CIDR block 192.168.0.0/24.

First, we define a few variables including the VPCID, CIDR block, and the AMIs to use.
param
(
    [string][parameter(mandatory=$true)]$VPCID,
    [string][parameter(mandatory=$false)]$ResourcesSubnetCIDR = '192.168.0.0/24',
    [string][parameter(mandatory=$false)]$NAT_AMI,
    [string][parameter(mandatory=$false)]$RDP_AMI
)
If the user does not provide an AMI, let’s assume they want the default NAT and Windows Server 2016.
If([System.String]::IsNullOrEmpty($NAT_AMI)){ $NAT_AMI = (Get-EC2ImageByName -Name 'VPC_NAT')[0].ImageId}
If([System.String]::IsNullOrEmpty($RDP_AMI)){ $RDP_AMI = (Get-EC2ImageByName -Name 'WINDOWS_2016_BASE')[0].ImageId}
Next, we choose an availability zone. We can simply get the first availability zone in the region.
$VPC = Get-EC2VPC -VpcID $VPCID
$AvailabilityZones = Get-EC2AvailabilityZone
$AvailabilityZone = $AvailabilityZones[0].ZoneName
Now we create the resources subnet, which will use a route table configured just like the public subnet that we created in Chapter 5.
$ResourcesSubnet = New-EC2Subnet -VpcId $VPCID -CidrBlock $ResourcesSubnetCIDR
     -AvailabilityZone $AvailabilityZone
$ResourcesRouteTable = New-EC2RouteTable -VpcId $VPC.VpcId
$VPCFilter = New-Object Amazon.EC2.Model.Filter
$VPCFilter.Name = 'attachment.vpc-id'
$VPCFilter.Value = $VPCID
$InternetGateway = Get-EC2InternetGateway -Filter $VPCID
New-EC2Route -RouteTableId $ResourcesRouteTable.RouteTableId -DestinationCidrBlock
     '0.0.0.0/0' -GatewayId $InternetGateway.InternetGatewayId
Register-EC2RouteTable -RouteTableId $ResourcesRouteTable.RouteTableId -SubnetId
     $ResourcesSubnet.SubnetId
Next, we need to configure the ACLs for our new subnet. First, we will allow traffic in to configure the NAT and RDP gateway servers. The NAT instance is running Linux and requires SSH port 22. The RDP instance is running Windows and requires RDP port 3389. In addition, we need to remember to open the ephemeral ports to allow the return traffic.
$ACL = New-EC2NetworkAcl -VpcId $VPCID
New-EC2NetworkAclEntry -NetworkAclId $ACL.NetworkAclId -RuleNumber 100 -CidrBlock
     '0.0.0.0/0' -Egress $false -PortRange_From 22 -PortRange_To 22 -Protocol 6
     -RuleAction Allow
New-EC2NetworkAclEntry -NetworkAclId $ACL.NetworkAclId -RuleNumber 110 -CidrBlock
      '0.0.0.0/0' -Egress $false -PortRange_From 3389 -PortRange_To 3389 -Protocol 6
     -RuleAction Allow
New-EC2NetworkAclEntry -NetworkAclId $ACL.NetworkAclId -RuleNumber 120 -CidrBlock
     '0.0.0.0/0' -Egress $true  -PortRange_From 49152 -PortRange_To 65535 -Protocol 6
     -RuleAction Allow
Now, we need to pass through the NAT gateway to download patches over HTTP and HTTPS. Therefore, we need to allow traffic on 80 and 443 from our private subnets, through the resources subnet, and out to the Internet.
New-EC2NetworkAclEntry -NetworkAclId $ACL.NetworkAclId -RuleNumber 200 -CidrBlock
     $VPC.CidrBlock -Egress $false -PortRange_From 80 -PortRange_To 80 -Protocol 6
     -RuleAction Allow
New-EC2NetworkAclEntry -NetworkAclId $ACL.NetworkAclId -RuleNumber 210 -CidrBlock
     $VPC.CidrBlock -Egress $false -PortRange_From 443 -PortRange_To 443 -Protocol 6
     -RuleAction Allow
New-EC2NetworkAclEntry -NetworkAclId $ACL.NetworkAclId -RuleNumber 230 -CidrBlock
     $VPC.CidrBlock -Egress $true -PortRange_From 49152 -PortRange_To 65535 -Protocol 6
     -RuleAction Allow
New-EC2NetworkAclEntry -NetworkAclId $ACL.NetworkAclId -RuleNumber 240 -CidrBlock
     '0.0.0.0/0' -Egress $true -PortRange_From 80 -PortRange_To 80 -Protocol 6
     -RuleAction Allow
New-EC2NetworkAclEntry -NetworkAclId $ACL.NetworkAclId -RuleNumber 250 -CidrBlock
     '0.0.0.0/0' -Egress $true -PortRange_From 443 -PortRange_To 443 -Protocol 6
     -RuleAction Allow
New-EC2NetworkAclEntry -NetworkAclId $ACL.NetworkAclId -RuleNumber 260 -CidrBlock
     '0.0.0.0/0' -Egress $false -PortRange_From 49152 -PortRange_To 65535 -Protocol 6
     -RuleAction Allow
We will also need to allow RDP traffic in through our RDP gateway. The RDP gateway creates an SSL tunnel (port 443) from the client to the gateway. Then it uses RDP (port 3389) from the gateway to the server. Again, we need to remember the ephemeral ports.
New-EC2NetworkAclEntry -NetworkAclId $ACL.NetworkAclId -RuleNumber 300 -CidrBlock
     '0.0.0.0/0' -Egress $false -PortRange_From 443 -PortRange_To 443 -Protocol 6
     -RuleAction Allow
New-EC2NetworkAclEntry -NetworkAclId $ACL.NetworkAclId -RuleNumber 310 -CidrBlock
     '0.0.0.0/0' -Egress $true -PortRange_From 49152 -PortRange_To 65535 -Protocol 6
     -RuleAction Allow
New-EC2NetworkAclEntry -NetworkAclId $ACL.NetworkAclId -RuleNumber 320 -CidrBlock
     $VPC.CidrBlock -Egress $true -PortRange_From 3389 -PortRange_To 3389 -Protocol 6
     -RuleAction Allow
New-EC2NetworkAclEntry -NetworkAclId $ACL.NetworkAclId -RuleNumber 330 -CidrBlock
     $VPC.CidrBlock -Egress $false -PortRange_From 49152 -PortRange_To 65535 -Protocol 6
     -RuleAction Allow
Next, we have to create security groups to protect the instances we are going to launch in the resources subnet. First, we will create a security group for administration. This will allow SSH port 22 and RDP port 3389 to configure the servers.
$RDPRule = New-Object Amazon.EC2.Model.IpPermission
$RDPRule.IpProtocol='tcp'
$RDPRule.FromPort = 3389
$RDPRule.ToPort = 3389
$RDPRule.IpRanges = '0.0.0.0/0'
$SSHRule = New-Object Amazon.EC2.Model.IpPermission
$SSHRule.IpProtocol='tcp'
$SSHRule.FromPort = 22
$SSHRule.ToPort = 22
$SSHRule.IpRanges = '0.0.0.0/0'
$AdminGroupId = New-EC2SecurityGroup -VpcId $VPCID -GroupName 'Admin' -GroupDescription
     "Allows RDP and SSH for configuration."
Grant-EC2SecurityGroupIngress -GroupId $AdminGroupId -IpPermissions $RDPRule, $SSHRule
Second, we will create a security group to allow HTTP and HTTPS traffic from anywhere in the VPC to the NAT gateway.
$HTTPRule = New-Object Amazon.EC2.Model.IpPermission
$HTTPRule.IpProtocol='tcp'
$HTTPRule.FromPort = 80
$HTTPRule.ToPort = 80
$HTTPRule.IpRanges = $VPC.CidrBlock
$HTTPSRule = New-Object Amazon.EC2.Model.IpPermission
$HTTPSRule.IpProtocol='tcp'
$HTTPSRule.FromPort = 443
$HTTPSRule.ToPort = 443
$HTTPSRule.IpRanges = $VPC.CidrBlock
$NatGroupId = New-EC2SecurityGroup -VpcId $VPCID -GroupName 'NATGateway'
     -GroupDescription "Allows HTTP/S from the VPC to the internet."
Grant-EC2SecurityGroupIngress -GroupId $NatGroupId -IpPermissions $HTTPRule, $HTTPSRule
Third, we will create a security group to allow RDP over SSL from the Internet to the RDP gateway.
$RDPRule = New-Object Amazon.EC2.Model.IpPermission
$RDPRule.IpProtocol='tcp'
$RDPRule.FromPort = 443
$RDPRule.ToPort = 443
$RDPRule.IpRanges = '0.0.0.0/0'
$RdpGroupId = New-EC2SecurityGroup -VpcId $VPCID -GroupName 'RDPGateway'
     -GroupDescription "Allows RDP over HTTPS from the internet."
Grant-EC2SecurityGroupIngress -GroupId $RdpGroupId -IpPermissions $RDPRule
Fourth, we must allow RDP traffic from the RDP gateway to the instances in the default subnet.
$VPCFilter = New-Object Amazon.EC2.Model.Filter
$VPCFilter.Name = 'vpc-id'
$VPCFilter.Value = $VPCID
$GroupFilter = New-Object Amazon.EC2.Model.Filter
$GroupFilter.Name = 'group-name'
$GroupFilter.Value = 'default'
$DefaultGroup = Get-EC2SecurityGroup -Filter $VPCFilter, $GroupFilter
$RDPGatewayGroup = New-Object Amazon.EC2.Model.UserIdGroupPair
$RDPGatewayGroup.GroupId = $RdpGroupId
$RDPRule = New-Object Amazon.EC2.Model.IpPermission
$RDPRule.IpProtocol='tcp'
$RDPRule.FromPort = 3389
$RDPRule.ToPort = 3389
$RDPRule.UserIdGroupPair = $RDPGatewayGroup
Grant-EC2SecurityGroupIngress -GroupId $DefaultGroup.GroupId -IpPermissions $RDPRule
Now we associate the resource subnet we created with the new ACL.
$VPCFilter = New-Object Amazon.EC2.Model.Filter
$VPCFilter.Name = 'vpc-id'
$VPCFilter.Value = $VPCID
$DefaultFilter = New-Object Amazon.EC2.Model.Filter
$DefaultFilter.Name = 'default'
$DefaultFilter.Value = 'true'
$OldACL = (Get-EC2NetworkAcl -Filter $VPCFilter, $DefaultFilter )
$OldAssociation = $OldACL.Associations | Where-Object { $_.SubnetId -eq
     $ResourcesSubnet.SubnetId }
$NoEcho = Set-EC2NetworkAclAssociation -AssociationId $
     OldAssociation.NetworkAclAssociationId -NetworkAclId $ACL.NetworkAclId
Next, we launch a NAT gateway to serve as an outbound proxy. A NAT gateway is simply a Red Hat Linux instance that forwards traffic to the Internet. There are numerous other proxies available in the AWS marketplace that can do advanced inspection, but they are all relatively expensive. The NAT gateway is offered by Amazon as an inexpensive (you pay only for the instance) solution.
$Reservation = New-EC2Instance -ImageId $NAT_AMI -KeyName 'MyKey' -InstanceType
     't2.micro' -SubnetId $ResourcesSubnet.SubnetId
$NATInstance = $Reservation.RunningInstance[0]
$Tag = New-Object Amazon.EC2.Model.Tag
$Tag.Key = 'Name'
$Tag.Value = 'NATGateway'
New-EC2Tag -ResourceId $NATInstance.InstanceID  -Tag $tag
We must wait for the instance to boot before moving on. This is different from the exercise in Chapter 3. Here we are just waiting for the instance to boot. We do not have to wait for the initialization to complete and the password to be available.
Start-Sleep -s 60
While ((Get-EC2InstanceStatus -InstanceId $NATInstance.InstanceID).InstanceState.name
     -ne 'running')
{
    Start-Sleep -s 60
    $NATInstance = (Get-EC2Instance -Instance $NATInstance.InstanceID).RunningInstance[0]
}
In order for the NAT instance to route traffic, we need to disable the source/destination check on the network interface. Usually an instance must be either the source or destination of any traffic that it sends or receives. To disable the check, we use the Edit-EC2NetworkInterfaceAttribute command.
$NIC = $NATInstance.NetworkInterfaces[0]
Edit-EC2NetworkInterfaceAttribute -NetworkInterfaceId $NIC.NetworkInterfaceId
     -SourceDestCheck:$false
Next, we assign the instance an EIP. Remember that the Internet gateway uses NAT to translate private IP addresses to Internet IP addresses. Therefore, traffic from an instance in a private subnet to the Internet gets translated twice. First, the NAT gateway translates the private IP of the sender to its own private IP. Second, the Internet gateway translates from the private IP of the NAT gateway to its corresponding EIP.
$EIP = New-EC2Address -Domain 'vpc'
Register-EC2Address -InstanceId $NATInstance.InstanceID -AllocationId $EIP.AllocationId
Finally, we find the Main route table for the VPC and set the default route to the NAT gateway. I assume here that all of your private subnets are using the Main route table.
#Find the Main Route Table for this VPC
$VPCFilter = New-Object Amazon.EC2.Model.Filter
$VPCFilter.Name = 'vpc-id'
$VPCFilter.Value = $VPC.VpcId
$IsDefaultFilter = New-Object Amazon.EC2.Model.Filter
$IsDefaultFilter.Name = 'association.main'
$IsDefaultFilter.Value = 'true'
$MainRouteTable = (Get-EC2RouteTable -Filter $VPCFilter, $IsDefaultFilter)
#Replace the default route with reference to the NAT gateway
$MainRouteTable.Routes | Where-Object { $_.DestinationCidrBlock -eq '0.0.0.0/0'} | %
     {Remove-EC2Route -RouteTableId $MainRouteTable.RouteTableId -DestinationCidrBlock $_.DestinationCidrBlock -Force}
New-EC2Route -RouteTableId $MainRouteTable.RouteTableId  -DestinationCidrBlock
     '0.0.0.0/0' -InstanceId $NATInstance.InstanceId

That takes care of the outbound traffic. Instances on the private subnets will route their traffic out through the NAT gateway, which will, in turn, route it through the Internet gateway. Now let’s move on to the RDP gateway.

Remote Desktop Gateway is a Windows feature available beginning with Windows Server 2008 R2 and above which allows the RDP client to connect securely over the public Internet using HTTPS to instances on a remote private network. The complete configuration of Remote Desktop Gateway requires SSL certificates and is beyond the scope of this book. (For more details about the configuration of RDP gateway, see http://technet.microsoft.com/en-us/library/dd983941(v=ws.10).aspx .)

For now, let’s use the user data section we learned about in Chapter 3 to enable the RDP gateway feature after the instance launches.
#Create a user data script to configure the RDP Gateway
$UserData = @'
<powershell>
Add-WindowsFeature -Name RDS-Gateway -IncludeAllSubFeature
</powershell>
'@
$UserData =
     [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($UserData))
Next, we will launch the instance, remembering to include the subnet and pass the user data script to execute after launch.
$Reservation = New-EC2Instance -ImageId $RDP_AMI -KeyName 'MyKey' -InstanceType
     't2.micro' -SubnetId $ResourcesSubnet.SubnetId -UserData
     $UserData
$RDPInstance = $Reservation.RunningInstance[0]
$Tag = New-Object Amazon.EC2.Model.Tag
$Tag.Key = 'Name'
$Tag.Value = 'RDPGateway'
New-EC2Tag -ResourceId $RDPInstance.InstanceID  -Tag $tag
Now, we wait for the instance to boot and allocate an additional EIP for the NAT instance and we are done.
Start-Sleep -s 60
While ((Get-EC2InstanceStatus -InstanceId $RDPInstance.InstanceID).InstanceState.name
     -ne 'running')
{
    Start-Sleep -s 60
    $RDPInstance = (Get-EC2Instance -Instance $RDPInstance.InstanceID).RunningInstance[0]
}
$EIP = New-EC2Address -Domain 'vpc'
Register-EC2Address -InstanceId $RDPInstance.InstanceID -AllocationId $EIP.AllocationId
If you have completed the configuration of the RDP gateway, you should be able to connect to a private instance and attempt to run Windows update. In order to connect to an instance in the private network, you need to tell your remote desktop client about the gateway server. See Figure 6-7. From the Advanced tab, click the Settings button, and enter the name of the server gateway. Now you can connect to the VPC instances as if they were publicly accessible.
../images/319650_2_En_6_Chapter/319650_2_En_6_Fig7_HTML.jpg
Figure 6-7

Remote Desktop Connection with an RDP gateway

Exercise 6.2: Least Privilege Security Groups

So far, we have been placing all of our private instances in the default group. The default group allows unrestricted communications between all the group members. While this makes configuration easy, it is not as secure as it could be.

In information security, the principle of least privilege requires that a system only have access to the resources it requires to do its job. In this example, we will build a set of security groups that allows the minimum set of permissions required for a simple application. Our simple application, shown in Figure 6-8, consists of a web server and SQL Server, both of which are members of an Active Directory domain.

At a high level, our application requires the following traffic flows:
  • HTTP/HTTPS from the Internet to the IIS server

  • TDS from IIS to SQL

  • Multiple protocols from the domain members (IIS and SQL) to the domain controllers

  • Replication between the domain controllers
    ../images/319650_2_En_6_Chapter/319650_2_En_6_Fig8_HTML.png
    Figure 6-8

    Least privilege security groups

Note that the IIS and SQL Servers are members of two groups. Rather than adding the domain member rules to the WebServer and SQLServer groups, it is better to have a group of each distinct role a server can hold. This will make it easier to maintain the rules over time.

First, we have to create the four groups pictured in Figure 6-8.
$DomainMembersGroupId = New-EC2SecurityGroup -GroupName 'DomainMembers' -GroupDescription
     "Domain Members" -VpcId $VPCID
$DomainControllersGroupId = New-EC2SecurityGroup -GroupName 'DomainControllers'
     -GroupDescription "Domain controllers" -VpcId $VPCID
$WebServersGroupId = New-EC2SecurityGroup -GroupName 'WebServers' -GroupDescription "Web
     servers" -VpcId $VPCID
$SQLServersGroupId = New-EC2SecurityGroup -GroupName 'SQLServers' -GroupDescription "SQL
     Servers" -VpcId $VPCID
Next, we add rules to the web group. The web group will allow HTTP (port 80) and HTTPS (port 443) from anywhere on the Internet.
#First, the Web instances must allow HTTP/S from the internet
$HTTPRule = New-Object Amazon.EC2.Model.IpPermission
$HTTPRule.IpProtocol='tcp'
$HTTPRule.FromPort = 80
$HTTPRule.ToPort = 80
$HTTPRule.IpRanges = '0.0.0.0/0'
$HTTPSRule = New-Object Amazon.EC2.Model.IpPermission
$HTTPSRule.IpProtocol='tcp'
$HTTPSRule.FromPort = 443
$HTTPSRule.ToPort = 443
$HTTPSRule.IpRanges = '0.0.0.0/0'
Grant-EC2SecurityGroupIngress -GroupId $WebServersGroupId
     -IpPermissions $HTTPRule, $HTTPSRule
Then, we add rules to the SQL group. The SQL Server should only be accessed from the web server. SQL uses a protocol called Tabular Data Stream (TDS) that runs on port 1433. In addition, applications are increasingly using SQL FileStream to store attachments. FileStream requires NetBIOS (port 139) and SMB (port 445) to stream the attachments to and from the SQL Server.
$WebGroup = New-Object Amazon.EC2.Model.UserIdGroupPair
$WebGroup.GroupId = $WebServersGroupId
$SQLRule = New-Object Amazon.EC2.Model.IpPermission
$SQLRule.IpProtocol='tcp'
$SQLRule.FromPort = 1433
$SQLRule.ToPort = 1433
$SQLRule.UserIdGroupPair = $WebGroup
$NetBIOSRule = New-Object Amazon.EC2.Model.IpPermission
$NetBIOSRule.IpProtocol='tcp'
$NetBIOSRule.FromPort = 139
$NetBIOSRule.ToPort = 139
$NetBIOSRule.UserIdGroupPair = $WebGroup
$SMBRule = New-Object Amazon.EC2.Model.IpPermission
$SMBRule.IpProtocol='tcp'
$SMBRule.FromPort = 445
$SMBRule.ToPort = 445
$SMBRule.UserIdGroupPair = $WebGroup
Grant-EC2SecurityGroupIngress -GroupId $SQLServersGroupId -IpPermissions $SQLRule, $NetBIOSRule, $SMBRule
Now, we add rules to the DomainMembers group. The DomainMembers group is simple, allowing only ping from the domain controllers. The domain controllers will occasionally ping the domain members to check that they are still running. In addition, the DomainMembers group is the source of all the rules in the DomainControllers group.
$DCGroup = New-Object Amazon.EC2.Model.UserIdGroupPair
$DCGroup.GroupId = $DomainControllersGroupId
$PingRule = New-Object Amazon.EC2.Model.IpPermission
$PingRule.IpProtocol='icmp'
$PingRule.FromPort = 8
$PingRule.ToPort = -1
$PingRule.UserIdGroupPair = $DCGroup
Grant-EC2SecurityGroupIngress -GroupId $DomainMembersGroupId -IpPermissions $PingRule

Finally, we add rules to the DomainControllers group. This group has several rules. We will break them down by IP protocol.

First, assuming we have more than one domain controller, they must be able to replicate data between each other. Therefore, we are allowing unrestricted communications between the controllers.
$AllRule = New-Object Amazon.EC2.Model.IpPermission
$AllRule.IpProtocol='-1'
$AllRule.UserIdGroupPair = $DCGroup
Grant-EC2SecurityGroupIngress -GroupId $DomainControllersGroupId -IpPermissions $AllRule
Second, the domain controllers allow ping from any of the domain members:
$DMGroup = New-Object Amazon.EC2.Model.UserIdGroupPair
$DMGroup.GroupId = $DomainMembersGroupId
$PingRule = New-Object Amazon.EC2.Model.IpPermission
$PingRule.IpProtocol='icmp'
$PingRule.FromPort = 8
$PingRule.ToPort = -1
$PingRule.UserIdGroupPair = $DMGroup
Grant-EC2SecurityGroupIngress -GroupId $DomainControllersGroupId -IpPermissions $PingRule
Third, the domain controller must allow an array of TCP communication types from the domain members. These include
  • 53 – DNS queries. Note DNS uses both TCP and UDP.

  • 88 – Kerberos authentication. Note Kerberos uses both TCP and UDP.

  • 135 – Remote procedure calls. Note: RPC will also use a port in the range 49152-65535.

  • 137–139 – NetBIOS. Note Kerberos uses both TCP and UDP.

  • 389 and 636 – Lightweight Directory Access Protocol (LDAP).

  • 445 – Server Message Block (SMB).

  • 464 – Password reset. Note that it uses both TCP and UDP.

  • 3268 – Microsoft global catalog.

#Domain controllers must allow numerous TCP protocols from domain members
$DNSRule = New-Object Amazon.EC2.Model.IpPermission
$DNSRule.IpProtocol='tcp'
$DNSRule.FromPort = 53
$DNSRule.ToPort = 53
$DNSRule.UserIdGroupPair = $DMGroup
$KerberosRule = New-Object Amazon.EC2.Model.IpPermission
$KerberosRule.IpProtocol='tcp'
$KerberosRule.FromPort = 88
$KerberosRule.ToPort = 88
$KerberosRule.UserIdGroupPair = $DMGroup
$NetBIOSRule = New-Object Amazon.EC2.Model.IpPermission
$NetBIOSRule.IpProtocol='tcp'
$NetBIOSRule.FromPort = 137
$NetBIOSRule.ToPort = 139
$NetBIOSRule.UserIdGroupPair = $DMGroup
$RPCRule = New-Object Amazon.EC2.Model.IpPermission
$RPCRule.IpProtocol='tcp'
$RPCRule.FromPort = 135
$RPCRule.ToPort = 135
$RPCRule.UserIdGroupPair = $DMGroup
$LDAPRule = New-Object Amazon.EC2.Model.IpPermission
$LDAPRule.IpProtocol='tcp'
$LDAPRule.FromPort = 389
$LDAPRule.ToPort = 389
$LDAPRule.UserIdGroupPair = $DMGroup
$SMBRule = New-Object Amazon.EC2.Model.IpPermission
$SMBRule.IpProtocol='tcp'
$SMBRule.FromPort = 445
$SMBRule.ToPort = 445
$SMBRule.UserIdGroupPair = $DMGroup
$PasswordRule = New-Object Amazon.EC2.Model.IpPermission
$PasswordRule.IpProtocol='tcp'
$PasswordRule.FromPort = 464
$PasswordRule.ToPort = 464
$PasswordRule.UserIdGroupPair = $DMGroup
$LDAPSRule = New-Object Amazon.EC2.Model.IpPermission
$LDAPSRule.IpProtocol='tcp'
$LDAPSRule.FromPort = 636
$LDAPSRule.ToPort = 636
$LDAPSRule.UserIdGroupPair = $DMGroup
$ADRule = New-Object Amazon.EC2.Model.IpPermission
$ADRule.IpProtocol='tcp'
$ADRule.FromPort = 3268
$ADRule.ToPort = 3269
$ADRule.UserIdGroupPair = $DMGroup
$RpcHpRule = New-Object Amazon.EC2.Model.IpPermission
$RpcHpRule.IpProtocol='tcp'
$RpcHpRule.FromPort = 49152
$RpcHpRule.ToPort = 65535
$RpcHpRule.UserIdGroupPair = $DMGroup
Grant-EC2SecurityGroupIngress -GroupId $DomainControllersGroupId -IpPermissions $DNSRule,
     $KerberosRule, $RPCRule, $LDAPRule, $PasswordRule, $LDAPSRule, $ADRule, $RpcHpRule
Fourth, the domain controller must allow an array of UDP communication types from the domain members. These include
  • 53 – DNS queries. Note DNS uses both TCP and UDP.

  • 88 – Kerberos authentication. Note Kerberos uses both TCP and UDP.

  • 123 – Network Time Protocol.

  • 137–139 – NetBIOS. Note Kerberos uses both TCP and UDP.

  • 389 – Lightweight Directory Access Protocol (LDAP).

  • 464 – Password reset. Note that it uses both TCP and UDP.

#Domain controllers must allow numerous TCP protocols from domain members
$DNSRule = New-Object Amazon.EC2.Model.IpPermission
$DNSRule.IpProtocol='udp'
$DNSRule.FromPort = 53
$DNSRule.ToPort = 53
$DNSRule.UserIdGroupPair = $DMGroup
$KerberosRule = New-Object Amazon.EC2.Model.IpPermission
$KerberosRule.IpProtocol='udp'
$KerberosRule.FromPort = 88
$KerberosRule.ToPort = 88
$KerberosRule.UserIdGroupPair = $DMGroup
$NTPRule = New-Object Amazon.EC2.Model.IpPermission
$NTPRule.IpProtocol='udp'
$NTPRule.FromPort = 123
$NTPRule.ToPort = 123
$NTPRule.UserIdGroupPair = $DMGroup
$NetBIOSRule = New-Object Amazon.EC2.Model.IpPermission
$NetBIOSRule.IpProtocol='udp'
$NetBIOSRule.FromPort = 137
$NetBIOSRule.ToPort = 139
$NetBIOSRule.UserIdGroupPair = $DMGroup
$LDAPRule = New-Object Amazon.EC2.Model.IpPermission
$LDAPRule.IpProtocol='udp'
$LDAPRule.FromPort = 389
$LDAPRule.ToPort = 389
$LDAPRule.UserIdGroupPair = $DMGroup
$PasswordRule = New-Object Amazon.EC2.Model.IpPermission
$PasswordRule.IpProtocol='udp'
$PasswordRule.FromPort = 464
$PasswordRule.ToPort = 464
$PasswordRule.UserIdGroupPair = $DMGroup
Grant-EC2SecurityGroupIngress -GroupId $DomainControllersGroupId -IpPermissions $DNSRule,
     $KerberosRule, $NTPRule, $NetBIOSRule, $LDAPRule, $SMBRule, $PasswordRule

As we have seen, security groups allow us to create very specific rules to secure our resources. By writing rules that are based on other security groups, we define our security policy before launching instances. This gives us the benefit of not needing to change the rules as we launch each instance. The rules in this example are just a starting point. You will need to add additional groups and rules as your infrastructure grows.

Summary

Amazon VPC gives us numerous capabilities to build our ultimate virtual network, with the isolation and security we need for our applications, all without the headaches of managing traditional networking equipment.

We can define outbound rules in our security groups. We can control the network configuration at launch including subnet, security group, and private IP address. We can assign publicly addressable EIPs. We can even add multiple IP addresses and multiple network interfaces.

All of these features allow us to create network configurations that are as simple or complex as we need them to be. In the examples, we explored advanced patterns for managing enterprise networks. First, we discussed how to manage and patch private instances using an RDP and NAT gateway. Second, we created a series of security groups to implement least privileged access for Windows instances in an Active Directory domain.

While VPC brings us numerous capabilities, it can also involve complexity. We will keep things relatively simple in the remaining chapters on EC2, by using a VPC configuration that allows us to focus on features without the complexity discussed in Chapters 5 and 6. In the next chapter, we discuss creating our own Amazon Machine Images.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset