首页 > 解决方案 > 用于在 Azure Active Directory 中创建安全组以管理对 Azure SQL 的访问的 Powershell 脚本

问题描述

下面是在 Azure AD 中创建组然后将 SQL 角色分配给组的脚本。该脚本依赖于 ODBC 17 和 sqlcmd 实用程序版本 15,这使得在 Azure devops 管道中使用它有点困难。我想知道是否有人知道我可以使用的任何替代 powershell cmdlet 在脚本中针对 SQL 运行查询。我尝试了 invoke-sqlcmd 但在尝试使用 onmicrosoft 帐户进行身份验证时遇到了问题。当使用您使用 SQL 数据库创建的 sql admin 用户时,我可以运行命令来设置目标数据库的权限,但无法运行在主数据库中创建组(来自外部提供者)的 sql 查询。所以我有点卡住了。想法是将脚本添加到部署管道并让它自动创建 AAD 组,这将允许运营团队管理用户对数据库的访问。请帮助 :-) <# .SYNOPSIS 创建用于控制对 SQL Server 和数据库资源的访问的 AAD 组

            .DESCRIPTION
                Based on the SQL Server and Database supplied as a input the script will create the required AAD groups required for every Azure SQL Server


            .INPUTS
                sqlServerName: Name of the sql server (IAAS) or the sql server instance (PAAS)
                sqlDatabaseName: Name of the database
                custom_vars_envResourceGroupName : Resource group the sql server resides in
                sqlAdminUser: 
                sqlAdminPassword
                ProjectId
                EnvironmentId
            .OUTPUTS
                Names of the AAD groups that was created

            .NOTES
                Script assumes that it is running in a session that is already connected to Azure RM TODO: Test least privilage
                Script assumes that it is running in a session that is already connected to Azure RM with contributor RBAC rights on the resource group TODO: Test least privilage
                If you are running this manually you need to add the sqlAdmin user into the Server admim group**** TODO: Still need to get the this automated to used the Azure DevOps Service Principle.
                Dont try this with a microsoft account it needs a AAD account to work on the db authenication
                If the qlAdminPassword is passed using clear text dont user "$" or "&" or "/" as special characters in the password.
            .EXAMPLE
            $sqlAdminPasswordnotsecure = "lhfuhwe48234#E"
            $sqlAdminSecurePassword = ConvertTo-SecureString $sqlAdminPasswordnotsecure -AsPlainText -Force
            #.\sqlAADGroupsCreator.ps1 `
                -custom_vars_envResourceGroupName "<Resource Group>" 
                -sqlServerName "<Servername>" 
                -sqlAdminUser "<eg sqlAdminUser@companydirectory.onmicrosoft.com>" 
                -sqlAdminSecurePassword "<complex password>" 
                -sqlDatabaseName "<database name>"
                -ProjectId "<Name of project>" 
                -EnvironmentId "<environment>"
            #>

            #region parameters
            Param(
                [Parameter(Mandatory = $True)][string]$custom_vars_envResourceGroupName,
                [Parameter(Mandatory = $True)][string]$sqlServerName,
                [Parameter(Mandatory = $True)][string]$sqlAdminUser,
                [Parameter(Mandatory = $True)][securestring]$sqlAdminSecurePassword,
                [Parameter(Mandatory = $True)][string]$sqlDatabaseName,
                [Parameter(Mandatory = $True)][string]$ProjectId,
                [Parameter(Mandatory = $True)][string]$EnvironmentId
            )
            $ErrorActionPreference = "Stop"
            #endregion parameters
            #region secureStringConversion
            #Convert secure string back to plain text to be used in SQL connection 
            function Get-PlainText() {
                [CmdletBinding()]
                param
                (
                    [parameter(Mandatory = $true)]
                    [System.Security.SecureString]$SecureString
                )
                BEGIN { }
                PROCESS {
                    $bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecureString);

                    try {
                        return [Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr);
                    }
                    finally {
                        [Runtime.InteropServices.Marshal]::FreeBSTR($bstr);
                    }
                }
                END { }
            }

            #Call The function
            $sqlAdminPassword = get-plaintext -SecureString $sqlAdminSecurePassword 
            #endregion secureStringConversion
            #region manualParameter
            <#Variables that can be used during testing or running manual
            $custom_vars_envResourceGroupName   = "MATA-APP-0-0-COMMON"
            $sqlServerName = "<server name>"
            $sqlAdminUser = "<SqlAdmin@educationtestgovtnz.onmicrosoft.com>"
            $sqlAdminPassword = "<complex password>"
            $sqlDatabaseName = "<database name>"
            $EnvironmentId = "<environment variable"
            $ProjectId ="<application name or abreviation>"
            #>
            #endregion manualParameter
            #region aadGroupsCreation. 
            #Build up database server Url 
            $sqlServerURL = $sqlServerName + ".database.windows.net"
            ###Create AAD Groups based on resource group name
            $sqlAdminGroupName = $sqlReadGroupName = $sqlDbContributorGroupName = $sqlDbReadGroupName = ""
            $sqlAdminGroupName = "AL SQL " + ($ProjectId.ToUpper()) + " " + ($EnvironmentId.ToUpper()) + " Admin"
            $sqlReadGroupName = "AL SQL " + ($ProjectId.ToUpper()) + " " + ($EnvironmentId.ToUpper()) + " Read" 
            $sqlDbContributorGroupName = "AL DB " + ($sqlServerName.ToUpper()) + " " + ($sqlDatabaseName.ToUpper()) + " Contributor" 
            $sqlDbReadGroupName = "AL DB " + ($sqlServerName.ToUpper()) + " " + ($sqlDatabaseName.ToUpper()) + " Read" 


            ###Create the Groups in Azure AD if they dont exist then assign access roles to Resource Group
            #SQL LEVEL ADMIN And DB OWNER#
            #Create new group for Owner
            if ($sqlAdminGroupName -ne ((Get-AzureRmADGroup -SearchString $sqlAdminGroupName).displayname)) {
                #$slqAdminGroupDiscription = "Server Admin and database owner access to "+ $sqlServerName
                New-AzureRmADGroup `
                    -DisplayName $sqlAdminGroupName `
                    -MailNickName "NotSet"
            }

            #Update group membership of sqlAdmin group
            $groupUser = Get-AzureRmADGroupMember -GroupDisplayName $sqlAdminGroupName
            if ($sqlAdminUser -ne ($groupUser.UserPrincipalName)) {
                Add-AzureRmADGroupMember -MemberUserPrincipalName $sqlAdminUser -TargetGroupDisplayName $sqlAdminGroupName
            }
            #DB LEVEL CONTRIBUTOR###
            #Create new group for Contributor
            if ($sqlDbContributorGroupName -ne ((Get-AzureRmADGroup -SearchString $sqlDbContributorGroupName).displayname)) {
                #$sqlContributorGroupDiscription = "Contributor access to "+ $sqlDatabase
                New-AzureRmADGroup `
                    -DisplayName $sqlDbContributorGroupName `
                    -MailNickName "NotSet"
            }

            #SQL LEVEL READER###
            #Create new group for ReadOnly
            if ($sqlReadGroupName -ne ((Get-AzureRmADGroup -SearchString $sqlReadGroupName).displayname)) {
                #$RGReadOnlygroupDiscription = "Read Only access to "+ $sqlDatabase
                New-AzureRmADGroup `
                    -DisplayName $sqlReadGroupName `
                    -MailNickName "NotSet"
            }

            #DB LEVEL READER###
            #Create new group for ReadOnly
            if ($sqlDbReadGroupName -ne ((Get-AzureRmADGroup -SearchString $sqlDbReadGroupName).displayname)) {
                #$RGReadOnlygroupDiscription = "Read Only access to "+ $sqlDatabase
                New-AzureRmADGroup `
                    -DisplayName $sqlDbReadGroupName `
                    -MailNickName "NotSet"
            }
            #endregion aadGroupsCreation.
            #region setDbPermissions
            #Enable Azure AD Administrator on the SQL server (SQL / AAD Integration)
            $sqlAdminGroupNameId = (Get-AzureRmADGroup -DisplayName $sqlAdminGroupName).Id
            Set-AzureRmSqlServerActiveDirectoryAdministrator -ResourceGroupName  $custom_vars_envResourceGroupName  -ServerName $sqlServerName -DisplayName $sqlAdminGroupName -ObjectId $sqlAdminGroupNameID

            #SQL Query to create the AAD groups in SQL master and map the appropriate roles to the AAD Groups
            $createSQLUsersQuery = ""
            $createSQLUsersQuery = @" 
            CREATE USER [$sqlDbContributorGroupName] FROM EXTERNAL PROVIDER;
            CREATE USER [$sqlReadGroupName] FROM EXTERNAL PROVIDER;
            CREATE USER [$sqlDbReadGroupName] FROM EXTERNAL PROVIDER;
            "@
            #Connect to SQL sever and configure the SQL Sever level logins
            Sqlcmd -S $sqlServerURL -d master -U $sqlAdminUser -P $sqlAdminPassword -G -Q $createSQLUsersQuery

            #SQL Query to create the AAD groups in targeted sqldatabase
            $createSQLDBUsersQuery = ""
            $createSQLDBUsersQuery = @"
            CREATE USER [$sqlAdminGroupName] FROM EXTERNAL PROVIDER;
            CREATE USER [$sqlDbContributorGroupName] FROM EXTERNAL PROVIDER;
            CREATE USER [$sqlReadGroupName] FROM EXTERNAL PROVIDER;
            CREATE USER [$sqlDbReadGroupName] FROM EXTERNAL PROVIDER;
            "@
            #Connect to SQL sever and configure the SQL database level logins
            Sqlcmd -S $sqlServerURL -d $sqlDatabaseName -U $sqlAdminUser -P $sqlAdminPassword -G -Q $createSQLDBUsersQuery

            #SQL Query to set the database level permissions in targeted sqldatabase
            $setSQLDBPermissionsQuery = ""
            $setSQLDBPermissionsQuery = @"
            ALTER ROLE db_owner ADD MEMBER [$sqlAdminGroupName]
            ALTER ROLE db_datareader ADD MEMBER [$sqlReadGroupName]
            ALTER ROLE db_datawriter ADD MEMBER [$sqlDbContributorGroupName]
            ALTER ROLE db_datareader ADD MEMBER [$sqlDbContributorGroupName]
            ALTER ROLE db_datareader ADD MEMBER [$sqlDbReadGroupName]
            "@
            #Connect to SQL sever and configure the SQL database level permissions
            Sqlcmd -S $sqlServerURL -d $sqlDatabaseName -U $sqlAdminUser -P $sqlAdminPassword -G -Q $setSQLDBPermissionsQuery
            #endregion setDbPermissions

