Run SQL query using powershell and AAD authentication with an SSO account - powershell

I am trying to run a set of queries from Cloud Shell using powershell that require and Azure AD user. I generally use invoke-sqlcmd using the server admin and password but the specific query I want to run require an AD user. I would like to run the query as myself. I have found that I can use the ConnectionString parameter to do this, but my problem is I do not have a password as I login to Azure via SSO. I basically want to mimic the process of going to my DB in Azure, going to query editor, using AAD authentication and running a query, but with powershell. Is there a way I can do this? Example of what I am trying to do below:
$serverName = 'server'
$dbName = 'database'
$query = 'CREATE USER [AAD_User] FROM EXTERNAL PROVIDER;'
Invoke-Sqlcmd -ServerInstance $ServerName -Database $dbName -Query $query
When I attempt this I get:
Invoke-Sqlcmd: Cannot authenticate using Kerberos. Ensure Kerberos has been initialized on the client with 'kinit' and a Service Principal Name has been registered for the SQL Server to allow Kerberos authentication.

I tried to reproduce the same in my environment and got the results like below:
As SSO is enabled and you do not have a password, you can try generating access token to perform the action.
I used the below script to add the user in Azure Database:
Connect-AzAccount
$connectionString = "Server=testrukserver.database.windows.net;Initial Catalog=testdb;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30"
$accessToken = (Get-AzAccessToken -ResourceUrl https://database.windows.net).Token
$sqlConn = New-Object System.Data.SqlClient.SqlConnection
$sqlConn.ConnectionString = $connectionString
$sqlConn.AccessToken = $accessToken
$sqlConn.Open()
Invoke-Sqlcmd -ServerInstance testrukserver.database.windows.net -Database testdb -AccessToken $accessToken -query 'CREATE USER [test#xxx.onmicrosoft.com] FROM EXTERNAL PROVIDER'
$sqlConn.Close()
The user is added sccessfully in the Azure Database like below:
Reference:
Connecting to Azure SQL Database with AAD Authentication using Powershell by alex stuart

Related

Execute an App registration without AzureAD

For a professional project, a chunk of the pipeline must be able to create an application (the first App registration, so I only have a global Admin) automatically within Azure AD. So far I used AzureAD which works well with Powershell 5.6 on Windows.
I now must be able to run the code with Ubuntu 20.04 and its Powershell 7.2. Unfortunately for me, AzureAD module is only supported on non-core Windows PowerShell, therefore it does not work on core PS6 or PS7. A very simplified piece of code is the following:
# Connection infos
$tenantId = "abcdef12345-1234-1234-124-abcdef12346789"
$account = "my_admin#domain.com" # Is cloud Admin by default
$password = ConvertTo-SecureString "MyPassword" -AsPlainText -Force
$psCred = New-Object System.Management.Automation.PSCredential -ArgumentList ($account, $password)
Connect-AzureAD -Credential $psCred -Tenant $tenantId
# Create app
$appName = "MyApp"
New-App -appName $appName -tenant_id $tenantId
I am stuck and my question is the following: how could I run such an operation with Powershell 7.2 considering AzureAD is not usable? I did check Connect-MgGraph for the connection part only (https://github.com/microsoftgraph/msgraph-sdk-powershell) but the clientId is an infos that I don't have -and want to create-.
Thanks in advance
You can use DeviceLogin as explained in this article to obtain an oAuth access token for you Global Administrator account in PowerShell (independent of the version) but this first step needs a human interaction.
After obtaining the token, you can use it to make Graph API calls with your Global Administrator permissions to create an application.
Once you create your first application, you must attribute required permissions and use it to automate the process (obtain token programmatically using API calls) for application creation in PowerShell.
You could use Resource Owner Password Credentials (ROPC) to authenticate, however Microsoft actively discourages it in their documentation due to the security implications of sending a password over the wire.
If the security issues present with this method of authentication are still tolerated within your acceptance criteria, you would still need a ClientID. Luckily, AzureAD has a well-known ClientID that you can use to authenticate. This ID is 1950a258-227b-4e31-a9cf-717495945fc2
The below Powershell code should get you started. I've basically translated the HTTP request within Microsoft's documentation into a splatted Invoke-RestMethod command.
$LoginWithROPCParameters = #{
URI = "https://login.microsoftonline.com/contoso.onmicrosoft.com/oauth2/v2.0/token"
Method = "POST"
Body = #{
client_id = "1950a258-227b-4e31-a9cf-717495945fc2"
scope = "user.read openid profile offline_access"
username = "username#contoso.onmicrosoft.com"
password = "hunter2"
grant_type = "password"
}
}
Invoke-RestMethod #LoginWithROPCParameters

How to add Managed Identity user to Azure SQL database with Powershell?

I'm trying to create a deploy script in powershell to create and configure the environment for a web application. The web app uses user-assigned Managed Identity to reach the SQL server.
I have to run the following command in the SQL server:
CREATE USER [<identity-name>] FROM EXTERNAL PROVIDER;
But this command errors when I use sql adminstrator login: "Only connections established with Active Directory accounts can create other Active Directory users."
I add an AD administrator with Set-AzSqlServerActiveDirectoryAdministrator
But how can use this AD login from powershell to run the SQL command?
It seems that Invoke-Sqlcmd (or at least the version of it that I have) doesn't support Azure AD authentication.
I've used a PowerShell script like this to create users (you may need to update sqlcmd):
$query = "CREATE USER [$identityName] FROM EXTERNAL PROVIDER;"
sqlcmd -S $serverHostName -d $databaseName -G -N -U $username -t 120 -b -Q $query
The -G flag there tells it to use Azure AD authentication, in this case it will use interactive authentication and require you to login.
If I recall, you can use the -U and -P flags to define the username and password as well for the Azure AD user, but that'll only work if the user doesn't have MFA enabled and isn't a federated user.
Apparently the Azure AD login only works with the -ConnectionString parameter. So the solution is:
# Create User Managed Identity
$mi = New-AzUserAssignedIdentity -ResourceGroupName $resourceGroupName -Name $managedIdentityName
# Enable AD login for SQL server
Set-AzSqlServerActiveDirectoryAdministrator -ServerName $sqlServerName -ResourceGroupName $resourceGroupName -DisplayName $AdAdminUser -ObjectId $AdAdminObjectId
# Add Managed identity login to SQL server
$connectString = "Server=tcp:$sqlServerName.database.windows.net,1433;Initial Catalog=$sqlDBName;Authentication=Active Directory Password;user=$AdAdminUser;pwd=$AdAdminPw"
$query = "CREATE USER [$managedIdentityName] FROM EXTERNAL PROVIDER;"
Invoke-Sqlcmd -ConnectionString $connectString -Query $query -OutputSqlErrors $true

Cannot use Azure SQL with Azure DevOps Server 2019 - (Azure Government)

I have been struggling to get my DevOpsServer 2019-RC1 installation to see my Azure SQL Server
My DevOpsServer install is on an Azure VM, as recommended
I have implemented everything from the below documentation regarding the set up of an MSI for the VM, and granting the MSI access to Azure SQL via AAD authentication:
https://learn.microsoft.com/en-us/tfs/server/install/install-azure-sql
I have also added the VNET where the VM NIC is located, as a VNET firewall rule on the Azure SQL Server to ensure there are no connection issues
My DevOpsServer refuses to see the Azure SQL Server or its databases
To confirm that Azure SQL is not blocked from the VM, I successfully created an ODBC system DSN connection on the VM, which allows me to see the Azure SQL Server, and its Databases
Per the reference documentation:
When setting up a new DevOps Server instance, i selected "This is a
new Azure DevOps Server deployment"
On the Database page of the configuration wizard, specify the Azure SQL
Database server instance, typically in the form of
"SQLInstanceName.database.windows.net"
Please let me know if there is anything else i can do to help the Devops Server Configuration Wizard see my Azure SQL Server and Databases
PS I am trying to get this working in Azure Government (MAG) if this changes the capability...
Error received when attempting to connect to the SQL Database programmatically via the following Powershell script:
# Retrieve the access token
$response = Invoke-WebRequest -Uri 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fdatabase.usgovcloudapi.net' -Method GET -Headers #{Metadata="true"}
$content = $response.Content | ConvertFrom-Json
$AccessToken = $content.access_token
# Create the connection
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Data Source = test-sqlsrv.database.usgovcloudapi.net; Initial Catalog = inldb"
$SqlConnection.AccessToken = $AccessToken
$SqlConnection.Open()
# Send a Query
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = "SELECT * from <TABLE>;"
$SqlCmd.Connection = $SqlConnection
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
$DataSet = New-Object System.Data.DataSet
$SqlAdapter.Fill($DataSet)
Try running ALTER USER [VMName] WITH DEFAULT_SCHEMA=dbo from both the collection and config DBs. I have a PR out to add this to the documentation and this might be causing your issue.
Try connecting to the SQL instance via Powershell instead of Azure DevOps Server.
You can run the following script to do that:
# Retrieve the access token
$response = Invoke-WebRequest -Uri 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fdatabase.windows.net%2F' -Method GET -Headers #{Metadata="true"}
$content = $response.Content | ConvertFrom-Json
$AccessToken = $content.access_token
# Create the connection
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Data Source = <AZURE-SQL-SERVERNAME>; Initial Catalog = <DATABASE>"
$SqlConnection.AccessToken = $AccessToken
$SqlConnection.Open()
# Send a Query
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = "SELECT * from <TABLE>;"
$SqlCmd.Connection = $SqlConnection
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
$DataSet = New-Object System.Data.DataSet
$SqlAdapter.Fill($DataSet)
This should at least give you a more descriptive error to debug.
Gvazzana, I also recommend testing with the script danwkennedy provided, but be sure to change database.windows.net to database.usgovcloudapi.net for Azure Government.
I would pay close attention to any errors around obtaining an access token and errors associated with opening the SQL connection.
If nothing's standing out is it possible to capture a Fiddler trace?
I agree that you should perform the PowerShell test to test your MSI. It looks like you are having issues reaching the IP to get the access token. If you are attempting to connect from a Government network, it is likely that you are going through some type of web proxy service (Blue Coat, etc.) to get to the internet. You can maybe trick the proxy by emulating the user agent string from a browser by using the -UserAgent parameter on your Invoke-WebRequest command.
If that doesn't work, you may need to reach out to your proxy team to troubleshoot the issue.
Lastly, if you are able to test successfully in PowerShell, but you still get the connection test error in the DevOps install, make sure to follow the steps here:
https://learn.microsoft.com/en-us/tfs/server/install/install-azure-sql
I forgot to add the user to the master DB... Once I did that, everything worked. Good luck.
You can access to your Azure Devops database with your Windows Authentication level. So your Windows login user should have configured sysadmin privilege in your database (e.g Microsoft SQL server)

New-AzureRmWebAppBackup errors out on "master" db

I'm attempting to script an Azure Web App backup in PowerShell.
These commands:
$DatabaseBackupSetting = New-AzureRmWebAppDatabaseBackupSetting -Name $DatabaseName `
-ConnectionString $ConnectionStrings[0].ConnectionString -DatabaseType "SqlAzure"
New-AzureRmWebAppBackup -ResourceGroupName $ResourceGroupName -Name $Site -StorageAccountUrl $SasUrl `
-Databases $DatabaseBackupSetting -BackupName ($Site + "_backup_" + (Get-Date -Format FileDateTimeUniversal)).ToLower()
Should back up the site and the attached db.
Here is the connection string I'm passing in to New-AzureRmWebAppDatabaseBackupSetting:
Server=tcp:[MYSERVER].database.windows.net,1433;Initial Catalog=demo-dev;Persist Security Info=False;User ID=demoadmin;Password=[MY_PASSWORD];MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;
When I run the New-AzureRmWebAppBackup command and check the status I see:
The server principal "demoadmin" is not able to access the database "master" under the current security context.
Cannot open database "master" requested by the login. The login failed.
Login failed for user 'demoadmin'.
I can't figure out how to tell the command to ignore the "master" db.
Any thoughts?

Credentials using Invoke-Sqlcmd against sql azure

I'm attempting to run a powershell build script against a sql azure database but receiving Login failed for user 'X'.
I'm fairly convinced the credentials are correct as they were taken straight from the live application config.
This is the command I'm using:
Invoke-Sqlcmd -InputFile "Build.sql" -ServerInstance $server -Database $database `
-WarningAction SilentlyContinue -OutputSqlErrors $false `
-Username $username -Password $password -EncryptConnection
I had this working with sqlcmd in a batch file so I'm wondering if it's got anything to do with the way the credentials are being sent, trusted_connection=false doesn't appear to be an option I can try.
It could be the password contains a few special characters that Azure/Invoke-sqlcmd does not handle (such as dollar, single or double quote, parentheses). I tried using the Azure interface and surrounding the password with single-quotes (we had a dollar-sign in the password), but that did not work. So, we simply removed the special character and now it is OK. see: Powershell Invoke-Sqlcmd Login Failed
and
https://mohitgoyal.co/2017/08/09/vsts-azure-sql-database-deployment-task-keeps-failing-with-error-login-failed-for-user/
When connecting to SQL Azure the login name must be of the form user#server. So if you created an user 'foo' and a server 'bar', the login must be foo#bar. See Managing Databases and Logins in Azure SQL Database:
Because some tools implement tabular data stream (TDS) differently, you may need to append the Azure SQL Database server name to the login in the connection string using the <login>#<server> notation. In these cases, separate the login and Azure SQL Database server name with the # symbol. For example, if your login was named login1 and the fully qualified name of your Azure SQL Database server is servername.database.windows.net, the username parameter of your connection string should be: login1#servername.
CREATE LOGIN also explains this:
In some methods of connecting to SQL Database, such as sqlcmd, you must append the SQL Database server name to the login name in the connection string by using the <login>#<server> notation. For example, if your login is login1 and the fully qualified name of the SQL Database server is servername.database.windows.net, the username parameter of the connection string should be login1#servername.