前言

以前就写过很多篇了

ASP.NET Core – Configuration & Options

Asp.net core 学习笔记 ( Azure key-vault )

Asp.net core 学习笔记 Secret 和 Data Protect Azure key-vault & Storage Account 第 2 篇

Azure 入门系列 (第四篇 Key Vault)

这篇作为最新最完整的版本呗.

参考

Docs – Safe storage of app secrets in development in ASP.NET Core

Docs –  Azure Key Vault configuration provider in ASP.NET Core

What & Why User Secrets?

一个项目里, 许多地方都会用到密码. 比如链接 SQL Server, SMTP, 还有各种 third party app client id & secret.

密码属于敏感信息, 只能个人或公司团队知道, 不可以外泄到其它地方.

早年, 大家都在本机上做开发, 公司团队则有自己的域网和服务器. 所以密码外泄是很难发生的.

可如今, 已经很少公司自己搞 version control 这些了. 大家都用 Github / Azure DevOps 等平台的 cloud service.

于是, 大家就开始关注如何确保密码不外泄了.

User Secrets 就是用来解决这些问题的. User Secrets 会确保密码只会保存在本机上, 不会被发布到 Github / Azure DevOps 上去.

只有每个开发人员的机子上才保存了密码. 这样就确保了密码不外泄.

而它在做到这些事情的同时并不会增加开发者的负担. 这点, ASP.NET Core 还是封装的很不错的.

User Secrets Get Started (WebApp)

创建项目

dotnet new webapp -o UserSecretsWebApp

添加账户密码到 appsettings.json

{
"Account": {
"Username": "Derrick",
"Password": "secret"
}
}

在 program.cs 读取  Account.Password

var builder = WebApplication.CreateBuilder(args);
var password = builder.Configuration.GetValue<string>("Account:Password");
Console.WriteLine(password); // secret

目前拿到的密码就是 appsettings.json 定义的 "secret", 现在我们加入 User Secrets

dotnet user-secrets init
dotnet user-secrets set "Account:Password" "my real password"

第一句是初始化, 第二句是添加 key value.

注意, key path 的分隔符是分号 : 而不是点 . 哦.

再次运行

dotnet run

password 从原本的 "secret" 换成了 "my real password"

几个重点

1.ASP.NET Core 的 User Secrets 通常是搭配 appsettings.json 和 Configuration 一起使用的.

2.常见的操作有: 初始化, 添加/更新, 列出, 删除

dotnet user-secrets init
dotnet user-secrets set "Account:Password" "my real password"
dotnet user-secrets list
dotnet user-secrets remove "Account:Password"

3. 所有 secret 会被保存到一个 json file, Windows 下的路径是

%APPDATA%\Microsoft\UserSecrets\<user_secrets_id>\secrets.json

4. 通过 Visual Studio 可以直接打开 json file 修改

User Secrets Get Started (Console)

var builder = WebApplication.CreateBuilder(args);

CreateBuilder 封装了太多细节. 我们来一个比较底层的接口, 看看它是如果工作的.

创建 Console 和 add package

dotnet new console -o UserSecretsConsole
dotnet add package Microsoft.Extensions.Configuration
dotnet add package Microsoft.Extensions.Configuration.FileExtensions
dotnet add package Microsoft.Extensions.Configuration.Json
dotnet add package Microsoft.Extensions.Configuration.UserSecrets
dotnet add package Microsoft.Extensions.Configuration.Binder

program.cs

using System.Reflection;
using Microsoft.Extensions.Configuration; // 创建 config builder
// 链接 appsettings.json
var configurationBuilder = new ConfigurationManager()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.Development.json", optional: true, reloadOnChange: true); if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development")
{
// 链接 User Secrets
configurationBuilder = configurationBuilder.AddUserSecrets(Assembly.GetExecutingAssembly());
} // 这里相等于 WebApp 的 builder.Configuration 了
var configuration = configurationBuilder.Build();
var password = configuration.GetValue<string>("Account:Password"); // my real password
Console.WriteLine(password);

AddUserSecrets 就是它偷龙转风的地方了.

查看源码 dotnet/runtime 里的 UserSecretsConfigurationExtensions.cs

会发现它并没有什么神奇的地方, 它也是通过 .AddJsonFile 把 secrets.json 覆盖到 configuration 里而已.

User Secrets with Azure Key Vault (Azure-hosted)

What & Why?

上面讲的都是在开发阶段如何保护密码. 那到了 Production 阶段呢?密码和程序是否应该放在一块?

显然, 分开是比较好的, 至少不要让 hacker 一次过拿完所有东西嘛.

User Secrets 把密码存到了 json file, 那在 VM (Virtual Machine Web Server), 我们也可以把密码 (json file 概念) 放到另一台机子上 (不要和程序的 VM 同一台)