标签: powershellazure-sql-databasesqlcmdazure-sql-serverinvoke-sqlcmd

解决方案


我认为您的问题是您试图以 SQL 管理员而不是为您的 Azure SQL 数据库实例配置的 AD 管理员身份运行以下 T-SQL。

若要创建基于 Azure AD 的包含数据库用户(拥有数据库的服务器管理员除外),请以至少具有 ALTER ANY USER 权限的用户身份连接到具有 Azure AD 身份的数据库。然后使用以下 Transact-SQL 语法:

CREATE USER <Azure_AD_principal_name> FROM EXTERNAL PROVIDER;

请参阅文档,因为它是为 Azure SQL 数据库(单实例/弹性池)、托管实例和数据仓库配置 Azure AD 的主要文档。

至于 PowerShell cmdlet,请注意AzureRM.sql(支持到 2020 年)已被弃用,而Az.sql是新模块。有关 Azure CLI(链接)的更多信息。

对于自动化场景,您需要从用户名和安全字符串创建凭据:

$passwd = ConvertTo-SecureString use a secure password here-AsPlainText -Force $pscredential = New-Object System.Management.Automation.PSCredential('服务主体名称/id', $passwd) Connect-AzAccount -ServicePrincipal -Credential $pscredential -TenantId $tenantId

$params = @{ 'Query' = 'CREATE USER FROM EXTERNAL PROVIDER' 'ConnectionString' = 'Data Source=MYSERVER;Initial Catalog=MyDatabase;Integrated Security=True' }

调用-Sqlcmd @params


推荐阅读