前言

以前就写过很多篇了

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. [oeasy]python0118_语言的发展_希腊字符_拼音文字_亚历山大大帝

    希腊字符回忆上次内容 尼罗河流域 的 埃及圣书体 是象形文字 两河流域 的 苏美尔楔形文字 不是象形文字 做生意的 腓尼基人 利用 埃及圣书体 的 字型 苏美尔楔形文字 的 写法 构造出 腓尼基字符 ...

  2. 在Python中使用SWCNN去除水印

    在Python中使用SWCNN去除水印 说明 首次发表日期:2024-07-17 SWCNN Github官方仓库: https://github.com/hellloxiaotian/SWCNN S ...

  3. [rCore学习笔记 014]批处理系统

    写在前面 本随笔是非常菜的菜鸡写的.如有问题请及时提出. 可以联系:1160712160@qq.com GitHhub:https://github.com/WindDevil (目前啥也没有 本章目 ...

  4. Python和RPA网页自动化-发送邮件

    以163邮箱为例,分别使用Python和RPA网页自动化发送邮件到指定邮箱 其中2个方法都需要用到163邮箱授权码,开启IMAP/SMTP服务即可得到授权码(POP3/SMTP服务不用开启) 1.py ...

  5. Vue Hook 封装通用型表格

    一.创建通用型表格的需求 实现一个通用型表格组件,具备以下功能: 动态列配置. 分页功能. 排序功能. 可扩展的行操作功能. 二.设计通用型表格组件 首先,需要设计一个基础的表格组件,它接受列配置.数 ...

  6. 【Kotlin】官网学习笔记

    0.IDEA环境设置: 1.基础语法 BasicSyntax 地址:https://kotlinlang.org/docs/basic-syntax.html 一.方法与变量 可以直接编写main方法 ...

  7. 【Java】 Void 类型

    void 也算一个类型,而且是基本数据类型 和其它数据类型一样提供了对应的包装类Void 每个包装类都提供一个TYPE字节实例,返回对应的原型类实例 public static void main(S ...

  8. 【Linux】Re02

    一.运行启动级别 0 关机 1 单用户 2 多用户状态没有网络服务 3 多用户状态存在网络服务 4 系统未使用保留给用户 5 图形界面 6 重启 命令: init [0 - 6] 图形化界面级别需要对 ...

  9. 【设计模式 Design Pattern】【UML】建模语言

    什么是UML图? UML-Unified Modeling Language 统一建模语言,又称标准建模语言. 是用来对软件密集系统进行可视化建模的一种语言. UML的定义包括UML语义和UML表示法 ...

  10. Odd and Even Zeroes 题解

    前言 题目链接:洛谷:UVA. 题目简述 定义 \(\operatorname{count}(num)\) 表示 \(num\) 末尾 \(0\) 的个数.给出 \(n\)(\(n \leq 10^{ ...