这就是 Azure Key Vault 的工作了. Azure Key Vault 是微软的 Cloud Service. 就是提供一个密码保险箱. 它可以管理 Secret, Key, Certificate 等等. 这里我们主要关注 Secret 就好.

Create Azure Key Vault

首先我们需要有 Microsoft Azure 账号, 然后安装 Azure CLI (MSI)

安装好后开启 Windows PowerShell, 输入

az login

它会开启游览器然后登入 Azure 账号。

有时候可能会需要指定 TENANT_ID,像这样

az login --tenant 12312312-1233-1233-1233-123123123123

TENANT_ID 可以去 Azure Portal search "Azure Active Directory" 就会看见了,或者问 ChatGPT。

接着创建 resource group

az group create --name "TestKeyVault-RG" --location "SoutheastAsia"

如果已经有其它 Resource Group 也可以用 existing 的.

接着创建 Key Vault

az keyvault create --name "First-KV" --resource-group "TestKeyVault-RG" --location "Southeast Asia"

然后给予 user 权限

先找出 user Object ID

az ad user list --output table

这句会 list out 全部的 users。UserPrincipalName 是 user 的 email address,抄下来。

然后

az ad user show --id "user email address"

这句会显示 user 的 information,其中的 id 就是我们需要的 Object ID,抄下来。

然后

az keyvault show --name "First-KV"

把 id 抄下来

接着添加权限

az role assignment create --assignee "Object ID" --role "Key Vault Administrator" --scope "key-vault-id"

这样就有添加 secret 的权限了。

然后添加 secret

az keyvault secret set --vault-name "First-KV" --name "Account-Password" --value "my read password"

注: name 是 Account-Password 分隔符是 hyphen -, 因为 Azure 不支持分号 : 所以...什么鬼嘛...超麻烦的...

另外,我们的项目要访问 secret 也需要权限,用回上面的方法。(注:如果你的程序不是 host 在 Azure VM 那要用另外一招, 下面会教)

获取 VM 的 Object ID

az vm show --ids /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/virtualMachines/{vmName} --query 'identity.principalId'

里面 3 个 parameters 分别是 subscriptionId, resourceGroupName, vmName

获取 subscriptionId 的方式是

az account show --query 'id' -o tsv

如果拿不到就省略掉 --query,直接

az account show

里面的 id 就是 subscriptionId,然后

az role assignment create --assignee "Object ID" --role "Key Vault Administrator" --scope "key-vault-id"

好了,搞定!

想知道更多 Azure CLI command 可以参考 Docs – az keyvault 或者问 ChatGPT 会更快.

Connect with Azure Key Vault

add package

dotnet add package Azure.Identity
dotnet add package Azure.Extensions.AspNetCore.Configuration.Secrets

program.cs

var builder = WebApplication.CreateBuilder(args);
if (builder.Environment.IsProduction())
{
builder.Configuration.AddAzureKeyVault(
new Uri("https://first-kv.vault.azure.net/"),
new DefaultAzureCredential(),
new HyphenKeyVaultSecretManager()
);
var password = builder.Configuration.GetValue<string>("Account:Password"); // my read password
}

通过 AddAzureKeyVault 让 Azure Key Vault 关联进来.

获取 URI 的方式是 (其实也可以按照命名规范自己推断出来)

az keyvault show --name "First-KV" --query "properties.vaultUri"

class HyphenKeyVaultSecretManager 的作用是把 Azure Key Vault 的 hyphen - 换成分号 : (上面有提到...超麻烦的...)

public class HyphenKeyVaultSecretManager : KeyVaultSecretManager
{
public override string GetKey(KeyVaultSecret secret)
{
return secret.Name.Replace("-", ConfigurationPath.KeyDelimiter);
}
}

至此, 只要我们的程序是 host 在 Azure VM (和 Key Vault 相同 resource group) 那么它们就可以链接到了.

注: 或许你会发现本地测试也可以跑起来, 那是因为 Azure CLI login 了, 同时我们用相同 account create 了 Key Vault.

一旦 az logout 本地就无法访问了.

User Secrets with Azure Key Vault (non-Azure-hosted)

如果我们的程序不是运行在 Azure VM / App 的话, 过程会繁琐一些.

参考: Docs – Use Application ID and X.509 certificate for non-Azure-hosted apps

创建 Azure App Registration (AKA Client App)

首先我们需要搞一个 Client App, 它们的关系是 : 我们的程序 connect to Client App 然后由  Client App 去访问 Azure Key Vault.

az ad app create --display-name AzureKeyVault-AR

Add access policy for Client App

像上面我们授权给 VM 那样, Azure Key Vault 也需要授权给 Client App

