Summary: Windows networking engineer, James Kehr, continues talking about how to us Windows Azure cmdlets to create endpoint ACLs.
Microsoft Scripting Guy, Ed Wilson, is here. Welcome back guest blogger, James Kehr, for Part 2 of 2…
If you missed Part 1 of this blog post, I recommend that you give that a read before digging in to Part 2:
Weekend Scripter: Creating ACLs for Windows Azure Endpoints—Part 1 of 2
I am not going to dive as deep into Window Azure network security in Part 2, so this post may not make sense if you have not read Part 1. Just so you know…
Editing Windows Azure endpoint ACLs
I like to measure how dry a subject is by how dull the title is…
“Journey to the Center of the Earth.” That’s an exciting title, and a great book.
“Editing Azure Endpoint ACLs.” Now that makes we want to fall asleep. That title should be added to every dictionary in the universe as an example of both dry and dull. I really tried to think of a snappy title, but nothing came to mind. I will try to compensate with livelier text, but I don’t know how exciting I can make endpoint ACLs.
ACLs help make networks secure. If you don’t understand why ACLs do this, then stop here and go read Part 1. Seriously…go read it. Part 2 isn’t going vanish in the ten minutes it takes to read Part 1. Of course, knowing my luck, that will happen, and I’ll get an angry emails when it does. If this does happen, I apologize in advance. And I hope that the reason why is a short-lived technological blip and not the world coming to a sudden and abrupt end.
Back to the blog…
ACLs make networks more secure by restricting access to network resources. With Windows Azure, you can create ACLs on Internet-facing endpoints so your cloud stuff is safer stuff. The issue is that stuff changes. IP addresses changes, access needs change, mistakes are made by people who don’t read the Hey, Scripting Guy! Blog, and a number of other things can happen. When stuff like this does happen, you need to update ACL rules. Fortunately for you, I happen to know how to do this. I’m even willing to share.
The first thing we need to do is get the current endpoint ACL rules and throw that object into a variable:
$acl = Get-AzureVM -ServiceName Web01 | Get-AzureAclConfig -EndpointName "HTTP"
You need to specify the exact EndpointName, or you could end up with the wrong rules or no rules at all. If you are wondering why I use ServiceName and not the virtual machine name…Part 1.
The next step is a little fuzzy because it changes with each scenario. To make this process easier to understand and write, I’ll continue with the example I used in Part 1. I have a server, Web01, hosting an Intranet site in the Windows Azure cloud. The port 80 endpoint in Windows Azure is secured by ACLs so only the app server and the corporate proxy servers can access the site.
Recently, around the time Part 2 was started, a second app server was added, and our imaginary devs opened a ticket because App2, IP 1.2.3.5, cannot access the website. It is now our task, as network security types, to grant App2 access.
The ACL rules, as shown by $acl output, look something like this:
RuleId | Order | Action | RemoteSubnet | Description |
0 | 0 | Permit | 1.2.3.4/32 | Allow App1 |
1 | 1 | Permit | 176.16.0.0/29 | Allow corp proxies |
2 | 2 | Deny | 0.0.0.0/0 | DenyAll |
To provide examples of how to remove and edit a rule, I will perform the update in three ways. Before I begin, you need to remember that ACL rule processing is stopped at the first rule match. If I were to simply add a rule for App2, it would show up as rule #3, the DenyAll rule #2 would apply first, and App2 would not have access.
Regardless of whether you are adding, removing, or editing a rule, all three rule options use the Set-AzureAclConfig cmdlet. The difference is in the rule parameter you call: AddRule, RemoveRule, or SetRule.
Each rule parameter has a different purpose and set of mandatory parameters, even though the root cmdlet is the same. AddRule was discussed in Part 1, and the other two will be explained in the three solutions to our example problem.
If you need to remove an endpoint while testing, this is the command you need to know:
Get-AzureVM -ServiceName <ServiceName> | Remove-AzureEndpoint <Endpoint name> | Update-AzureVM
Solution 1
The first solution provides an example of how to remove a rule. The full script looks like this:
# get existing ACL
$acl = Get-AzureVM -ServiceName Web01 | Get-AzureAclConfig -EndpointName "HTTP"
# remove DenyAll
Set-AzureAclConfig -RemoveRule -RuleId 2 -ACL $acl
# add permit App2 and DenyAll in correct order
Set-AzureAclConfig -AddRule -ACL $acl -Order 2 -Action Permit -RemoteSubnet "1.2.3.5/32" -Description "Allow App2"
Set-AzureAclConfig -AddRule -ACL $acl -Order 3 -Action Deny -RemoteSubnet "0.0.0.0/0" -Description "DenyAll"
# commit changes
Get-AzureVM -ServiceName Web01 | Set-AzureEndpoint -ACL $acl -Name "HTTP" -Protocol TCP -PublicPort 80 -LocalPort 80 | Update-AzureVM
The remove command is pretty simple. Tell the Set-AzureAclConfig -RemoveRule command where the ACL is stored and which rule number needs the axe:
Set-AzureAclConfig -RemoveRule -RuleId 2 -ACL $acl
Add the App2 rule, the DenyAll rule, commit changes, done. Not very hard, but not the most efficient way to do it.
Solution 2
This solution is more efficient by one whole line of code. You’re amazed, I know. This solution involves changing rule #2, and adding DenyAll at rule #3. The ACL update part of the Solution 1 script now looks like this:
# change rule #2 to permit App2
Set-AzureAclConfig -SetRule -ACL $acl –RuleId 2 -Order 2 -Action Permit -RemoteSubnet "1.2.3.5/32" -Description "Allow App2"
# add DenyAll
Set-AzureAclConfig -AddRule -ACL $acl -Order 3 -Action Deny -RemoteSubnet "0.0.0.0/0" -Description "DenyAll"
If you look at the -SetRule version of the cmdlet, you will notice that it looks almost exactly like the -AddRule version. The only difference besides the rule parameter is the addition of the RuleID. SetRule changes the rule matching the rule plus order numbers to whatever values you put in Action, RemoteSubnet, and Description. All of these parameters are mandatory.
Solution 3
The final solution is a sneaky one and the most efficient way to make the change. Take a minute and see if you can figure it out…
Don’t worry about me, I can wait. I’ll give you a clue: Look at the IP addresses of App1 and App2.
When you’re ready the answer is:
# update rule to permit both App servers
Set-AzureAclConfig –SetRule -ACL $acl -RuleId 0 -Order 0 -Action Permit -RemoteSubnet "1.2.3.4/31" -Description "App servers"
For those who didn’t get it, perhaps this will help. App1 has an IP address of 1.2.3.4, App2 uses 1.2.3.5. A /32 subnet is a single IP address, a /31 subnet is … 2 IP addresses.
The RemoteSubnet parameter is used to define the subnet, yes. But on this end of the conversation, it just means an IP address range, and it is not used to define the network boundaries. The ACL process does not care what your network, gateway, broadcast, or HSRP IP addresses are. It only cares whether the source IP address matches one of the rule IP masks. This means that 1.2.3.4/31 will work for both App1 and App2 without adding rules to the ACL or compromising the endpoint.
Gently give your monitor a high-five if you figured out that one.
Load-balanced endpoints
Our last topic is the original reason I wrote this blog post. Everything I have written so far is to help novices to Windows Azure and ACLs gain enough background knowledge to understand the load-balanced endpoint ACLs in Windows Azure.
Load-balanced endpoints allow a single public IP, called a VIP (virtual IP), to send network traffic to multiple private IP addresses. I won’t go into much detail on how load-balanced endpoints work because there are a number of resources that explain the topic. If you want to learn more, check out this topic in the Windows Azure documentation: Load Balancing Virtual Machines.
For the purposes of this post, I will append our example with this scenario. The devs have recently added a second web server (Web02) and created an IIS web farm. This web farm will host a secure site by using port 443, which must remain up in the event of a server reboot and must be load balanced. Your job is to create the load-balanced endpoint and set up identical ACL rules to the Web01 port 80 ACL.
I sound like a MCSE exam question…
Which Windows Azure cmdlet should you use?
a) Make-MagicHappen
b) Add-AzureEndpoint
c) Set-AzureLoadBalancedEndpoint
d) Love-PowerShell
If you chose answer b), you are correct. If you answered c), you are half right. If you answered a), please share your magical cmdlet with the rest of the world. And if you answered d), The Scripting Guy will probably give you a passing grade on the non-certification exam anyway.
The Add-AzureEndpoint cmdlet is what creates the endpoint. It can be used to add the ACL at the same time, which makes it the most correct answer. The Set-AzureLoadBalancedEndpoint (New-Alias Set-ALBE Set-AzureLoadBalancedEndpoint) can add an ACL to a load-balanced endpoint, but only if the endpoint already exists. I will use these cmdlets in my script so you have an example of both.
# create new load balanced endpoint
Get-AzureVM -ServiceName Web01 | `
Add-AzureEndpoint -Name "HTTPS" -Protocol TCP -PublicPort 443 -LocalPort 443 -ProbePort 3443 -ProbeProtocol HTTP -ProbePath "/” -LBSetName "Web-HTTPS-LB" | `
Update-AzureVM
# create ACL
$acl = New-AzureAclConfig
Set-AzureAclConfig -AddRule -ACL $acl -Order 0 -Action Permit -RemoteSubnet "1.2.3.4/31" -Description "Allow App servers"
Set-AzureAclConfig -AddRule -ACL $acl -Order 1 -Action Permit -RemoteSubnet "172.16.0.0/29" -Description "Allow corp proxies"
Set-AzureAclConfig -AddRule -ACL $acl -Order 2 -Action Deny -RemoteSubnet "0.0.0.0/0" -Description "DenyAll"
# add ACL to the LB endpoint
Set-AzureLoadBalancedEndpoint -ServiceName Web01 –LBSetName "Web-HTTPS-LB” -ACL $acl -Protocol TCP -LocalPort 443 –ProbeProtocolHTTP –ProbePath "/" -ProbePort 3443
The Add-AzureEndpoint cmdlet is using new parameters that are required for creating load-balanced endpoints:
Add-AzureEndpoint -Name "HTTPS" -Protocol TCP -PublicPort 443 -LocalPort 443 -ProbePort 3443 -ProbeProtocol HTTP -ProbePath "/” -LBSetName "Web-HTTPS-LB"
ProbePort: This port is used to test whether the service is up. There is a gotcha with the probe port. Your probe port cannot be the same as the local port or you’ll get a nasty error message when you try to add an ACL.
ProbeProtocol: Your options are TCP or HTTP. When set to TCP, the probe only needs to make a simple TCP connection, and the service is considered up. When set to HTTP, you must add the ProbePath parameter to test the probe.
ProbePath: This is the path to your keep alive page …basically. This is the HTTP path minus the domain/IP, where “/” is considered the site root. If you have an actual keep alive page, the probe path would look something like this “/keep-alive.html”. The load-balanced probe will connect to this path on the private IP address and the probe port. If an HTTP 200 status code is returned, the probe is considered up, any other status code and the service is considered down. No redirectors are allowed for getting to the keep alive page!
LBSetName: This is kind of self-explanatory. The endpoint Name is what the individual endpoints are called, the LBSetName is the name of the group of individual endpoints that make up the load-balanced endpoint.
If you don’t want to check a keep alive page, you can use the TCP option, which looks like this:
Add-AzureEndpoint -Name "HTTPS" -Protocol TCP -PublicPort 443 -LocalPort 443 -ProbePort 3443 -ProbeProtocol TCP -LBSetName "Web-HTTPS-LB"
No matter which probe protocol you use, you need to bind the probe port to your website, and then open a port on the server’s firewall. This should not be considered a security concern because the probe port is not exposed to the Internet. Only internal Windows Azure services and other servers and services in the same VNET can access the probe port.
This is also where using ServiceName in the Get-AzureVM cmdlet comes in handy. If you specify the virtual machine name, the endpoint is only applied to that single virtual machine. When you use ServiceName, it is applied to all of the virtual machines in the service. This allows you to apply the endpoint to all the load-balanced virtual machines at one time. Nifty, isn’t it?
Set-AzureLoadBalancedEndpoint -ServiceName Web01 –LBSetName "Web-HTTPS-LB” -ACL $acl -Protocol TCP -LocalPort 443 –ProbeProtocolHTTP –ProbePath "/" -ProbePort 3443
I skipped the ACL creation part because that has been discussed thoroughly. Set-ALBE is a handy cmdlet because you don’t have to use Get-AzureVM or Update-AzureVM. Run and done. This cmdlet is used to update the load-balanced endpoint, and as such, you need to include ALL of the endpoint information, including the ACL, each time you use the cmdlet. In this example, it is used to add the ACL. If you don’t like it, in two steps, you can create the ACL first and add the -ACL parameter to Add-AzureAclConfig cmdlet. After the load-balanced endpoint is created, you can to use Set-ALBE to make changes.
Windows Azure cmdlets are a great way to automate processes in the cloud. Endpoint ACLs are a great way to secure your cloud services and Windows PowerShell is a great tool to set those ACLs. I want to remind you to be careful when planning ACLs. Do not add a ton of rules, and put your frequently used services first to improve performance.
That’s all I have this time around. I hope you learned something new about Windows Azure and Windows PowerShell.
~James
Thanks James, for sharing your time and knowledge. I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy