microsoft / DacFx

DacFx, SqlPackage, and other SQL development libraries enable declarative database development and database portability across SQL versions and environments. Share feedback here on dacpacs, bacpacs, and SQL projects.
https://aka.ms/sqlpackage-ref
MIT License
307 stars 18 forks source link

SqlPackage doesn't honor impersonation from PowerShell #297

Open kkloss-od opened 1 year ago

kkloss-od commented 1 year ago

I have a scenario where a CD pipeline needs to launch PowerShell as a service user, impersonate another service user which has privileges on a remote SQL Server, and use sqlpackage to publish a DACPAC to that server. sqlpackage doesn't appear to actually use the impersonated user when establishing the connection.

Steps to Reproduce:

  1. Via PInvoke, use the advapi32 functions LogonUser and DuplicateToken to create a login token with the Delegation impersonation level
  2. Create a new System.Security.Principal.WindowsIdentity object with the impersonation token
  3. Call Impersonate on the new identity
  4. Observe that calling System.Security.Principal.WindowsIdentity::GetCurrent() from PowerShell shows the user being impersonated
  5. Run sqlpackage and use Windows authentication by including Integrated Security=true;TrustServerCertificate=true;Trusted_Connection=yes in the connection string

Expected: sqlpackage connects using the impersonated user, because it uses the identity from GetCurrent() Actual: sqlpackage connects as the original user running PowerShell:

# $identityName = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
# Write-Host "SqlPackage as: $identityName"
# dotnet tool run sqlpackage
SqlPackage as: DOMAIN\SQLUSER
# ...
Microsoft.Data.SqlClient.SqlException (0x80131904): Login failed for user 'DOMAIN\PIPELINEUSER'.

Did this occur in prior versions? If not - which version(s) did it work in? I don't believe this is a regression

(SqlPackage)

kkloss-od commented 1 year ago

My only hypothesis for this behavior is that calling Impersonate on the identity object is entering impersonation within .NET Framework (or another AppDomain or something), because it's being done from PowerShell, but sqlpackage is retrieving its identity from .NET Core (or another AppDomain or something).

dzsquared commented 1 year ago

Applying your hypothesis, if you run the .NET Framework SqlPackage (from the DacFx msi), does it leverage the identity impersonation you're applying from powershell?

One example of installing the msi during a pipeline run: https://learn.microsoft.com/sql/tools/sqlpackage/sqlpackage-pipelines?view=sql-server-ver16#azure-pipelines-2

wget -O DacFramework.msi "https://aka.ms/dacfx-msi"
msiexec.exe /i "DacFramework.msi" /qn

sqlpackage is installed to: C:\Program Files\Microsoft SQL Server\160\DAC\bin\

kkloss-od commented 1 year ago

We try not to install versioned tools like SqlPackage directly on the deploy agents, but I did check the opposite case and reproduced the same behavior running it within WindowsIdentity.RunImpersonated in PowerShell Core 7.