az keyvault set-policy --name "First-KV" --secret-permissions get list --object-id "9e60491d-5161-43e2-b409-a580124944b8"

注意, 这里的 object-id 其实是放 application id 的值.

通过 az ad app 可以查看 Client App 的 application id 和 object id

az ad app list --display-name "AzureKeyVault-AR" --query "[].{id:id, appId:appId}" --output tsv

id 是 object id, appId 是 application id (AKA client id), 而 set-policy 的参数虽然叫 object-id 但正确的输入是放 application id 值哦, 它乱来, 我们可不要被误导哦.

Add certificate to Client App

早年 Azure 只是提供一个 Client Secret (AKA password), 但后来因为不够安全所以改成用 certificate 做非对称加密和签名.

具体怎样创建 certificate 可以看之前我写的 ASP.NET Core – Work with X509

创建 .pfx 和 .cer

using var algorithm = RSA.Create(keySizeInBits: 2048);
var subject = new X500DistinguishedName($"CN=AzureKeyVault"); // 名字顺便, 因为是 self-signed
var request = new CertificateRequest(subject, algorithm, HashAlgorithmName.SHA256, RSASignaturePadding.Pss);
var certificate = request.CreateSelfSigned(
notBefore: DateTimeOffset.UtcNow,
notAfter: DateTimeOffset.UtcNow.AddYears(2)
);
var pfxBytes = certificate.Export(X509ContentType.Pfx, "my password");
var certBytes = certificate.Export(X509ContentType.Cert);
File.WriteAllBytes(Directory.GetCurrentDirectory() + "\\AzureKeyVault.pfx", pfxBytes);
File.WriteAllBytes(Directory.GetCurrentDirectory() + "\\AzureKeyVault.cer", certBytes);

.pfx 是给程序用的 .cer 是给 Azure Client App 用的.

upload .cer to Client App

az ad app credential upload --id "9e60491d-5161-43e2-b409-a580124944b8" --cert "@C:\keatkeat\my-projects\asp.net core\7.0\Secret\UserSecretsWebApp\AzureKeyVault.cer"

参数 --id 同样是指 application id 而不是 object id 哦.

Connect to Client App and Key Vault

var builder = WebApplication.CreateBuilder(args);

// read certificate from file
var rowData = File.ReadAllBytes(Directory.GetCurrentDirectory() + "\\AzureKeyVault.pfx");
var certificate = new X509Certificate2(rowData, "my password"); // connect to Client App and Key Vault
builder.Configuration.AddAzureKeyVault(
new Uri("https://stgtestkeyvault-kv.vault.azure.net/"),
new ClientCertificateCredential(
tenantId: "30609328-e0b1-8cb0-974d-117ee17e02b5",
clientId: "9e60491d-5161-43e2-b409-a580124944b8",
certificate
),
new HyphenKeyVaultSecretManager()
);
var password = builder.Configuration.GetValue<string>("Account:Password"); // my read password
Console.WriteLine(password); // my read password

1. 其实 certificate 应该要放在 store 里面的, 但因为 IIS read store 经常有权限问题, 这里只是为了演示而已, 所以我直接 read from file 就好了.

2. 获取 tenantId

az account show --query tenantId -o tsv

