Dapr for dotnet | 密钥管理 - Secret Management
密钥管理(Secret Management)简介
应用程序通常会通过使用专用的密钥存储来秘密存储敏感信息,常见示例包括:
- 包含用户名和密码的数据库连接字符串。
- 用于调用外部 Web API 的 API 密钥。
- 用于对外部系统进行身份验证的客户端证书/令牌。
温馨提示:必须谨慎管理机密,以免在应用程序之外泄露。
传统的做法是 将应用程序机密存储在应用程序代码库内的配置文件中, .NET 开发人员一想到 web.config 文件就会很亲切。 虽然实现起来很简单,但 将机密与代码集成在一起并不安全。 常见的错误是在推送到公共 GIT 存储库时包含该文件,导致机密泄露。
【十二要素(The Twelve Factors)应用】是一种被广泛认可的用于构建新式分布式应用程序的方法。 其中介绍了一系列原则和最佳做法。 第三个要素规定配置和机密要存储在代码库外部。
通常这需要建立一个 密钥存储,如 Azure Key Vault、Hashicorp Vault 和其他仓库等机密管理工具中隔离机密(并在那里存储应用程序级别的密钥)。 可通过这些工具将机密存储在外部、在不同环境中使用不同的凭据,并且通过应用程序代码引用它们。 不过,每款工具都不简单,而且需要学习(增加相应的学习成本)。
要访问这些密钥存储,应用程序需要导入相应的密钥存储 SDK,并使用它访问这些密钥。 这可能需要相当数量的模板代码,这些代码与应用的实际业务领域无关,因此在多云场景中,可能会使用不同厂商特定的密钥存储,这就成为一个更大的挑战。
Dapr 的密钥管理
Dapr 提供了简化机密管理的构建基块。让开发人员在任何地方更容易消耗应用程序密钥, Dapr 有一个专用的密钥构建块 API ,允许开发人员从一个密钥存储获得密钥。
密钥管理的优点
通过 Dapr 机密管理构建基块,可轻松地使用机密和机密管理工具。
- 它通过统一的接口隐藏基础管道。
- 它支持各种可插入的机密存储组件,这些组件在开发环境和生产环境中可能有所不同。
- 应用程序不需要直接依赖于机密存储库(应用程序和密钥存储分离)。
- 开发人员无需详细了解每个机密存储。
密钥管理的应用
使用 Dapr 的密钥存储构建块通常涉及以下内容:
- 设置一个特定的密钥存储解决方案的组件。
- 在应用程序代码中使用 Dapr 密钥 API 获取密钥。
- [可选] 在 Dapr 组件文件中引用密钥。
密钥管理的工作原理
应用程序通过两种方式使用机密管理构建基块:
- 直接从构建基块 API 检索查询机密。
- 从 Dapr 组件配置中间接引用机密。
应用程序代码可以调用密钥构建块 API,从 Dapr 支持的密钥存储中检索密钥,并可以在您的代码中使用。
例如,下图显示了一个应用程序从配置的云密钥存储中请求名为 “mysecret“ 的密钥存储 “vault”。
应用程序可以使用密钥 API 访问 Kubernetes 密钥存储的秘密。 在下面的示例中,应用程序会从 Kubernetes 密钥存储检索相同的密钥 “mysecret”。
组件配置路径:
- C:\Users<username>.dapr\components
更多密钥管理支持的组件,请查看:
- Secret stores =》https://docs.dapr.io/reference/components-reference/supported-secret-stores/
密钥管理 API
使用机密管理构建基块时,应用程序会与 Dapr Sidecar 进行交互。 Sidecar 会公开机密 API。 可使用 HTTP 或 gRPC 调用 API。
- 【调用 Endport 】
使用以下 URL 调用 HTTP API(GET 请求)
# 单个密钥获取
http://localhost:<daprPort>/v1.0/secrets/<secret-store-name>/<name># 批量密钥获取
http://localhost:<daprPort>/v1.0/secrets/<secret-store-name>/bulk
URL 字段说明:
- < dapr-port > 指定 Dapr Sidecar 正在侦听的端口号。
- < store-name > 指定 Dapr 机密存储的名称。
- < name > 指定要检索的机密的名称。
- < metadata > [可选]提供机密的其他信息。
元数据属性因机密存储而异。 有关元数据属性的详细信息,请查看 [机密 API 参考](机密 API 参考 | Dapr Docs)。
- 【响应状态码】
Code / 状态码 | Description / 描述 |
---|---|
200 | OK,成功 |
204 | Secret not found,未找到机密 |
400 | Secret store is missing or misconfigured,机密存储丢失或配置错误 |
403 | Access denied,访问被拒绝 |
500 | Failed to get secret or no secret stores defined,未能获取机密存储或未定义机密存储 |
- 【构建块 Secret API 】
在 Dapr Sidecar 中的构建块 Secret API 接口信息(由于 daprd 是 go 语言编写的,因此下面提供 go 语言的接口信息):
type SecretStore interface {// Init authenticates with the actual secret store and performs other init operation// Init 使用实际的秘密存储进行身份验证并执行其他 init(初始化) 操作Init(metadata Metadata) error// GetSecret retrieves a secret using a key and returns a map of decrypted string/string values// GetSecret 使用密钥检索密钥并返回解密的字符串/字符串值的映射GetSecret(req GetSecretRequest) (GetSecretResponse, error)// BulkGetSecrets retrieves all secrets in the store and returns a map of decrypted string/string values// BulkGetSecrets 检索存储中的所有(批量)机密并返回解密的字符串/字符串值的映射BulkGetSecret(req BulkGetSecretRequest) (BulkGetSecretResponse, error)
}
在 .NET 中使用 Secret(机密)
此处使用 secretstores.local.file 类型来演示。
直接从构建基块 API 检索查询 Secret
添加 secrets01.json 文件
在 FrontEnd 项目中新增文件夹 Secrets ,并添加 secrets01.json 文件,在该文件中新增如下配置信息:
{"RabbitMQConnectStr": "amqp://mqtest:test123@192.168.30.71:5672","RedisConnectStr": "redis://:password@192.168.30.71:6379/0?timeout=200ms","PostgreSQLConnectStr": ""
}
新建 secrets01.yaml
在 C:\Users<username>.dapr\components 中添加 secrets01.yaml 配置文件信息
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:name: secrets01
spec:type: secretstores.local.fileversion: v1metadata:- name: secretsFile# secrets01.json 文件路径value: C:\Users\sws-dev-server\Desktop\dapr-demo\dapr-demo\FrontEnd\Secrets\secrets01.json- name: nestedSeparatorvalue: ":"
在 appsettings.json 文件中添加如下配置
{"Logging": {"LogLevel": {"Default": "Information","Microsoft.AspNetCore": "Warning"}},"AllowedHosts": "*","Dapr": {"Secrets": {"Development": {"FileName": "secrets01","Items": {"RabbitMQ": "RabbitMQConnectStr","Redis": "","PostgreSQL": "","SqlServer": ""}}}}
}
此处只举例 RabbitMQ 的连接,其他类似,可自行扩展;
新增 DaprSecretManagementController
在 FrontEnd 项目中新增 DaprSecretManagementController API ,通过 API 方式获取 Secret 在应用程序中使用,添加如下代码:
using Dapr.Client;
using Microsoft.AspNetCore.Mvc;
using System.Text.Json;namespace FrontEnd.Controllers;[Route("api/[controller]")]
[ApiController]
public class DaprSecretManagementController : ControllerBase
{private readonly ILogger<DaprSecretManagementController> _logger;private readonly DaprClient _daprClient;private readonly IConfiguration _configuration;public DaprSecretManagementController(ILogger<DaprSecretManagementController> logger, DaprClient daprClient, IConfiguration configuration){_logger = logger;_daprClient = daprClient;_configuration = configuration;}// 单个获取 Secret[HttpGet("GetSecret")]public async Task<ActionResult> GetSecretAsync(){_logger.LogInformation($"[{DateTime.Now}] ===> 进入 DaprSecretManagement.GetSecretsAsync");string storeName = _configuration["Dapr:Secrets:Development:FileName"];string key = _configuration["Dapr:Secrets:Development:Items:RabbitMQ"];Dictionary<string, string> secrets = await _daprClient.GetSecretAsync(storeName, key);string jsonSecrets = JsonSerializer.Serialize(secrets);_logger.LogInformation(jsonSecrets);return Ok(secrets[key]);}// 批量获取 Secret[HttpGet("GetBulkSecret")]public async Task<ActionResult> GetBulkSecretAsync(){_logger.LogInformation($"[{DateTime.Now}] ===> 进入 DaprSecretManagement.GetBulkSecretAsync");string storeName = _configuration["Dapr:Secrets:Development:FileName"];var secrets = await _daprClient.GetBulkSecretAsync(storeName);string jsonSecrets = JsonSerializer.Serialize(secrets);_logger.LogInformation(jsonSecrets);return Ok(secrets);}
}
dapr run 启动测试
执行如下命令,启动 frontend 服务:
dapr run --dapr-grpc-port 50020 --dapr-http-port 3501 --app-port 5001 --app-id frontend dotnet run
浏览器查看 Swagger 页面,操作 API 输出如下信息:
curl 调用单个获取 Secret 的 api
curl -X 'GET' \'http://localhost:5001/api/DaprSecretManagement/GetSecret' \-H 'accept: */*'
输出信息如下:
curl 调用批量获取 Secret 的 api
curl -X 'GET' \'http://localhost:5001/api/DaprSecretManagement/GetBulkSecret' \-H 'accept: */*'
输出信息如下:
从 Dapr 组件配置中间接引用 Secret
继续拿上一篇 Dapr for dotnet | 绑定 - Input/Output Bindings 中的输入/输出绑定举例,在前面的 yaml 配置中 rabbitmq 的连接字符串是包含铭感信息(amqp://mqtest:test123@192.168.30.71:5672),此处改造如下:
修改 Input/Output Bindings 的 yaml 配置文件
分别修改 rabbitmq-input-binding.yaml 和 rabbitmq-output-binding.yaml 文件中的的配置,修改信息如下:
- rabbitmq-input-binding.yaml
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:name: api/DaprBindings/Input
spec:type: bindings.rabbitmqversion: v1metadata:- name: queueNamevalue: queue-for-input-binding- name: hostsecretKeyRef:name: RabbitMQConnectStrkey: RabbitMQConnectStr
auth:secretStore: secrets01
- rabbitmq-output-binding.yaml
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:name: api/DaprBindings/Output
spec:type: bindings.rabbitmqversion: v1metadata:- name: queueNamevalue: queue-for-output-binding- name: hostsecretKeyRef:name: RabbitMQConnectStrkey: RabbitMQConnectStr
auth:secretStore: secrets01
- 在 host 的 value 修改添加 secretKeyRef ;
- 添加授权 auth.secretStore;
密钥(Secret)作用域 / 访问权限限制
一旦配置完毕,默认情况下任何该仓库内定义的密钥(Secret)都可以从 Dapr 应用程序访问。
要限制 Dapr 应用程序访问密钥(Secret)的话, 您可以通过向应用程序配置添加密钥作用域政策并限制权限来定义密钥作用域。
如何使用秘钥的作用域限定访问 =》https://docs.dapr.io/developing-applications/building-blocks/secrets/secrets-scopes/
- 修改 config.yaml 权限配置
secrets:scopes:- storeName: secrets01defaultAccess: deny
# 或者- storeName: secrets01defaultAccess: denyallowedSecrets: ["RabbitMQConnectStr"]
完整信息如下:
apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:name: daprConfig
spec:tracing:samplingRate: "1"zipkin:endpointAddress: http://localhost:9411/api/v2/spanssecrets:scopes:- storeName: secret01defaultAccess: deny # 拒绝访问,允许访问使用 allowdeniedSecrets: ["RabbitMQConnectStr"] # 添加引用的 key
dapr run 启动测试
执行如下命令,启动 frontend 服务:
dapr run --dapr-grpc-port 50020 --dapr-http-port 3501 --app-port 5001 --app-id frontend dotnet run
浏览器查看 Swagger 页面,操作 API 输出如下信息:
操作输入绑定 API 接口,在 RabbitMQ 管理页面查看对应的【queue-for-input-binding】队列信息,并没有看到消息写入,说明上面配置中的访问限制生效了。
想要恢复 RabbitMQ 绑定的可访问性,可以修改 defaultAccess: allow 然后(dapr run)重启 frontend 服务器即可。
注意:先检查 RabbitMQ 服务是否开启,可用浏览器查看管理页面。
参考文章推荐:
- Secrets management overview =》https://docs.dapr.io/developing-applications/building-blocks/secrets/secrets-overview/
- Secrets API reference =》https://docs.dapr.io/reference/api/secrets_api/
- How To: Use secret scoping =》https://docs.dapr.io/developing-applications/building-blocks/secrets/secrets-scopes/
- How To: Retrieve a secret =》https://docs.dapr.io/developing-applications/building-blocks/secrets/howto-secrets/
- Secret stores =》https://docs.dapr.io/reference/components-reference/supported-secret-stores/
- 面向 .NET 开发人员的 Dapr | Dapr 机密管理构建基块 =》https://docs.microsoft.com/zh-cn/dotnet/architecture/dapr-for-net-developers/secrets-management
Dapr for dotnet | 密钥管理 - Secret Management相关推荐
- 面向.NET开发人员的Dapr——机密
目录: 面向.NET开发人员的Dapr--前言 面向.NET开发人员的Dapr--分布式世界 面向.NET开发人员的Dapr--俯瞰Dapr 面向.NET开发人员的Dapr--入门 面向.NET开发人 ...
- 浅析 Dapr 里的云计算设计模式
Dapr 实际上是把分布式系统 与微服务架构实践的挑战以及k8s 这三个主题的全方位的设计组合,特别是Kubernetes设计模式 一书作者Bilgin Ibryam 提出的Multi-Runtime ...
- Dapr简单入门(一)
Dapr 是微软主导的云原生开源项目,2019年10月首次发布,到发布 V1.0 版本时候github star 数达到了 1.2 万,超过同期的 kubernetes.istio.knative 等 ...
- 面向.NET开发人员的Dapr——状态管理
目录: 面向.NET开发人员的Dapr--前言 面向.NET开发人员的Dapr--分布式世界 面向.NET开发人员的Dapr--俯瞰Dapr 面向.NET开发人员的Dapr--入门 面向.NET开发人 ...
- 面向.NET开发人员的Dapr——参考应用程序
目录: 面向.NET开发人员的Dapr--前言 面向.NET开发人员的Dapr--分布式世界 面向.NET开发人员的Dapr--俯瞰Dapr 面向.NET开发人员的Dapr--入门 Dapr refe ...
- 面向.NET开发人员的Dapr——前言
Foreword 前言 With the wave of cloud adoption well underway, there is a major shift happening towards ...
- Dapr 交通流量控制示例
Dapr 已在塔架就位 将发射新一代微服务 牛年 dotnet云原生技术趋势 Dapr是如何简化微服务的开发和部署 前面几篇文章都是从大的方面给大家分享Dapr 能帮助我们解决什么问题,微软从开源到1 ...
- 在非k8s 环境下 的应用 使用 Dapr Sidekick for .NET
在k8s 环境下,通过Operator 可以管理Dapr sidecar, 在虚拟机环境下,我们也是非常需要这样的一个管理组件,之前写的一篇文章< 在 k8s 以外的分布式环境中使用 Dapr& ...
- Blazor+Dapr+K8s微服务之开发环境调试
1 安装Dapr开发调试环境 1.1 Dapr 完整安装模式不支持开发调试 在上一篇随笔<Blazor+Dapr+K8s微服务之服务调用>中,我们通过为每个微服务运行dapr run -. ...
- dapr微服务.net sdk入门
Actors入门 先决条件 .Net Core SDK 3.0 Dapr CLI Dapr DotNet SDK 概述 本文档描述如何在客户端应用程序上创建Actor(MyActor)并调用其方法. ...
最新文章
- Pandas_transform的用法
- 我对计算机的看法英语作文,我对网络的看法英语作文
- XStream 用法汇总
- Android线性布局(Linear Layout)
- 深夜学算法之SkipList:让链表飞
- Blazor中的无状态组件
- Vim功能键整理(图片来自mooc)
- 【转】SOAR从概念到落地
- Felix的Nodejs代码风格
- python调用大漠找图_[教程贴]按键精灵调用大漠插件后台找图示例
- Cesium专栏-卫星轨迹
- python编程设计_程序设计入门—Python
- 快速轻巧的CQRS和事件源解决方案
- 基于C#net4.5websocket客户端与服务端
- 业务如何驱动技术发展
- 2022-车道线检测综述
- 【批处理】快速批量修改特定文件夹的文件名
- boj 454 帮帮小叮当【SPFA】
- 华为荣耀9刷Android9.0,华为荣耀手机,安卓9.0/EMUI9.0升级常见问题大汇总!
- 北京双线机房服务器托管