Azure SQL这种PaaS数据库已经越来越被大型企业所接受,对于连接PaaS数据库的方式也和传统的用户名pwd相比有非常大的变化,对于PaaS数据库来说,一方面可以使用传统的数据库userid和pwd登陆,在connection string中注明ID和pwd,也可以使用一些其他形式的身份验证方式,比如service principal和managed identity,这两种方式也越来越被用户所接受
这次要介绍的就是managed identity和Azure SQL数据库的结合,demo的环境主要使用基于.NET Core的app service,以及一个小型的Azure SQL数据库
managed identity的介绍不多说了,简单理解就是个微软托管的用户账户,直接通过后台API自动获取/refresh token,无需用户自己维护pwd,所以通过managed identity访问Azure资源的时候是不需要用户输入pwd的,这样其实也可以一定程度避免身份泄露
不过对于Azure SQL来说,使用managed identity连接到数据库对于代码来说并不是透明的,需要自己引入一些包,并且编写一些code,但是对于开发来说,其实也都是分分钟的事
下边来大概演示下
首先可以自己创建个ASP.NET Core的application,或者github上找个简单的sample也行,在项目中添加下相关包的引入
Install-Package Microsoft.Data.SqlClient -Version 3.0.1
Install-Package Azure.Identity -Version 1.4.0
在application.json里加上一个connection string
"ConnectionStrings": {
"MyDbConnection": "Server=tcp:mxydemo.database.windows.net;Authentication=Active Directory Device Code Flow; Database=demo;"
}
接下来需要定义一个类,用于处理token等操作,然后在入口的代码里进行初始化,拿到相关的token
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Azure.Core;
using Azure.Identity;
using Microsoft.Data.SqlClient;
namespace DotNetCoreSqlDb.Data
{
public class CustomAzureSQLAuthProvider : SqlAuthenticationProvider
{
private static readonly string[] _azureSqlScopes = new[]
{
"https://database.windows.net//.default"
};
private static readonly TokenCredential _credential = new DefaultAzureCredential();
public override async Task<SqlAuthenticationToken> AcquireTokenAsync(SqlAuthenticationParameters parameters)
{
var tokenRequestContext = new TokenRequestContext(_azureSqlScopes);
var tokenResult = await _credential.GetTokenAsync(tokenRequestContext, default);
return new SqlAuthenticationToken(tokenResult.Token, tokenResult.ExpiresOn);
}
public override bool IsSupported(SqlAuthenticationMethod authenticationMethod) => authenticationMethod.Equals(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow);
}
}
代码相关的内容其实就这么多,本身是很固定的内容,和业务代码完全无关
之后要准备为app service开启managed identity,并且在数据库中针对这个identity进行授权,这里直接通过CLI开启identity
az webapp identity assign --resource-group myResourceGroup --name <app-name>
接下来,使用Azure AD账号连接到SQL Server,在db level创建user,然后授权,这一步是必须要做的,否则managed identity无法通过AAD拿到操作数据库的权限,另外注意这步必须通过AAD账号登陆才可以,sql账号登陆是没办法成功执行下边的命令的,identity-name一般就是app service的名字
CREATE USER [<identity-name>] FROM EXTERNAL PROVIDER;
ALTER ROLE db_datareader ADD MEMBER [<identity-name>];
ALTER ROLE db_datawriter ADD MEMBER [<identity-name>];
ALTER ROLE db_ddladmin ADD MEMBER [<identity-name>];
GO
,
之后可以通过git或者FTP等方式将代码发布到app service,如果遇到报错,可以看下project file,将需要的引用加入进去
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.Core" Version="1.22.0" />
<PackageReference Include="Azure.Identity" Version="1.4.0" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="3.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.10">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="5.0.10" />
</ItemGroup>
</Project>
如果遇到Invalid value for key 'authentication',可能是Microsoft.Data.SqlClient版本过低,升级到3.0.x以上再试试
问题解决之后一般就可以正常访问应用了,在数据库中其实可以很明显看到当前连接是使用的什么provider
可以看到基本不需要配置azure sql的pwd,即使代码公布出去,也不需要担心权限泄露