ASP.NET Core – User Secrets & Azure Key Vault的更多相关文章

  1. 【Azure 环境】Azure Key Vault (密钥保管库)中所保管的Keys, Secrets,Certificates是否可以实现数据粒度的权限控制呢?

    问题描述 Key Vault (密钥保管库) 能不能针对用户授权实现指定用户只能访问某个或某些特定的key? 如当前有两个用户(User1, User2),在Key Vault中有10个Key,Use ...

  2. 如何在ASP.NET Core中使用Azure Service Bus Queue

    原文:USING AZURE SERVICE BUS QUEUES WITH ASP.NET CORE SERVICES 作者:damienbod 译文:如何在ASP.NET Core中使用Azure ...

  3. 【Azure Developer】Python代码通过AAD认证访问微软Azure密钥保管库(Azure Key Vault)中机密信息(Secret)

    关键字说明 什么是 Azure Active Directory?Azure Active Directory(Azure AD, AAD) 是 Microsoft 的基于云的标识和访问管理服务,可帮 ...

  4. Azure Key Vault(二)- 入门简介

    一,引言 在介绍 Azure Key Vault 之前,先简单介绍一下 HSM(硬件安全模块). -------------------- 我是分割线 -------------------- 1,什 ...

  5. Azure Key Vault (3) 在Azure Windows VM里使用Key Vaule

    <Windows Azure Platform 系列文章目录> 本章我们介绍如何在Azure Windows VM里面,使用.NET使用Azure Key Vault 我们需要对Key V ...

  6. Azure Key Vault (2) 使用Azure Portal创建和查看Azure Key Vault

    <Windows Azure Platform 系列文章目录> 请注意: 文本仅简单介绍如何在Azure Portal创建和创建Key Vault,如果需要结合Application做二次 ...

  7. 【Azure Developer】解决Azure Key Vault管理Storage的示例代码在中国区Azure遇见的各种认证/授权问题 - C# Example Code

    问题描述 使用Azure密钥保管库(Key Vault)来托管存储账号(Storage Account)密钥的示例中,从Github中下载的示例代码在中国区Azure运行时候会遇见各种认证和授权问题, ...

  8. 【Azure Developer - 密钥保管库 】使用 Python Azure SDK 实现从 Azure Key Vault Certificate 中下载证书(PEM文件)

    问题描述 在Azure Key Vault中,我们可以从Azure门户中下载证书PEM文件到本地. 可以通过OpenSSL把PFX文件转换到PEM文件.然后用TXT方式查看内容,操作步骤如下图: Op ...

  9. 【Azure Developer】记录一次使用Java Azure Key Vault Secret示例代码生成的Jar包,单独运行出现 no main manifest attribute, in target/demo-1.0-SNAPSHOT.jar 错误消息

    问题描述 创建一个Java Console程序,用于使用Azure Key Vault Secret.在VS Code中能正常Debug,但是通过mvn clean package打包为jar文件后, ...

  10. 如何在ASP.NET Core中自定义Azure Storage File Provider

    文章标题:如何在ASP.NET Core中自定义Azure Storage File Provider 作者:Lamond Lu 地址:https://www.cnblogs.com/lwqlun/p ...

随机推荐

  1. Solo 开发者周刊 (第 1 期):开源产品的探索之路

    产品推荐 如何着手将一个简单的想法转变为一个成熟的开源项目,以及如何在此过程中利用和贡献于开源社区.同时使其达到商业化的同时,保持原有的开源精神.这些是我们需要探索的. Spug 开源运维平台 Spu ...

  2. vb.net 实现excel导入的时候滚动显示导入的数据

    如果你想在 Excel 导入过程中滚动显示导入的数据,可以使用逐行读取 Excel 数据并在滚动窗口中显示. 在 VB.NET 中,你可以使用 Excel.Range 对象逐行读取 Excel 数据, ...

  3. oeasy教您玩转vim - 60- # vim选项

    ​ vim选项 从头开始 这次我们从头开始 从进入vim之前开始 我们可以在终端里面给vim怎么样的参数呢? man vim 这个如果不行的话 要先运行unminimize更新manual 也可以在v ...

  4. 题解:AT_abc359_e [ABC359E] Water Tank

    背景 中考结束了,但是暑假只有一天,这就是我现在能在机房里面写题解的原因-- 分析 这道题就是个单调栈. 题目上问你第一滴水流到每个位置的时间.我们考虑,答案其实就是比当前木板高且距离当前木板最近的那 ...

  5. 前端太卷了,不玩了,写写node.js全栈涨工资,赶紧学起来吧!!!!!

    首先聊下node.js的优缺点和应用场景 Node.js的优点和应用场景 Node.js作为后端开发的选择具有许多优点,以下是其中一些: 高性能: Node.js采用了事件驱动.非阻塞I/O模型,使得 ...

  6. UE5 打不开

    在游戏开发中,出现了UE打不开的情况 初步推测,新增了接口Attacker, 而我们的DefaultPawn可能一下子实现了两个接口造成的 而这两个接口都在一个插件里,一个是c++实现的,一个是蓝图实 ...

  7. Python版WGCNA分析和蛋白质相互作用PPI分析教程

    在前面的教程中,我们介绍了使用omicverse完成基本的RNA-seq的分析流程,在本节教程中,我们将介绍如何使用omicverse完成加权基因共表达网络分析WGCNA以及蛋白质相互作用PPI分析. ...

  8. 七天.NET 8操作SQLite入门到实战 - 第七天Blazor学生管理页面编写和接口对接(3)

    前言 本章节我们的主要内容是完善Blazor学生管理页面的编写和接口对接. 七天.NET 8 操作 SQLite 入门到实战详细教程 第一天 SQLite 简介 第二天 在 Windows 上配置 S ...

  9. Windows下搭建Vue脚手架CLI

    Vue CLI的使用依赖Node.js,先按照Node.js环境. //安装环境C:\Users\16779>npm install --global vue-cli npm WARN depr ...

  10. 对比python学julia(第一章)--(第一节)万事开头也不难

    自1989年被创立以后,历经30多年的发展,Python已经如日中天,在运维.大数据.云计算.web.科学计算上混的风生水起,并且于2020.2021年蝉联TIOBE年度编程语言首座.以至于,如今不会 ...