Accessing Azure SQL from Web App with EF Core, Docker and System Assigned Identity - sql-server

I'm trying to access a serverless azure SQL database from an Azure Web Application running a docker container under Linux. The container is a .Net Core 3.1 web application using the latest EF Core. The web app has been configured to use a system assigned identity.
For the SQL user, I use the following PS script to get an SID, where the object ID is the system assigned identity object ID:
$principal = Get-AzADServicePrincipal -ObjectId $objectId
foreach ($byte in $principal.ApplicationId.ToByteArray())
{
$byteGuid += [System.String]::Format("{0:X2}", $byte)
}
$sid = "0x" + $byteGuid
Then, I created the user with db_owner role to the database using the SID like this...
'CREATE USER [AppUser] WITH DEFAULT_SCHEMA=[dbo], SID=' + '$(AppSiD)' + ' , TYPE = E'
...similar to the process described here:
https://blog.bredvid.no/handling-azure-managed-identity-access-to-azure-sql-in-an-azure-devops-pipeline-1e74e1beb10b
I've also updated the EF instance using the following method:
https://learn.microsoft.com/en-us/azure/app-service/app-service-web-tutorial-connect-msi#modify-aspnet-core
When the application tried to access the DB, the following exception is thrown:
Microsoft.Data.SqlClient.SqlException (0x80131904): Login failed for user '<token-identified principal>'.
EDIT I don't believe the SQL user to be causing the issue, as the error occurs whether the user exists or not.
I'd prefer to fix the error above but if there is is an alternative way to connect to the DB without using a SQL user I would appreciate the advice.
Thanks
EDIT
Elaborated on the SQL user process as the link is down at the time of posting

First you need to make your SQL database AAD-enabled. Then you can create a user for your Managed Identity like this
CREATE USER [<identity-name>] FROM EXTERNAL PROVIDER;
And then of course assign permissions to that user as needed.

Related

Issue creating master key for Azure SQL Pool - Permission error

I'm trying to follow this tutorial but I'm having issues with granting CONTROL permission.
This is on a Dedicated SQL pool (formerly SQL DW) within Azure by following this tutorial.
I initially try CREATE MASTER KEY ENCRYPTION BY PASSWORD = '23987hxJ#KL95234nl0zBe'; which returns
User does not have permission to perform this action.
So I try to apply CONTROL permission to the user account:
GRANT CONTROL ON DATABASE::master TO useradmin
But this returns
Principal doesn't exist or doesn't have sufficient privileges.
I have search the web for a solution but I cant find one that has yet worked so any help or advice would be much appreciated!
To create MASTER key in azure SQL, follow below statement in Azure SQL data base.
CREATE MASTER KEY
GO
For more details refer this SO Thread by Alberto Morillo and also refer this Microsoft official document.
Updated:
I reproduced same thing in my environment its working fine .
sample code:
CREATE MASTER KEY ENCRYPTION BY PASSWORD='xxxx'
GO
CREATE DATABASE SCOPED CREDENTIAL [cred-name] WITH IDENTITY = 'User_name' , SECRET = 'xxxx'
GO

How do I connect to Azure SQL from an Azure function using a managed identity (no credentials in connection string)?

I have an Azure Function app, written in C# and using .NET Core (3.x) running on Linux. I would like this set of functions to be able to connect to an Azure SQL database. I have followed this process:
I ensured that the function app has system-assigned managed identity enabled:
I created a user in my database using CREATE USER ... FROM EXTERNAL PROVIDER and added the user to the appropriate roles (db_datareader and db_datawriter in my case). In my case, I had to create an Azure AD group and add the managed identity to the group, and then create the user for the group (there were two AD identities with the name of the function app, for some reason...).
I set up the connection string in the function app's settings. This is where I think I've gone wrong. I am not clear on how to specify the correct connection string. Connection strings I tried:
Data Source=my-database-server.database.windows.net;Initial Catalog=my-database did not work. I saw errors such as this: Login failed for user ''.
Data Source=my-database-server.database.windows.net;Initial Catalog=my-database;Authentication=Active Directory Integrated (using System.Data.SqlClient) did not work. I saw errors such as this: Keyword not supported: 'authentication'.
Data Source=my-database-server.database.windows.net;Initial Catalog=my-database;Authentication=Active Directory Integrated (using Microsoft.Data.SqlClient) I saw errors such as this: MSAL cannot determine the username (UPN) of the currently logged in user.
What is the magic connection string incantation, or step that I am missing?
Use Microsoft.Data.SqlClient instead of System.Data.SqlClient if getting Keyword not supported: 'authentication'
More details on various values for authentication= and suppported library versions can be found here:
https://learn.microsoft.com/en-us/sql/connect/ado-net/sql/azure-active-directory-authentication?view=sql-server-ver16#setting-azure-active-directory-authentication
I can't claim any credit for this solution, I found it on reddit of all places!

