This post demonstrates the use of IP restrictions inside a Windows Azure Web Role to allow or prevent access by known IP addresses. This question was asked of me by Robin Osborne (@rposbo) a good friend and leading technical expert in London, and in exploring his question I thought I’d share the results with the wider community.
Source code is provided.
In a given application there may be sensitive areas of the system that need protecting. Traditional authentication mechanisms may suffice, but in certain circumstances it may be necessary to lock down a location at a lower level. One way of doing this is to allow or deny access by IP Address.
This feature is supported in IIS7, and so is available for our use in Windows Azure. From the documentation on IIS7, this is the summary of what is possible with IIS7 IP Security:
In IIS 7, all Internet Protocol (IP) addresses, computers, and domains can access your site by default. To enhance security, you can limit access to your site by creating an allow rule that grants access to all IP addresses (the default), a specific IP address, a range of IP addresses, or a specific domain. For example, if you have a site on an intranet server that is connected to the Internet, you can prevent Internet users from accessing your intranet site by allowing access only to members of your intranet.
This feature is very easy to configure and use, since in IIS7 we can do most of our configuration in our web.config file.
Jumping straight into some setup, we first need a new Cloud Project with a single Web Role inside.
Since we are very concerned about IP addresses, I modified the Site.Master page to add a basic piece of ASP.NET to show the user’s IP Address.
<h1> You are: <%: Request.UserHostAddress %> </h1>
Following this, we need to open our Web.config, and add in some basic rules. These rules can be complex, allowing or denying access to certain paths based on IP Address. For my example, I found my own IP address (by going to http://www.whatismyip.com) and denied myself access to the ~/Account/ folder within my application. This looks like:
This setting means that all users have access to the path ~/Account (because allowUnlisted is true), but the specified ip address is denied access to the folder. I will test access is available to other IP Addresses using another device, such as my smart phone.
Note that if we try this in the Azure compute emulator, we will need to modify the ipAddress for local to 127.0.0.1. I am testing against Azure staging instead, so my ipAddress remains static.
That’s all there is to it! Well almost.
If we load up the project in Azure, we find that actually we can access the page even though our IP address should be banned. What’s going on?
It turns out that IIS7 doesn’t have the module or role installed for IP Security in Azure (or any Windows 2008 Server) by default. Therefore we must go ahead and install the module ourselves, before the application starts. The way to achieve this is to create a startup task.
Create a .cmd file (Save as Unicode Without Signature) called Startup.cmd in the root of your web application. Mark this as Content and “Copy Always”. In this file we are going to put some shell commands to make the Web Role install the correct IIS module during its startup. Those commands are:
@echo off @echo Installing "IPv4 Address and Domain Restrictions" feature %windir%System32ServerManagerCmd.exe -install Web-IP-Security @echo Unlocking configuration for "IPv4 Address and Domain Restrictions" feature %windir%system32inetsrvAppCmd.exe unlock config -section:system.webServer/security/ipSecurity
Then go into the ServiceDefinition.csdef and add the startup task like so:
<Startup> <Task commandLine="Startup.cmd" executionContext="elevated" taskType="simple" /> </Startup>
Note that this startup task does increase the length taken to start a role considerably (~5mins on a SMALL instance size). This is clearly due to installing new IIS components.
Now when we deploy again to Windows Azure, we find that our IP Address is no longer allowed access to the folder or any of its contents.
When I access the same path on my smart phone (clearly it will have a different IP), I get the the login screen:
That’s about all, source code is attached here: IPRestrictions