Dapr + .NET Core實戰(七)Secrets

什麼是Secrets

應用程序通常會通過使用專用的存儲來存儲敏感信息,如連接字符串、密鑰等。

通常這需要建立一個密鑰存儲,如Azure Key Vault、Hashicorp等,並在那裏存儲應用程序級別的密鑰。 要訪問這些密鑰存儲,應用程序需要導入密鑰存儲SDK,並使用它訪問這些密鑰。 這可能需要相當數量的模板代碼,這些代碼與應用的實際業務領域無關,因此在多雲場景中,可能會使用不同廠商特定的密鑰存儲,這就成爲一個更大的挑戰。

讓開發人員在任何地方更容易訪問應用程序密鑰, Dapr 提供一個專用的密鑰構建塊 ,允許開發人員從一個存儲獲得密鑰。

使用 Dapr 的密鑰存儲構建塊通常涉及以下內容:

  1. 設置一個特定的密鑰存儲解決方案的組件。
  2. 在應用程序代碼中使用 Dapr Secrets API 獲取密鑰。
  3. 在Dapr的Component文件中引用密鑰

工作原理

 

 

  1. 服務A調用 Dapr Secrets API,提供要檢索的Serects的名稱和要查詢的項名字。
  2. Dapr sidecar 從Secrets存儲中檢索指定的機密。
  3. 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:[email protected]: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成功

以下表格列出了所有可能的訪問權限配置

ScenariosdefaultAccessallowedSecretsdeniedSecretspermission
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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章