Configuring Integrated Windows Authentication with SSRS and SQL DB Azure

Today let’s talk about Cloud and Azure. My new job gives me now the opportunity to work in a hybrid environment with some components hosted in a cloud including SQL Azure Databases. To get straight to the point, PaaS databases are different beasts and I my confirm DBA role is shifting to another dimension. The focus is more on providing higher value in the architecture design and tuning because resources are a big concern, at least in a different order of magnitude, because they are now treated as operational expenses (OpEx). Entering now in a World of code as infrastructure, provisioning such service has become an easy game and can be automated through Cloud provider APIs and specialized tools. My colleagues already did a lot of good jobs on this topic.

In this blog post I would like to focus on the authentication architecture design to connect to a SQL Azure DB. I already played with some SQL Azure DB with a simple authentication protocol that consisted in using SQL Logins and opening some firewall ports to expose the DB service on the internet. I guess this is a basic scenario for lot of people (including me) who want to play with such service. But what about enterprise-class scenarios? I had the chance to get involved to the implementation of the end-to-end Integrated Windows Authentication (IWA) between SSRS data sources on-premises and one of SQL Azure DB. SQL Login is likely the most common method used to connect for its simplicity, but like on-premises scenarios, it is not the best one in terms of security.

So where to start? First of all, let’s say that Microsoft provides some configuration clues in the BOL (Azure SQL Database and AAD section).

