Dapr + .NET Core实战(七)Secrets
什么是Secrets
应用程序通常会通过使用专用的存储来存储敏感信息,如连接字符串、密钥等。
通常这需要建立一个密钥存储,如Azure Key Vault、Hashicorp等,并在那里存储应用程序级别的密钥。 要访问这些密钥存储,应用程序需要导入密钥存储SDK,并使用它访问这些密钥。 这可能需要相当数量的模板代码,这些代码与应用的实际业务领域无关,因此在多云场景中,可能会使用不同厂商特定的密钥存储,这就成为一个更大的挑战。
让开发人员在任何地方更容易访问应用程序密钥, Dapr 提供一个专用的密钥构建块 ,允许开发人员从一个存储获得密钥。
使用 Dapr 的密钥存储构建块通常涉及以下内容:
- 设置一个特定的密钥存储解决方案的组件。
- 在应用程序代码中使用 Dapr Secrets API 获取密钥。
- 在Dapr的Component文件中引用密钥
工作原理

- 服务A调用 Dapr Secrets API,提供要检索的Serects的名称和要查询的项名字。
- Dapr sidecar 从Secrets存储中检索指定的机密。
- Dapr sidecar 将Secrets信息返回给服务。
Dapr目前支持的Secrets存储请见存储
使用Secrets时,应用程序与 Dapr sidecar 交互。 sidecar 公开Secrets API。 可以使用 HTTP 或 gRPC 调用 API。 使用以下 URL 调用 HTTP API:
http://localhost:<dapr-port>/v1.0/secrets/<store-name>/<name>?<metadata>
URL 包含以下字段:
<dapr-port>指定 Dapr sidecar 侦听的端口号。<store-name>指定 Dapr Secrets存储的名称。<name>指定要检索的密钥的名称。<metadata>提供Secrets的其他信息。 此段是可选的,每个Secrets存储的元数据属性不同。 有关元数据属性详细信息
项目实战
通过Dapr SDK获取secrets
仍然使用FrontEnd项目,并使用本地文件存储Secrets,首先在默认component目录C:\Users\<username>\.dapr\components中新建文件secrets01.json,声明密钥内容
{
"RabbitMQConnectStr": "amqp://admin:123456@192.168.43.101:5672"
}
在此目录新建secrets01.yaml定义store
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: secrets01
spec:
type: secretstores.local.file
version: v1
metadata:
- name: secretsFile
value: C:\Users\username\.dapr\components\secrets01.json
- name: nestedSeparator
value: ":"
定义接口获取Secrets01的内容,新建SecretsController
using Dapr.Client; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging; using System.Collections.Generic;
using System.Threading.Tasks; namespace FrontEnd.Controllers
{
[Route("[controller]")]
[ApiController]
public class SecretsController : ControllerBase
{
private readonly ILogger<SecretsController> _logger;
private readonly DaprClient _daprClient;
public SecretsController(ILogger<SecretsController> logger, DaprClient daprClient)
{
_logger = logger;
_daprClient = daprClient;
} [HttpGet]
public async Task<ActionResult> GetAsync()
{
Dictionary<string, string> secrets = await _daprClient.GetSecretAsync("secrets01", "RabbitMQConnectStr");
return Ok(secrets);
}
}
}
运行Frontend
dapr run --dapr-http-port 3501 --app-port 5001 --app-id frontend dotnet .\FrontEnd\bin\Debug\net5.0\FrontEnd.dll
验证此api,获取成功

通过IConfiguration访问Secrets
Dapr还提供了从IConfiguration中访问Secrets的方法,首先引入nuget包Dapr.Extensions.Config

在Program.cs中修改注册
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(config =>
{
var daprClient = new DaprClientBuilder().Build();
var secretDescriptors = new List<DaprSecretDescriptor> { new DaprSecretDescriptor("RabbitMQConnectStr") };
config.AddDaprSecretStore("secrets01", secretDescriptors, daprClient);
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>().UseUrls("http://*:5001");
});
在SecretsController注入IConfiguration
private readonly ILogger<SecretsController> _logger;
private readonly DaprClient _daprClient;
private readonly IConfiguration _configuration;
public SecretsController(ILogger<SecretsController> logger, DaprClient daprClient, IConfiguration configuration)
{
_logger = logger;
_daprClient = daprClient;
_configuration = configuration;
}
在SecretsController中新增接口
[HttpGet("get01")]
public async Task<ActionResult> Get01Async()
{
return Ok(_configuration["RabbitMQConnectStr"]);
}
调用接口,获取数据成功

