Connecting to Azure SQL from App Service using AAD identity - azure-sql-database

An on-premise web application (.net 4.6.1) which uses Windows Authentication for its users and then AD Integrated Authentication to connect to a MS SQL database is been migrated to Azure.
Ideally, the existing security mechanism of granting permissions to AD users on database objects and let the DB be security source of the application should be kept.
A copy of the SQL database has already been created and configured.
If I run the web application locally but using the new Azure database everything works as expected.
If I run this command I get the expected AD user:
SELECT CURRENT_USER;
Now, when I deploy exactly the same application to an Azure App Service and enable Azure Active Directory Authentication and Managed Service Identity, the user is authenticated correctly on the Web application but it is not able to connect to the SQL database and the following error is returned:
Errors = System.Data.SqlClient.SqlErrorCollection ClientConnectionId =
e9f0c48a-3159-465c-ab72-c1da99761b8f Class = 14 LineNumber = 65536
Number = 18456 Procedure = Server =
xxxxxxxxxxx.tr4.canadacentral1-a.worker.database.windows.net,11057
State = 1 Source = .Net SqlClient Data Provider ErrorCode =
-2146232060 Message = Login failed for user 'NT AUTHORITY\ANONYMOUS LOGON'
If I disable Managed Service Identity, I get this error instead:
InnerExceptions =
System.Collections.ObjectModel.ReadOnlyCollection`1[System.Exception]
Message = One or more errors occurred. Data =
System.Collections.ListDictionaryInternal InnerException =
Microsoft.Azure.Services.AppAuthentication.AzureServiceTokenProviderException:
Parameters: Connection String: [No connection string specified],
Resource: https://database.windows.net/, Authority: . Exception
Message: Tried the following 4 methods to get an access token, but
none of them worked. Parameters: Connection String: [No connection
string specified], Resource: https://database.windows.net/, Authority:
. Exception Message: Tried to get token using Managed Service
Identity. Unable to connect to the Managed Service Identity (MSI)
endpoint. Please check that you are running on an Azure resource that
has MSI setup. Parameters: Connection String: [No connection string
specified], Resource: https://database.windows.net/, Authority: .
Exception Message: Tried to get token using Visual Studio. Access
token could not be acquired. Visual Studio Token provider file not
found at
"D:\local\LocalAppData.IdentityService\AzureServiceAuth\tokenprovider.json"
Parameters: Connection String: [No connection string specified],
Resource: https://database.windows.net/, Authority: . Exception
Message: Tried to get token using Azure CLI. Access token could not be
acquired. 'az' is not recognized as an internal or external command,
operable program or batch file. Parameters: Connection String: [No
connection string specified], Resource: https://database.windows.net/,
Authority: https://login.microsoftonline.com/common. Exception
Message: Tried to get token using Active Directory Integrated
Authentication. Access token could not be acquired.
get_user_name_failed: Failed to get user nameInner Exception : The
format of the specified domain name is invalidat
Microsoft.Azure.Services.AppAuthentication.AzureServiceTokenProvider.d__14.MoveNext()
Is it what I'm trying to do possible? If yes, what am I missing? Any thoughts will be appreciated.
For reference, this is the method returning the SQL connection:
private SqlConnection GetSqlConnection()
{
var accessToken = new AzureServiceTokenProvider().GetAccessTokenAsync("https://database.windows.net/").Result;
return new SqlConnection
{
ConnectionString = WebConfigurationManager.ConnectionStrings["Default"].ConnectionString,
AccessToken = accessToken
};
}
... and this is the connection string:
<connectionStrings>
<add name="Default" connectionString="Data Source=myserver.database.windows.net;Initial Catalog=MyDB;" providerName="System.Data.SqlClient" />
</connectionStrings>
Note: The local AD is been synchronized with its Azure AD counterpart.

I think to solve your issue you have to do the following:
Grant access for the user as external provider in the database: (you can also find in AAD, under Enterprise applications when you select All applications). Important to make sure, that app service identity is already created at this moment.
For a web app it is the name of the web app
If you are using deployment slots the sql user name is {application-name}/slots/{slot-name}
If you are using User managed identity, you also have to specify app setting AzureServicesAuthConnectionString with the following value: RunAs=App;AppId={ClientId of identity}
Change your connection string and web config to use the interactive authentication.
Connection string can be something like this: Server=tcp:{server}.database.windows.net,1433;Initial Catalog={DatabaseName};Persist Security Info=False;MultipleActiveResultSets=True;Encrypt=True;TrustServerCertificate=False;Authentication='Active Directory Interactive'.
This also works with EntityFramework, but if you set up connection string directly in Azure you need to choose Custom instead of SqlAzure as a provider.
In web.config add this
<SqlAuthenticationProviders>
<providers>
<add name="Active Directory Interactive" type="Microsoft.Azure.Services.AppAuthentication.SqlAppAuthenticationProvider, Microsoft.Azure.Services.AppAuthentication" />
</providers>
</SqlAuthenticationProviders>

Make sure you have added the identity user in your Azure SQL and granted required privileges.
CREATE USER [MyAppIdentity] FROM EXTERNAL PROVIDER
GO
ALTER ROLE db_datareader ADD MEMBER [MyAppIdentity];
ALTER ROLE db_datawriter ADD MEMBER [MyAppIdentity];

Once you deploy the application, please put your application settings and connection string to your webapp Application Settings option on Azure. Refer to this article.
Note: It has pulled the value from the App Settings configured in the Azure App Service’s – Application Settings blade but not from the Web.config file. This way, you can change these configurable values whenever you like to change without depending on developers. The same rule applies even for Connection String.

Related

sqlalchemy Azure SQL Token Authentication Failure

We are trying to connect and insert data into our AZURE SQL DB using sqlalchemy and pandas.dataframe.to_sql using our service principal and token. The problem is that we are able to connect to one database perfectly but to another database we are getting the following error
sqlalchemy.exc.InterfaceError: (pyodbc.InterfaceError) ('28000', "[28000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Login failed for user '<token-identified principal>'. (18456) (SQLDriverConnect); [28000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Login failed for user '<token-identified principal>'. (18456)") (Background on this error at: https://sqlalche.me/e/14/rvf5)
We are trying to login via Service Principal using client id, client secret & Tenant ID. All the values have been verified and are working fine to connect to the database using Azure databricks.
Any help would be highly appreciated.
The problem is that we are able to connect to one database perfectly but to another database, we are getting the Login failed for user '<token-identified principal>' error.
According to documentation, if you are using any external provider then you need to create and map the required permissions to Azure AD identities.
CREATE USER <Azure_AD_principal_name> FROM EXTERNAL PROVIDER;
CREATE USER [bob#contoso.com] FROM EXTERNAL PROVIDER;
CREATE USER [alice#fabrikam.onmicrosoft.com] FROM EXTERNAL PROVIDER;
And after that, as suggested by Jason Pan , make sure to On Identity status on portal.
Updated answer:
According to Radiatelabs, the issue got fixed after copying the whole database from DEV to UAT and creating the UAT user in the database.
References: Login Failed for user ``, Login failed for user token-identified principal when web app is in an AAD Group ,and Login failed for user 'token-identified principal' but works in Data Studio

Get accesstoken using AzureServiceTokenProvider in SSIS script task deployed to Azure Data Factory SSIS IR

I am trying to invoke an Azure Rest API from SSIS script task. I need a bearer token to authenticate the request.
I am using AzureServiceTokenProvider to get the access token.
AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider();
string accessToken =
azureServiceTokenProvider.GetAccessTokenAsync("https://management.azure.com/").Result;
This code worked and I was able to get the token from Visual studio. However, it fails when the package is deployed to Azure SSISDB IR.
The error message is as below:
Parameters: Connection String: [No connection string specified], Resource:
https://vault.azure.net, Authority: https://management.azure.com/, Authority: . Exception
Message: Tried the following 3 methods to get an access token, but none of them worked.
Parameters: Connection String: [No connection string specified], Resource:
https://vault.azure.net, Authority: https://management.azure.com/, Authority: . Exception
Message: Tried to get token using Managed Service Identity. Unable to connect to the
instance Metadata Service (IMDS).
Skipping request to the Managed Service Identity (MSI) token endpoint.
I have the managed identity created and configured on the Azure resources.
Any inputs on resolving this error?
Or is there any other way to get the bearer token?
Any help is appreciated!

Trying to connect Polybase to Oracle leads to Login failed. The login is from an untrusted domain and cannot be used with Integrated authentication

I'm using SQL Server 2019 and try to connect to a Oracle DB via Polybase:
CREATE DATABASE SCOPED CREDENTIAL OracleUser WITH IDENTITY = 'username', Secret = 'password';
CREATE EXTERNAL DATA SOURCE [OrDB] WITH (LOCATION = N'oracle://192.168.1.5:1521'),
CREDENTIAL = OracleUser);
I'm getting the error:
Login failed. The login is from an untrusted domain and cannot be used with Integrated authentication.
However the user is not a domain user and oracle does not use integrated authentication.
As I mentioned in my comment above, you get this error if you are logged into your SQL Server instance with integrated security. This is due to a regression bug in SQL Server 2019.
Log in with SQL authentication instead, and it will work.
try this:
CREATE EXTERNAL DATA SOURCE [OrDB] WITH (LOCATION = N'oracle://192.168.1.5:1521'),
CREDENTIAL = OracleUser,
CONNECTION_OPTIONS = 'UseDefaultEncryptionOptions=false'
);

How to specify Authentication in RegisteredServer

based on my question about creating RegisteredServer in Microsoft.SqlServer.Management.RegisteredServers,
Unable to create RegisteredServer in Microsoft.SqlServer.Management.RegisteredServers, I work on adding a database from Azure SQL Server. I could add a database but the authentication is based on Windows Authentication
Absolutely, I can not connect to Azure:
Therefore I am looking for a solution to specify authentication in C# code. It is strange because I pass my connection string with username and password:
var registeredServer = new RegisteredServer(serverName)
{
ConnectionString = "Server=tcp:server.database.windows.net,1433;Initial Catalog=...;Persist Security Info=true;User ID=...;Password=....;MultipleActiveResultSets=True;Encrypt=True;TrustServerCertificate=False;"
}
First, Azure SQL supports AAD authentication. As far as I know, the windows authentication is suitable for local SQL Server.
And, you need to set AAD admin for your Azure SQL server
After that, you can conect to your Azure SQL with AAD credential. If your local accounts are synced to Azure AD with AD Connect. Then you should be able to use AD credential to connect to Azure SQL too.
Finally, I solved it, we need to install System.Security.Cryptography.ProtectedData package in order to set the connection string:
Install-Package System.Security.Cryptography.ProtectedData -Version 4.6.0
then, we need to specify CredentialPersistenceType and AuthenticationType like this:
var registeredServer = new RegisteredServer(databaseEngineServerGroup, serverName)
{
ConnectionString = localConnectionString,
Description = $"This is a sample connection to {serverName}",
CredentialPersistenceType = CredentialPersistenceType.PersistLoginNameAndPassword,
AuthenticationType = 1,
};

Insufficient Permissions with Access Token to Azure Data Catalog

I'm trying to issue an API call to Azure Data Catalog using a Client Secret, however I get a Permission denied error.
I'm able to create the token and I've given the client application the necessary permissions in AAD.
If I change the authentication method to use delegated access where the user signs in, it works but if i try to use a client secret the generated token does not have the proper permissions.
Here's some code that I've altered using various samples
The token from this code works
//get the token
authResult = await authContext.AcquireTokenAsync(resourceUri, clientId, new Uri(redirectUri), new PlatformParameters(PromptBehavior.Always));
//the token from this code doesn't work
IConfidentialClientApplication app;
app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithClientSecret(clientSecret)
.WithAuthority(new Uri(authorityuri))
.Build();
string[] scopes = new string[] { "https://api.azuredatacatalog.com/.default" };
result = await app.AcquireTokenForClient(scopes);
I get this error The remote server returned an error:
(403) AccessDenied : Access denied..
Following is high level steps to configure the Service Principal configuration to support ADC REST API
Azure Active Directory | App Registration – Select Web app / API for Application Type and URL can be anything Example:  http://portal.azure.com
Select the Application | Required Permission | Add the Microsoft Azure Data Catalog
Navigate to http://www.azuredatacatalog.com | Settings - Add the Service Principal to Catalog User based on the business need you can add to glossary admin / catalog admin. The format is clientid#tenantid
****Clientid = Azure Active Directory | App Registration | Application ID**
**TenantID = Azure Active Directory | Properties | Directory ID****
Follow the Service Principal Authentication sample REST API code to build your solution https://github.com/Azure-Samples/data-catalog-dotnet-service-principal-get-started