From an architecture standpoint we must meet the following prerequisites:

  • Active Directory Authentication installed on the concerned SSRS servers
  • Active Directory Federation Services (ADFS) configured to federate across on-premises your on-premises Active Directory (AD) and Azure AD (AAD)
  • Kerberos Constraint Delegation (KCD) enabled between SSRS and ADFs services
  • Kerberos authentication enabled in SSRS report (RSReportServer.config)
  • Azure Active Directory authentication configured with SQL DB Azure
  • Sounds complicated right? It could be regarding your context and which components you have access.

    Let’s show a very simplified chart of the authentication flow:

    154 - 0 - SSRS - SQL DB Azure Login flow

    Usually shops which own a hybrid environment with Azure already implemented the federation which was the case for me. So as DBA you will likely delegate some Active Directory stuff to right team.
    Let’s start with the easiest parts of this big cake: Installing ADALSQL library on SSRS servers is pretty straightforward so need to talk further about it. Once the library is installed, it gives access to a new Microsoft Azure SQL Database connection type in SSRS data source as show below:

    154 - 1 - SSRS datasource DB Azure Type

    => Kerberos delegation

    If you are already confident with Kerberos delegation with your SQL Server environment, configuring Kerberos delegation on ADFS didn’t raise special difficulties. You must still configure correctly the SPNs and then configure the Kerberos delegation. In this case, The SSRS service must be configured to delegate the authentication to the ADFS service.

    # Retrieve ADFS hostname
    Get-AdfsProperties | Select-Object Hostname
    setpn -A http/adfs_host_name.domainname domain-user-account

    # Configure SPN SSRS + ADFS
    setpn -A http/computername.domainname domain-user-account

    => AAD authentication with SQL DB Azure

    AAD authentication must be enabled on the SQL Azure DB before using IWA. As you know, SQL DB Azure provides different ways to connect including:

  • SQL based Login – the most basic method we may use when Windows authentication is not available
  • Azure Active Directory based Login – This method requires an underlying AAD infrastructure configured + one AAD account as Active Directory Admin of the SQL DB in Azure. This is mandatory to allow the Azure SQL Server to get permissions to read Azure AD and successfully accomplish tasks such as authentication of users through security group membership or creation of new users
  • Well, you may notice that enabling AAD authentication is not trivial :) So let’s dig further to the AAD authentication method. It provides 2 non-interactive ways Active Directory – Password and Active Directory – Integrated authentication that are suitable for many applications based on ADO.NET, JDCB, ODC used by SSRS data-sources. This is because these methods never result in pop-up dialog boxes which can be used. Other method includes interactive method like Active Directory – Universal with MFA suitable for administrative accounts (including DBAs) for obvious security reasons. These methods are illustrated below:

    154 - 2 - SQL DB Azure - Login

    After authentication, authorization comes into play. As DBA we must be aware of the different security model implied by this Azure service. In addition, regarding the login / user type, the access path will be different accordingly as follows:

    154 - 8 - Access Path

    Compared to on-premises SQL databases, there are only 2 unrestricted accounts including a Server Admin (SQL based Login) and an AAD admin created in master. These accounts are automatically mapped to the dbo user of each SQL Azure DB and are implicitly DB owner. Even these accounts are considered unrestricted, in fact it is not because they are not member of sysadmin server role (that is not available in SQL DB Azure by the way). For more details the BOL is your friend :)

    Here a PowerShell script sample that helps identifying each of them:

    # Server admin
    (Get-AzSqlServer -ResourceGroupName $ResourceGroup).SqlAdministratorLogin  

    # Active Directory admin
    (Get-AzSqlServerActiveDirectoryAdministrator -ResourceGroupName $ResourceGroup -ServerName $ServerName).DisplayName

    Other administrative roles are dbmanager and loginmanager which are respectively able to create Azure databases and to create logins. Members of these roles must be created in the master database.
    Finally, non-administrative users don’t need to access to the master database and may be SQL or AAD contained authentication-based users (making your database portable)
    Creation of AAD login / user requires using the clause FROM EXTERNAL PROVIDER in the CREATE USER TSQL command. Like on-premises environments, you can rely on AAD group for your security strategy.
    The sys.database_principals DMV is still available to get a picture of different users in each database:

    select name as username,
           create_date,
           modify_date,
           type_desc as type,
           authentication_type_desc as authentication_type
    from sys.database_principals
    where type not in ('A', 'G', 'R')
          and sid is not null
    order by username;

    154 - 9 - DB users

    Username values are not important here :) Note the type and authentication_type column values. In my context, we have a mix of AAD groups and users (EXTERNAL_USER/GROUP). Users with INSTANCE authentication type are server-level users with a correspond entry in master database. In the first line, the user is part of the dbmanager role.

    SELECT DP1.name AS DatabaseRoleName,  
        isnull (DP2.name, 'No members') AS DatabaseUserName  
    FROM sys.database_role_members AS DRM  
    RIGHT OUTER JOIN sys.database_principals AS DP1  
        ON DRM.role_principal_id = DP1.principal_id  
    LEFT OUTER JOIN sys.database_principals AS DP2  
        ON DRM.member_principal_id = DP2.principal_id  
    WHERE DP1.type = 'R'
    ORDER BY DP1.name;  
    GO

    154 - 9 - 2 - DB roles

    Referring to this quick overview of SQL DB Azure authentication and permissions, in the context of my project we only need to configure a dedicated AD account to get access the data in Azure. Because the security standard is group-based we only need to move this user to the corresponding group that is member of db_datareader role on the SQL DB Azure side.

    For DBAs the previous topics are familiar. However, the biggest part of the cake: the underlying AD and federation infrastructure is likely less. For modern DBAs in the cloud, authentication and connectivity are part of their new skills to gain. I don’t pretend to be an expert on this topic so the idea here is to share my experience I had on an issue we faced during the IWA implementation and drove me to improve my skills on the different components of the federation infrastructure including the ADFS server, the AD Azure connect component and the Azure Active Directory. After configuring the different components of the authentication infrastructure, we tried to configure the dedicated SSRS service account with the new SSRS data source and here the message we got when attempting to connect to the SQL Azure DB:

    Could not discover a user realm. (System.Data)

    Before continuing, let’s precise that the SSRS service account name (or User Principal Name) we configured on the AD on-premises side was in the form of domain.local\ssrs_account. After the AD Azure sync comes into play, on the AAD side the correspond AAD identity was ssrs_account@domain.onmicrosoft.com

    At this stage, I didn’t pay attention of this UPN and I naively believed that creating the user referring this identity on the SQL DB Azure will be the final step of the authentication architecture implementation:

    CREATE USER [ssrs_account@domain.onmicrosoft.com]
    FROM EXTERNAL PROVIDER;

    ALTER ROLE db_datareader ADD MEMBER [ssrs_account@domain.onmicrosoft.com];
    GO

    But as you guess, it was not the case and the authentication process failed. I spent some times to figure out what could be wrong.I admit my first DBA’s habit led me to try to look at an eventual SQL Server error log, but you know, we are dealing with a different beast and there is no SQL Server error log anymore to look at … In fact, to get a status of SQL Server connections SQL DB Azure provides auditing capabilities at different levels (server and db) with a default policy that includes FAILED_DATABASE_AUTHENTICATION_GROUP action to monitor successful and failed logins. In addition, consuming these events depends on the target storage (Storage Account, Logs Analytics). For instance, here a sample of results I got from our dedicated Log Analytics workspace with a search from the SQLSecurityAuditEvents category:

    154 - 7 - Logs Analytics

    But nothing relevant and related to my SSRS service account … After reading the BOL more carefully, I finally figured out that if I want to get a chance to find (maybe) something related to the AAD identity I had to look at the AAD side instead as stated to the follow section of the documentation:

    When using AAD Authentication, failed logins records will not appear in the SQL audit log. To view failed login audit records, you need to visit the Azure Active Directory portal, which logs details of these events.

    But again, the AAD audit trail didn’t contain any relevant records of my issue. So where to look at in this case? Well, I decided to review the authentication process in the federation part. In the error message it was about a missing realm … realm names come from the Kerberos authentication protocol and they serve practically the same purpose as domains and domain names. In my context because we are in a hybrid authentication infrastructure, in order to make the authentication process working correctly a federation must be configured and it was effective in my case. As said previously, the federation part includes an ADFS server (provides SSO capabilities and IWA authentication for applications), an AD Sync component (To sync identities between AD and AAD) and a configured AAD as shown below:

    154 - 10 - ADFS

    A basic configuration we may retrieve in many shops. However, the remarkable thing was the different form of the SSRS realm between AD on-premises and AAD after the synchronization stuff of the AD Azure connect component. Getting support of my team, it became quickly obvious the root cause was on the federation infrastructure side. In normal case, with verified users we normally get the same UPN on the both side as shown below:

    domain.com\user (AD on-premises) => domain.com\user (AAD)

    Something important to bear in mind is that the Azure AD Connect tool comes with a troubleshooting section that was helpful in my case because it helped to validate our suspicion:

    154 - 4 - AD Connect troubleshooting

    154 - 5 - AD Connect troubleshooting Result

    The tool diagnosed there was a mismatch between the userPrincipalName attribute value between the AD on-premises and the AAD because the UPN suffix was not verified by the AAD Tenant.
    Using the Get-AzureDDomain cmdlet confirmed the only domain name: domain.com that was federated as shown below:

    154 - 11 - AAD domain

    As a reminder, the SSRS account was created with an UPN domain suffix (domain.local) which was not verified by the AAD (domain.local is different from domain.com). As stated by the troubleshooting section when the UPN suffix is not verified with the AAD Tenant, Azure AD takes different inputs into account in the given order to calculate the UPN prefix in the cloud resulting to create the wrong one in my case (ssrs_account@domain.onmicrosoft.com).

    Finally changing the correct UPN suffix to domain.com fixed this annoying issue!

    154 - 12 - SSRS auth ok

    See you!

    Laisser un commentaire