其他组件引用Secrets
Dapr的其他组件,同样可以引用Secrets,我们以上节RabbitMQBinding为例,修改rabbitbinding.yaml
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: RabbitBinding
spec:
type: bindings.rabbitmq
version: v1
metadata:
- name: queueName
value: queue1
- name: host
secretKeyRef:
name: RabbitMQConnectStr
key: RabbitMQConnectStr
- name: durable
value: true
- name: deleteWhenUnused
value: false
- name: ttlInSeconds
value: 60
- name: prefetchCount
value: 0
- name: exclusive
value: false
- name: maxPriority
value: 5
auth:
secretStore: secrets01
secretKeyRef元素引用指定的密钥。 它将替换以前的 明文 值。 在 auth 中找到对应的secretStore。
现在运行Frontend
dapr run --dapr-http-port 3501 --app-port 5001 --app-id frontend dotnet .\FrontEnd\bin\Debug\net5.0\FrontEnd.dll
在RabbitMQ Management中发送消息,消费成功
== APP == info: FrontEnd.Controllers.RabbitBindingController[0]
== APP == .............binding.............11122444
限制Secrets访问权限
我们可以在Dapr的默认配置文件C:\Users\username\.dapr\config.yaml中设置Secrets的访问权限,现在我们尝试禁止secrets01的权限
apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
name: daprConfig
spec:
tracing:
samplingRate: "1"
zipkin:
endpointAddress: http://localhost:9411/api/v2/spans
secrets:
scopes:
- storeName: secrets01
defaultAccess: deny
设置之后,Frontend会启动失败,因为我们在Program.cs中设置了读取secrets01。
== APP == Unhandled exception. Dapr.DaprException: Secret operation failed: the Dapr endpoint indicated a failure. See InnerException for details.
== APP == ---> Grpc.Core.RpcException: Status(StatusCode="PermissionDenied", Detail="access denied by policy to get "RabbitMQConnectStr" from "secrets01"")
== APP == at Dapr.Client.DaprClientGrpc.GetSecretAsync(String storeName, String key, IReadOnlyDictionary`2 metadata, CancellationToken cancellationToken)
== APP == --- End of inner exception stack trace ---
== APP == at Dapr.Client.DaprClientGrpc.GetSecretAsync(String storeName, String key, IReadOnlyDictionary`2 metadata, CancellationToken cancellationToken)
== APP == at Dapr.Extensions.Configuration.DaprSecretStore.DaprSecretStoreConfigurationProvider.LoadAsync()
== APP == at Dapr.Extensions.Configuration.DaprSecretStore.DaprSecretStoreConfigurationProvider.Load()
== APP == at Microsoft.Extensions.Configuration.ConfigurationRoot..ctor(IList`1 providers)
== APP == at Microsoft.Extensions.Configuration.ConfigurationBuilder.Build()
== APP == at Microsoft.Extensions.Hosting.HostBuilder.BuildAppConfiguration()
== APP == at Microsoft.Extensions.Hosting.HostBuilder.Build()
== APP == at FrontEnd.Program.Main(String[] args) in C:\demo\test\DaprBackEnd\FrontEnd\Program.cs:line 20
我们可以修改配置让其允许
apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
name: daprConfig
spec:
tracing:
samplingRate: "1"
zipkin:
endpointAddress: http://localhost:9411/api/v2/spans
secrets:
scopes:
- storeName: secrets01
defaultAccess: deny
allowedSecrets: ["RabbitMQConnectStr"]
重启Frontend成功
以下表格列出了所有可能的访问权限配置
| Scenarios | defaultAccess | allowedSecrets | deniedSecrets | permission |
|---|---|---|---|---|
| 1 - Only default access | deny/allow | empty | empty | deny/allow |
| 2 - Default deny with allowed list | deny | [“s1”] | empty | only “s1” can be accessed |
| 3 - Default allow with deneied list | allow | empty | [“s1”] | only “s1” cannot be accessed |
| 4 - Default allow with allowed list | allow | [“s1”] | empty | only “s1” can be accessed |
| 5 - Default deny with denied list | deny | empty | [“s1”] | deny |
| 6 - Default deny/allow with both lists | deny/allow | [“s1”] | [“s2”] | only “s1” can be accessed |
Dapr + .NET Core实战(七)Secrets的更多相关文章
- Dapr + .NET Core实战(十四)虚拟机集群部署 mDNS + Consul
前面我们说了在单机模式下和K8S集群下的Dapr实战,这次我们来看看如何在不使用K8S的情况下,在一个传统的虚拟机集群里来部署Dapr. 1.环境准备 我们准备两台centos7虚拟机 Dapr1:1 ...
- Dapr + .NET Core实战(九)本地调试
前几节开发Dapr应用程序时,我们使用 dapr cli 来启动dapr服务,就像这样: dapr run --dapr-http-port 3501 --app-port 5001 --app-id ...
- Dapr + .NET Core实战(十一)单机Dapr集群
如何单机部署Dapr集群 第十篇讲过了K8S集群下如何使用Dapr运行程序,但是很多人一直在问如何单机下进行Dapr的负载,这节课我们来聊聊如何单机进行Dapr的负载. 首先要说的是单机下,通过 da ...
- Dapr + .NET Core实战(十一)单机Dapr集群负载均衡
如何单机部署Dapr集群 第十篇讲过了K8S集群下如何使用Dapr运行程序,但是很多人一直在问如何单机下进行Dapr的负载,这节课我们来聊聊如何单机进行Dapr的负载. 首先要说的是单机下,通过 da ...
- Dapr + .NET Core实战(十二)服务调用之GRPC
什么是GRPC gRPC 是一种与语言无关的高性能远程过程调用 (RPC) 框架. gRPC 的主要优点是: 高性能轻量级 RPC 框架. 协定优先 API 开发,默认使用协议缓冲区,允许与语言无关的 ...
- Dapr + .NET Core实战(十三)跨语言开发
因为基于Dapr的服务架构是不限语言的,我们来看看Dapr的跨语言开发.我们使用golang,python,.NET来实现跨语言的服务调用,拓扑如下 我们继续使用.NET 5的fontend和back ...
- Dapr + .NET Core实战(四)发布和订阅
什么是发布-订阅 发布订阅是一种众所周知并被广泛使用的消息传送模式,常用在微服务架构的服务间通信,高并发削峰等情况.但是不同的消息中间件之间存在细微的差异,项目使用不同的产品需要实现不同的实现类,虽然 ...
- Dapr + .NET Core实战(五)Actor
什么是Actor模式 Actors 为最低级别的"计算单元" 以上解释来自官方文档,看起来"晦涩难懂".大白话就是说Actors模式是一段需要单线程执行的代码块 ...
- Dapr + .NET Core实战(六)绑定
什么是绑定 处理外部事件或调用外部接口的功能就是绑定,绑定可以提供以下好处: 避免连接到消息系统 ( 如队列和消息总线 ) 并进行轮询的复杂性 聚焦于业务逻辑,而不是如何与系统交互 使代码不受 SDK ...
随机推荐
- Raspberry Pi 中安装Mono
摘自:http://www.phodal.com/blog/user-csharp-develop-raspberry-pi-application/ Raspberry Pi C# Mono Lin ...
- qt 中的对象树
本节内容讲解了什么是对象树以及其所带来的 GUI 编程好处.最后说明了在对象树中析构顺序问题并举了个特殊的例子,来说明平时编程中需要注意的一个点. 什么是对象树? 我们常常听到 QObject 会用对 ...
- 怎样在Qt中建立使用动态链接库
参考网址: https://blog.csdn.net/q496713258/article/details/6990837 qt 的学习网址: http://c.biancheng.net/view ...
- 【nodejs】express框架+mysql后台数据查询
一 环境部署 1,首先安装nodejs,并配置好环境变量(看自己习惯), 2,安装Express npm install express -g //全局安装 npm install express-g ...
- spring初始化源码浅析之关键类和扩展接口
目录 1.关键接口和类 1.1.关键类之 DefaultListableBeanFactory 1.2.关键类之XmlBeanDefinitionReader 1.3.关键类之ClassPathXml ...
- BeanUtils低依赖属性拷贝测试(一)
javabean package entity; import java.util.Date; /** * 一个测试用: * student,javaBean * @author mzy * 一个标准 ...
- py2neo学习记录
py2neo 通用 # -*- coding: UTF-8 -*- from py2neo import Graph, Node, Relationship, walk, NodeMatcher, R ...
- Mac OS ssh 禁用密码登陆
$ sudo vim /etc/ssh/sshd_config PubkeyAuthentication yes PasswordAuthentication no UsePAM no then: $ ...
- 为开源项目 go-gin-api 增加后台任务模块
目录 任务管理界面 (WEB) 任务调度器 任务执行器 小结 推荐阅读 任务管理界面 (WEB) 支持在 WEB 界面 中对任务进行管理,例如:新增任务.编辑任务.启用/禁用任务.手动执行任务 等. ...
- HashSet的存储原理
HashSet的底层用哈希散列表来存储对象(默认长度为16的数组),假如: Set set=new HashSet(); set.add(obj); 内部存储过程为:定义h=obj.hashCode, ...