There’s nothing more important than securing access to your organization’s data. Here’s how to set up your Azure SQL database so that only authorized applications can get to it.
In Coding Azure 4: Securing a Web Service in an App Service to Access an Azure SQL Database, I created and assigned a Managed Identity to an App Service holding a Web Service that accesses an Azure SQL database. In this post, I’m going to take advantage of that identity to allow only that App Service (or, rather, the Web Service running inside the App Service) to access my database. After doing that, I’m going to show how to further secure your database using something less “cloud-based”: IP addresses.
As I discussed in my previous post, a Managed Identity and a user are both examples of service principals—i.e., things you can assign permissions to (users also have account information assigned to them). One of the places you can use a service principal is within an Azure SQL database, provided you’ve set up your Azure SQL database resource to use Entra Id as your authentication provider, as I did in Coding Azure 2: Configuring an Azure SQL Database.
In a database, “giving permissions” begins with setting up your Managed Identity as a user for your database. To do that, start SQL Server Management Studio and connect to your Azure SQL database server (in my case, that’s warehousedbserver.database.windows.net).
To add your Managed Identity as a user:
Your user will now show up in SQL Server Management Studio, under your database’s Users node. To confirm that your user has Connect permissions:
You could add additional settings/permissions for your Azure SQL resource to your Managed Identity (e.g., give your identity a database role or a default schema). However, the less functionality the identity has in this resource, the more secure your database is. The minimum that you need to provide is access to individual tables in the database, and that doesn’t require anything more than the Connect permissions already granted.
The next step is to give your Managed Identity user access to the table it needs. Initially, all I want my identity to be able to do is return all the rows from my WarehouseDB’s SalesLT.Products table. To do that:
But we can do a little more to make sure that only our Web Service can access our Azure SQL database by leveraging your App Service’s TCP addresses and Azure SQL’s built-in firewall.
Your App Service has a set of outbound TCP addresses that are used when your Web Service sends a request (for example, the requests sent to your Azure SQL database). You can find those outbound addresses on your App Service’s Overview page or from your App Service’s left-hand menu under Settings | Networking. In either place, look for the label Outbound traffic configuration to find the list of addresses.
Now that you have that list, you can limit your database resource to only accept resources from those addresses.
To do that, in the Azure Portal, surf to your Azure SQL to see the database resources you’ve set up. Your database resource appears in that list twice: a SQL database and SQL server. You can give your App Service access at either level.
The database-level rules are processed first and, if your App Service is denied at that level, then your request will be rejected regardless of the setting at the server level. Database-level rules can make sense if you allow a large number of users at the server level and then want to selectively deny access to individual databases for users or resources allowed access at the database level. That is a strategy that adds complexity to your security configuration and the resulting database-level rules are much less visible than those set in the Azure Portal.
To set your server-level rules:
You’ve now whitelisted your App Service for your database. Which raises the question: Without this rule in place, how has your App Service been able to access your database resource?
Up until now, your App Service has been getting access through a firewall exception that allows all Azure Services and resources to send requests to your database server. You need to turn that off now (otherwise, putting in the IP addresses for your App Service is redundant).
To do that, look below the list of firewall rules that you just added to and find the checkbox labeled Allow Azure services and resources … . Uncheck that checkbox and click the Save button at the bottom of the page to commit your changes.
Having said that, just because you can do something doesn’t mean that you should do something. The more measures you take to secure access to your applications, the more likely it is that, over time and the changes time brings, your application will fail.
If, for example, you destroy and recreate your App Service, it may get a new set of outbound addresses … new addresses which, of course, will be incompatible with the settings in your database’s firewall. Alternatively, if you change your App Service’s service plan from Basic, Standard or Premium to Premium2 or Premium3, then your App Service will get additional outbound addresses which, again, won’t be whitelisted in your database’s firewall but your App Service will use.
And you may do nothing at all and still have your App Service’s outbound IP addresses change—Microsoft does not guarantee that these are static addresses. The Azure teams does, however, try to send notifications of IP address changes out approximately 90 days before the change, giving you time to plan for the change.
You can address this just by “being careful” when creating your App Service, but a better choice would be to take advantage of Azure’s templates for defining services. I’ll be covering that in a later post. Alternatively, if you like this idea of whitelisting your App Service but would prefer to have a guaranteed static IP address, you can consider upgrading to (and paying for) an App Service Environment.
Or you may decide that the default exception that limits access to your database resource to other items in your Azure tenant may be sufficient. I’m not here to judge.
Now that you’ve got a data tier (your Azure SQL Database) and a middle tier (your App Service holding your Web Service), you need a frontend. Before I cover that, though, now that you have deployed code, it makes sense to turn on debugging and logging. I’ll cover that in my next post and, after that, walk through creating both client-side and server-side frontends.
Peter Vogel is the author of the Coding Azure series, providing full-stack consulting from UX design through object modeling to database design. Peter holds multiple Azure certifications in Azure administration, architecture, development and security. He is also a Microsoft Certified Trainer.