I'm new to Azure and I'm working on a project that uses the new Websites model as opposed to Cloud Services. I want to set up a continuous delivery process like this one: http://www.windowsazure.com/en-us/develop/net/common-tasks/publishing-with-tfs/
However, I don't want my site to be publicly addressable after each continuous deployment. Instead, I want my continuous deployments to be accessible only by my team for testing purposes. How can this best be achieved?
Thoughts so far:
Wrap the whole site in forms authentication - but I don't like the fact that this means I will be deploying a different version of my site to production than that which I deploy to testing.
IP address restrictions - but I don't know if this can be done with Azure Websites and whether this is a good solution?
The Azure Websites Authentication / Authorization feature was designed to support this exact scenario. Basically, you create a site slot, add AAD authentication to it using a few clicks, and from then on your staging slot will always require a valid login, even after you do a swap operation.
Blog Post: http://azure.microsoft.com/blog/2014/11/13/azure-websites-authentication-authorization/
Demo Video: http://azure.microsoft.com/en-us/documentation/videos/azure-websites-easy-authentication-and-authorization-with-chris-gillum/
You can add IP restrictions using the URL Rewrite Module, which Azure web sites seem to have enabled by default.
Your web.config:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="SayNoToZombies" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{REMOTE_ADDR}" pattern="::1" negate="true" />
</conditions>
<action type="CustomResponse" statusCode="403" statusReason="Forbidden: Access is denied." statusDescription="Sorry, you're not allowed" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
You can replace pattern="::1" (localhost in IPv6) with a suitable regex to match your permitted IP, e.g., pattern="87.236.134.47" or if more than one:
pattern="(62\.231\.142\.233)|(87\.236\.134\.47)|(::1)|(127\.0\.0\.1)"
I had to do something similar for a client, but couldn't find a way to restrict access to the site from the Azure portal itself. I went with the IP address restriction option, but did it through code in the application itself. My application was already using forms authentication, so I could perform the IP address check in the sign in action.
In your case I would suggest a custom action filter. Perform the check in the filter and if the IP address is not allowed, return a http 401 (unauthorised) status code.
Create an app setting called AllowedIpAddresses or some such, in which you can add a comma separated list of allowed IP addresses. When you perform the check, you can set your site to allow all traffic if AllowedIpAddresses is empty or doesn't exist. That way, you can ignore this setting in production and all traffic will be allowed by default. You can set up custom app settings for each site within the Azure portal.
Here's what a custom filter might look like. I haven't tested this!
public class AccessRestrictionFilterAttribute : ActionFilterAttribute
{
// simple wrapper around ConfigurationManager.AppSettings for testability
private readonly IAppSettingsHandler appSettingsHandler;
public AccessRestrictionFilterAttribute(IAppSettingsHandler appSettingsHandler)
{
this.appSettingsHandler = appSettingsHandler;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var isAllowed = false;
var userIpAddress = filterContext.HttpContext.Request.UserHostAddress;
if (appSettingsHandler.AllowedIpAddresses.Split(new[] { ',' }).Any(x => x == userIpAddress))
{
isAllowed = true;
}
if (!isAllowed)
{
filterContext.Result = new HttpUnauthorizedResult();
}
base.OnActionExecuting(filterContext);
}
}
Related
I have website that is Hosted in a Azure App Service. are there any options in azure so that I can put a password on the website. Ideally without changing the websites code.
Just a basic password or user name and password, doesn't need to be google or facebook login or AD login.
It is a .net based website and I have seen a few options to do this, but it means I have to change the code of the website in someway or another.
Surely with all that sophisticated cloud technology, I can go in to the portal and set a password at a server level? - Or is the only way to make some kind of change to the application?
It is possible to enable Basic Authentication for Azure Web Apps with some settings in the applicationHost.xdt. You can load some modules in this file on the start of your Web App.
Steps:
Navigate to your WebApp in the Azure Portal
In the left menu, search for the header Development Tools an select Advanced Tools (Kudu)
Use the Debug Console > CMD tool, to navigate to the WebApp directory: \home\site
Create a file named: applicationHost.xdt
Paste the following:
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<location path="%XDT_SITENAME%" xdt:Locator="Match(path)">
<system.webServer>
<rewrite xdt:Transform="InsertIfMissing">
<allowedServerVariables xdt:Transform="InsertIfMissing">
<add name="RESPONSE_WWW_AUTHENTICATE" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
</allowedServerVariables>
<rules xdt:Transform="InsertIfMissing">
<rule name="BasicAuthentication" stopProcessing="true" xdt:Transform="InsertIfMissing" xdt:Locator="Match(name)">
<match url=".*" />
<conditions>
<add input="{HTTP_AUTHORIZATION}" pattern="^Basic dXNlcjpwYXNzd29yZA==" ignoreCase="false" negate="true" />
</conditions>
<action type="CustomResponse" statusCode="401" statusReason="Unauthorized" statusDescription="Unauthorized" />
<serverVariables>
<set name="RESPONSE_WWW_AUTHENTICATE" value="Basic realm=Project" />
</serverVariables>
</rule>
</rules>
</rewrite>
</system.webServer>
</location>
</configuration>
Change the Basic Auth to your liking (default in example is: user:password)
Make sure the web.config rewrite rules don't contain <clear /> as this wil remove the effects from the applicationHost.xdt file
Save the file and Stop and Start your WebApp (a simple Restart will not suffice)
Notes:
Not sure if this works on Linux based WebApps..
You can add this step to you're deployment pipelines by using FTP
Update: I've noticed issues with applicationHost.xdt while using it on secondary Web App slots. Only the primary slot seems to work.
PS: Cross-post from my answer here.
You can use Authentication and authorization in Azure App Service.
Authentication/Authorization was previously known as Easy Auth.
Azure App Service provides built-in authentication and authorization support, so you can sign in users and access data by writing minimal or no code in your web app, RESTful API, and mobile back end, and also Azure Functions. This article describes how App Service helps simplify authentication and authorization for your app.
Source: Authentication and authorization in Azure App Service and Azure Functions.
EDIT:
The above is a solution to have a password protected App Service without changing any code whatsoever. At this point there is no alternative, as you can see in the open feedback issue Allow HTTP Basic authentication on basic apps
Hi everyone, we understand the demand for this feature, but we do not plan to support authentication at this level. We suggest using EasyAuth for this scenario.
https://learn.microsoft.com/en-us/azure/app-service/overview-authentication-authorization
EDIT 2:
This method forces the user to use google or facebook, etc...
This is not true. You can also create a user in your Azure Active Directory and use that one with Easy Auth. The username would be something like username#<YOUR-TENANT>.onmicrosoft.com
I have an API running and a front-end node server running for SSR purposes. Everything is on Azure using App Services.
Both the node server and client(s) make requests to the API.
I am trying to apply 'dynamicIpSecurity' in the web.config of my API, but do not want my node server IPs to be throttled by that security setting since it is a trusted 'client'.
Goal is to throttle all other client IPs through this setting in case a client decides to try ddos-ing me or load testing my API without my permission to find loopholes.
I currently have the the dynamic ip security settings commented out, but this is how they look.
<dynamicIpSecurity>
<!--Restricting single IP to make maximum of 20 concurrent request at a time-->
<denyByConcurrentRequests enabled="true" maxConcurrentRequests="20" />
<!--Restricting single IP NOT to make more than 50 requests within 3 seconds duration-->
<denyByRequestRate enabled="true" maxRequests="50" requestIntervalInMilliseconds="3000"/>
</dynamicIpSecurity>
In the article, <dynamicIpSecurity> could only use denyByConcurrentRequests and denyByRequestRate to blocking of requests from IP address based on The number of concurrent requests or
The number of requests over a period of time.
Although as the article said, <dynamicIpSecurity> could Allow list of IP addresses that will not be blocked. However, in web.config it could not configure, you could only do it in IIS.
So, if you still want to defines a list of IP-based security restrictions you could use <ipSecurity> like below:
<security>
<ipSecurity allowUnlisted="true">
<add ipAddress="192.168.100.1" />
<add ipAddress="169.254.0.0" subnetMask="255.255.0.0" />
</ipSecurity>
<dynamicIpSecurity enableLoggingOnlyMode="true">
<denyByConcurrentRequests enabled="true" maxConcurrentRequests="10" />
<denyByRequestRate enabled="true" maxRequests="30"
requestIntervalInMilliseconds="300" />
</dynamicIpSecurity>
</security>
I created a ARM template that creates App Service (web application) and Application Insights resource that is similar to this template (https://github.com/tomasr/webapp-appinsights). The App insights is connected to web app and everything works fine, the only problem is that app insights automatically generates requests to root of my web app as part of availability test that always return error because I don't have anything in the root path (even if I had, it is calling http instead of https url). There is nothing in the template that sets up this request, and if I go to availability properties, nothing is there. Is there a way to turn this feature off or configure it to call a valid URL?
In case it's Always On, the feature of App Service that keeps your app from going idle by pinging it with an HTTP GET to the root every once in a while, there is a way with Rewrite.
You can make a rewrite rule that has a condition that detects it's an Always On request, and if it is, make it hit another URL you specify instead.
Here is an example:
<?xml version="1.0" encoding="UTF-8" standalone="no">
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Rewrite AlwaysOn" stopProcessing="true">
<match url="^$" />
<conditions>
<add input="{HTTP_USER_AGENT}" pattern="^AlwaysOn$" />
</conditions>
<action type="Rewrite" url="/api/Online/Ping" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
Original article I found this from: https://blogs.msdn.microsoft.com/benjaminperkins/2018/08/10/how-to-optimize-azure-app-service-alwayson-cold-start-warm-up-request/
If you have a rewrite rule that redirects HTTP to HTTPS, you should add this rule before that.
My marketing team accidentally created materials with an additional 'www' sub domain and I need to see if I can remove it using Azure traffic manager.
Marketing domain (incorrect) HTTPS://www.my.site.com
Desired domain HTTPS://my.site.com
I only have a wildcard cert for *.site.com so at this time I cannot support the 'www'.
If the user enters the 'www' site over HTTP I can successfully redirect to the correct site. If they enter the HTTPS, or use Firefox that defaults to HTTPS, they will see a certificate error for HTTPS://www.my.site.com.
Would a second wildcart cert for *.my.site.com help? I am not sure where I would configure it.
Any help would be appreciated, thanks.
The certificate you have should be enough since its a wildcard cert, no need to buy another one.
I think this can be fixed by adding another host-name to your app and creating another SSL binding.
That means you need to add the www.my.site.com host-name (make sure to assign it to the traffic manager url):
And then do the binding:
Once that is done both URLs will work through SSL.
If you want to then have all traffic from going to you can then add a URL re-write rule:
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="SPA">
<match url="OLDURL" />
<action type="Rewrite" url="NEWURL" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
You can look at this other answer to get more data: Rewriting a URL in an Azure web app
I am developing on a website which is currently hosted in Azure on a VM. Now I am changing this website to be able to run it as an Azure website.
Now my problem:
I am using the url rewrite module from IIS with the database provider, which works perfectly in the VM. With the database provider users of the website can create their own simple rewrite rules.
But when I upload my website as an Azure Website and I access a url that's specified in the database I get an error:
"The page cannot be displayed because an internal server error has occurred.".
This is the logging configuration I currently use:
<rewrite>
<rules configSource="RewriteInbound_Live.config" />
<outboundRules configSource="RewriteOutbound_Live.config" />
<providers>
<provider name="DB" type="DbProvider, Microsoft.Web.Iis.Rewrite.Providers, Version=7.1.761.0, Culture=neutral, PublicKeyToken=0545b0627da60a5f">
<settings>
<add key="ConnectionString" value="*****" />
<add key="StoredProcedure" value="sp_GetRewrittenUrl" />
<add key="CacheMinutesInterval" value="60" />
</settings>
</provider>
</providers>
</rewrite>
I've turned on web server logging which doesn't give me any information, and I've enabled application logging which also doesn't give me any information.
My question, is it possible to use custom providers for the url rewite module in Azure, of can this be achieved in another way?
I had the same problem: DbProvider not available in azure web app. So I left most of the url rewriting stuff in the web.config untouched and moved the database-based rules to the global.asax file's Application_BeginRequest method.
For redirect rules, just use a Response.Redirect or an adequate Redirect301 implementation. On the other hand, for the rewrites, use HttpContext.Current.RewritePath.
You should add a caching mechanism in order to reduce repetitive queries to the DB:
void Application_BeginRequest(Object sender, EventArgs e)
{
//TODO: Cache sql queries
string requestUrl = Request.FilePath;
using (DBConn conn = new DBConn("GetRedirectUrl"))
{
conn["input"] = requestUrl;
string res = conn.ExecuteScalar()?.ToString();
if (!string.IsNullOrEmpty(res))
{
Response.Redirect301(res);
}
}
//TODO: Cache sql queries
using (DBConn conn = new DBConn("GetRewrittenUrl"))
{
conn["input"] = requestUrl;
string res = conn.ExecuteScalar()?.ToString();
if (!string.IsNullOrEmpty(res))
{
HttpContext.Current.RewritePath(res);
}
}
}