4小时Dapr+.NET 5+K8S 的实战 https://ke.qq.com/course/4000292?tuin=1271860f
Dapr进阶虚拟机集群实战(非K8S) https://ke.qq.com/course/4002149?tuin=1271860f
什么是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>.daprcomponents中新建文件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:Usersusername.daprcomponentssecrets01.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 .FrontEndinDebug et5.0FrontEnd.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 .FrontEndinDebug et5.0FrontEnd.dll
在RabbitMQ Management中发送消息,消费成功
== APP == info: FrontEnd.Controllers.RabbitBindingController[0] == APP == .............binding.............11122444
限制Secrets访问权限
我们可以在Dapr的默认配置文件C:Usersusername.daprconfig.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 estDaprBackEndFrontEndProgram.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 |