Azure AD user unable to connect to Azure SQL Error: 18456,State:1,Class:14

BACKGROUND
The user is defined in Azure AD and in Azure SQL.
test.user#company.com is defined and active in Azure AD. I’m able to log in with this user in Azure portal.
I have created a contained database user with the clause "from external provider" in the Azure SQL database and added the user to the db_datareader system role. The commands commits without error. I have compared the Asset ID in Azure AD and the SID in database and they match. I have tried with different users.
I am able to login as an AD User assigned to the SQL servers assigned "Active Directory Admin"
SQL Server users also login without any issue
Login test in SSMS
I have set default database to the specific database I’m trying to log into (Options-Connect to database).
I have tried with different Authentication modes:
“Azure Active Directory – Universal with MFA” and
“Azure Active Directory – Password”
When I try to login with SSMS I get
Error: 18456, state 1, class 14.
When I query [sys].[event_log] it returns
[event_systype]= 4, [event_subtype_desc] = login_failed_for_user.
PROCESS FOLLOWED
I have a user defined in Azure AD. (test.user#company.com)
In my Azure SQL database, I have set an Active Directory administrator.
I have created a user in SSMS test.user#company.com with the following syntax:
CREATE USER [test.user#company.com] FROM EXTERNAL PROVIDER;
I have assigned the user to the db_datareader role with the following syntax:
ALTER ROLE db_datareader ADD MEMBER [test.user#company.com]
ISSUE: When I try to connect as test.user#company.com, the connection fails and I get this error:
Login Failed for user test.user#company.com
Details of error contains:
Error Number: 18456, State: 1, Class: 14
I have tried to find an answer on learn.microsoft.com, googled my ass off and found some useful resources on this, but none that actually helps me with pinpointing what to do to resolve the issue. If anybody have an Idea of what I'm doing wrong, ref "PROCESS FOLLOWED" I'd be forever grateful :)
I solved it by a workaround, setting up a new database.
I did not find the cause of the problem, but it must be related to database setup "DTU"-"Basic" or some setting that I have managed to set without remembering.
Anyways, my process works when I set up a new database with "DTU"-"Standard" Configuration.
It seems to be some kind of encoding problem. After almost giving up and using a different DB, I tried creating a new one, but without some special characters. And suddenly, it worked.
If you can't change your database's password, you can just edit the connection string in another editor and it works as well (Notepad, VS code, etc).

SqlException: Cannot open database

I have problem with the IIS itself it seems that the database could not authenticate. The error shows like this:
SqlException: Cannot open database "dbPEMCOLoan" requested by the login. The login failed.
Login failed for user 'WORKGROUP\IAMPRO$'.
The problem right now is that I don't have any workgroup on my computer. See picture below:
and also here is my connection string:
"ConnectionStrings": {
"PEMCOLoan": "Data Source=IAMPRO;Initial Catalog=dbPEMCOLoan;Integrated Security=True;Connect Timeout=15;Encrypt=False;TrustServerCertificate=True;ApplicationIntent=ReadWrite;MultiSubnetFailover=False;"
}
I'm a bit new with the asp.net core framework and I'm trying my best to do the research on my own to fix the issue and tried those suggestions but never of them work because I couldn't find the domain WORKGROUP\IAMPRO$ itself.
Any help would be very much appreciated! Thanks!
WORKGROUP\IAMPRO$ is the local machine user account your IIS Application Pool runs and thus is used for Integrated Security (specified in your connection string).
Configure your Application Pool to run under a different user that is already granted access to your database or create a new, dedicated user account.
Using a dedicated user account is considered best practice since it allows to grant the specific privileges needed (on database and OS) and your App will not break when the password of your own user account is changed.

Prevent database access outside the application

We have a MVC application running with SQL Server database.
We are using windows authentication, and when we want to give user access to our site we add them in the active directory group SEUser.
We have given login as well as access permission to SEUser group to our database as well.
But the problem is since the AD group has permission to database so the user belonging to that group not only can access website but can also connect to the database from outside the application and can make changes to it as well.
So I am searching a lot to find any way where I can restrict user group to access database only when the request comes through our application and not from outside.
For that the first approach I thought of is to use impersonation/connect as approach, and allow only worker process account to connect to the database,
But the problem is we are accessing current logged in user information within stored procedures also by using methods like SYSTEM_USER and IS_MEMBER which considers current logged in user only and so we cannot use worker process approach.
Is there any way I can achieve this for my particular scenario? Please help
The short answer is there is no capability that would allow an authorized user to connect from one program (i.e. your middle tier), but not another (i.e. an interactive query program such as SSMS).
The best advice I can give you is to design your system under the assumption that the users will find a way to connect directly to the database, and therefore restrict their permissions as much as possible to avoid any problem when they decide to do so.
One strategy to limit what users can do on the system when connecting to the DB directly is to use stored procedures to limit what they should be able to do on the DB (i.e. they have access to run the SPs, and nothing else), granting permissions only through the SP execution via signatures.
I also strongly recommend using auditing to detect any abuse of the users’ privileges. Given that you expect all users to connect via your middle-tier application, it should be relatively easy to detect unusual activity.
One trick you may find interesting as a workaround is to use logon triggers to try to avoid accidental access through non-authorized programs (AKA. avoid the “I didn’t know” excuse). But be warned: This is not a security boundary, and it is easy to bypass, but it will help you keep honest people honest.
For example:
I grant access to a specific group on my system, but I would like to limit this group as much as possible to my app:
CREATE LOGIN [myDomain\myGroup] FROM WINDOWS
So I will create a logon trigger that will check the application name on the session, and block any app I haven’t approved for these users.
CREATE TRIGGER connection_limit_trigger
ON ALL SERVER
FOR LOGON
AS
BEGIN
IF( IS_SRVROLEMEMBER('sysadmin') != 1 )
BEGIN
IF( IS_MEMBER('myDomain\myGroup') = 1 )
BEGIN
DECLARE #appName nvarchar(256)
SELECT #appName = program_name FROM sys.dm_exec_sessions where session_id = ##SPID
IF( #appName != 'My approved app' )
ROLLBACK;
END
END
END;
Notice that this trigger will affect ALL my users, so I added checks to avoid unnecessary restrictions on certain users.
I have a very simple app that I approved (See the ApplicationName property on the connection string):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.Data.SqlClient;
namespace SampleAppSql
{
class Program
{
static void Main(string[] args)
{
SqlConnectionStringBuilder cnnstrbldr = new SqlConnectionStringBuilder();
cnnstrbldr.ApplicationName = #"My approved app";
cnnstrbldr.DataSource = #"."; //local machine
cnnstrbldr.IntegratedSecurity = true;
using (SqlConnection conn = new SqlConnection(cnnstrbldr.ConnectionString))
{
conn.Open();
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = #"SELECT ##version;";
string vers = (string)cmd.ExecuteScalar();
System.Console.WriteLine(#"SQL Server version: {0}", vers);
}
conn.Close();
}
}
}
}
When a user of this group tries to connect to SQL Server, the trigger will check the application name, and if it doesn’t match, the logon trigger will cause the connection to fail:
C:\>g:\temp\SampleAppSql.exe
SQL Server version: Microsoft SQL Server 2016 (RTM) …
C:\>sqlcmd -E -S .
Sqlcmd: Error: Microsoft ODBC Driver 13 for SQL Server : Logon failed for login 'myDomain\toto' due to trigger execution..
Please notice that this technique is not a security boundary, as the authorized users can simply manipulate the application name and bypass the trigger; but the offending user will not be able to deny that she/he tried to bypass your policy on purpose.
I hope this information helps.
For more details, I recommend the following articles:
Logon Triggers
(https://msdn.microsoft.com/en-us/library/bb326598.aspx)
Signing Stored Procedures in SQL Server (https://msdn.microsoft.com/en-us/library/bb669102(v=vs.110).aspx )
Customizing Permissions With Impersonation in SQL Server (https://msdn.microsoft.com/en-us/library/bb669087(v=vs.110).aspx )
SQL Server Audit (https://msdn.microsoft.com/en-us/library/cc280386.aspx )
-Raul
I don't think you should focus on verifying the application. I think you should instead verify the user's actions, in the Web Service (the MVC Controller). As this gives you the most fine grained control.
Then the Web Service should be the only component with direct network access to the database. There should be no harm in accessing the Web Service (the MVC Controller) from outside the intended UI (the MVC View)

Resources