This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Secret 管理

安全地从应用程序访问 Secret

1 - Secrets 管理概述

Secrets 管理 API 构建块概述

应用程序通常使用专用的 secret 存储来保存敏感信息。例如,您可以使用存储在 secret 存储中的连接字符串、密钥、令牌和其他应用程序级别的 secret 来对数据库、服务和外部系统进行身份验证,例如 AWS Secrets Manager, Azure Key Vault, Hashicorp Vault 等

为了访问这些 secret 存储,应用程序需要导入 secret 存储的 SDK。在多云场景中,这种情况更具挑战性,因为可能会使用不同供应商特定的 secret 存储。

Secrets 管理 API

Dapr 的专用 secrets 构建块 API 使开发人员更容易从 secret 存储中使用应用程序 secret。要使用 Dapr 的 secret 存储构建块,您需要:

  1. 为特定的 secret 存储解决方案设置一个组件。
  2. 在应用程序代码中使用 Dapr secrets API 检索 secret。
  3. 可选地,在 Dapr 组件文件中引用 secret。

以下概述视频和演示展示了 Dapr secrets 管理的工作原理。

功能

Secrets 管理 API 构建块为您的应用程序带来了多种功能。

在不更改应用程序代码的情况下配置 secret

您可以在应用程序代码中调用 secrets API,从 Dapr 支持的 secret 存储中检索和使用 secret。观看此视频以了解如何在应用程序中使用 secrets 管理 API 的示例。

例如,下图显示了一个应用程序从配置的云 secret 存储中请求名为 “mysecret” 的 secret,该 secret 存储名为 “vault”。

应用程序还可以使用 secrets API 从 Kubernetes secret 存储中访问 secret。默认情况下,Dapr 在 Kubernetes 模式下启用了内置的 Kubernetes secret 存储,可以通过以下方式部署:

  • 使用 Helm 的默认设置,或
  • 运行 dapr init -k

如果您使用其他 secret 存储,可以通过在 deployment.yaml 文件中添加注释 dapr.io/disable-builtin-k8s-secret-store: "true" 来禁用(不配置)Dapr Kubernetes secret 存储。默认值为 false

在下面的示例中,应用程序从 Kubernetes secret 存储中检索相同的 secret “mysecret”。

在 Azure 中,您可以配置 Dapr 使用托管身份通过 Azure Key Vault 检索 secret。在下面的示例中:

  1. 配置了一个 Azure Kubernetes Service (AKS) 集群 以使用托管身份。
  2. Dapr 使用 pod 身份 代表应用程序从 Azure Key Vault 检索 secret。

在上述示例中,应用程序代码无需更改即可获取相同的 secret。Dapr 通过 secrets 管理构建块 API 使用 secret 管理组件。

尝试使用 secrets API 通过我们的快速入门或教程之一。

在 Dapr 组件中引用 secret 存储

在配置 Dapr 组件(如 state 存储)时,通常需要在组件文件中包含凭据。或者,您可以将凭据放在 Dapr 支持的 secret 存储中,并在 Dapr 组件中引用该 secret。这是首选方法和推荐的最佳实践,尤其是在生产环境中。

有关更多信息,请阅读在组件中引用 secret 存储

限制对 secret 的访问

为了对 secret 的访问提供更细粒度的控制,Dapr 提供了定义范围和限制访问权限的能力。了解更多关于使用 secret 范围的信息。

尝试 secrets 管理

快速入门和教程

想要测试 Dapr secrets 管理 API 吗?通过以下快速入门和教程来查看 Dapr secrets 的实际应用:

快速入门/教程描述
Secrets 管理快速入门使用 secrets 管理 API 从配置的 secret 存储中在应用程序代码中检索 secret。
Secret Store 教程演示如何使用 Dapr Secrets API 访问 secret 存储。

直接在您的应用中开始管理 secret

想要跳过快速入门?没问题。您可以直接在应用程序中尝试使用 secret 管理构建块来检索和管理 secret。在安装 Dapr后,您可以从secrets 使用指南开始使用 secrets 管理 API。

下一步

2 - 如何检索 Secret

使用 Secret 存储构建块安全地检索 Secret

在了解了Dapr Secret 构建块的功能后,接下来学习如何在服务中使用它。本指南将演示如何调用 Secret API,并从配置的 Secret 存储中将 Secret 检索到应用程序代码中。

示例服务的 Secret 管理示意图。

配置 Secret 存储

在应用程序代码中检索 Secret 之前,您需要先配置一个 Secret 存储组件。此示例配置了一个使用本地 JSON 文件存储 Secret 的 Secret 存储。

在项目目录中,创建一个名为 secrets.json 的文件,内容如下:

{
   "secret": "Order Processing pass key"
}

创建一个名为 components 的新目录。进入该目录并创建一个名为 local-secret-store.yaml 的组件文件,内容如下:

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: localsecretstore
spec:
  type: secretstores.local.file
  version: v1
  metadata:
  - name: secretsFile
    value: secrets.json  # Secret 文件的路径
  - name: nestedSeparator
    value: ":"

更多信息:

获取 Secret

通过调用 Dapr sidecar 的 Secret API 来获取 Secret:

curl http://localhost:3601/v1.0/secrets/localsecretstore/secret

查看完整的 API 参考

从代码中调用 Secret API

现在您已经设置了本地 Secret 存储,可以通过 Dapr 从应用程序代码中获取 Secret。以下是利用 Dapr SDK 检索 Secret 的代码示例。

// 依赖项
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Dapr.Client;
using Microsoft.AspNetCore.Mvc;
using System.Threading;
using System.Text.Json;

// 代码
namespace EventService
{
    class Program
    {
        static async Task Main(string[] args)
        {
            string SECRET_STORE_NAME = "localsecretstore";
            using var client = new DaprClientBuilder().Build();
            // 使用 Dapr SDK 获取 Secret
            var secret = await client.GetSecretAsync(SECRET_STORE_NAME, "secret");
            Console.WriteLine($"Result: {string.Join(", ", secret)}");
        }
    }
}
// 依赖项
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.dapr.client.DaprClient;
import io.dapr.client.DaprClientBuilder;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;

// 代码
@SpringBootApplication
public class OrderProcessingServiceApplication {

    private static final Logger log = LoggerFactory.getLogger(OrderProcessingServiceApplication.class);
    private static final ObjectMapper JSON_SERIALIZER = new ObjectMapper();

    private static final String SECRET_STORE_NAME = "localsecretstore";

    public static void main(String[] args) throws InterruptedException, JsonProcessingException {
        DaprClient client = new DaprClientBuilder().build();
        // 使用 Dapr SDK 获取 Secret
        Map<String, String> secret = client.getSecret(SECRET_STORE_NAME, "secret").block();
        log.info("Result: " + JSON_SERIALIZER.writeValueAsString(secret));
    }
}
# 依赖项 
import random
from time import sleep    
import requests
import logging
from dapr.clients import DaprClient
from dapr.clients.grpc._state import StateItem
from dapr.clients.grpc._request import TransactionalStateOperation, TransactionOperationType

# 代码
logging.basicConfig(level = logging.INFO)
DAPR_STORE_NAME = "localsecretstore"
key = 'secret'

with DaprClient() as client:
    # 使用 Dapr SDK 获取 Secret
    secret = client.get_secret(store_name=DAPR_STORE_NAME, key=key)
    logging.info('Result: ')
    logging.info(secret.secret)
    # 使用 Dapr SDK 获取批量 Secret
    secret = client.get_bulk_secret(store_name=DAPR_STORE_NAME)
    logging.info('Result for bulk secret: ')
    logging.info(sorted(secret.secrets.items()))
// 依赖项 
import (
	"context"
	"log"

	dapr "github.com/dapr/go-sdk/client"
)

// 代码
func main() {
	client, err := dapr.NewClient()
	SECRET_STORE_NAME := "localsecretstore"
	if err != nil {
		panic(err)
	}
	defer client.Close()
	ctx := context.Background()
     // 使用 Dapr SDK 获取 Secret
	secret, err := client.GetSecret(ctx, SECRET_STORE_NAME, "secret", nil)
	if secret != nil {
		log.Println("Result : ")
		log.Println(secret)
	}
    // 使用 Dapr SDK 获取批量 Secret
	secretBulk, err := client.GetBulkSecret(ctx, SECRET_STORE_NAME, nil)

	if secret != nil {
		log.Println("Result for bulk: ")
		log.Println(secretBulk)
	}
}
// 依赖项 
import { DaprClient, HttpMethod, CommunicationProtocolEnum } from '@dapr/dapr'; 

// 代码
const daprHost = "127.0.0.1"; 

async function main() {
    const client = new DaprClient({
        daprHost,
        daprPort: process.env.DAPR_HTTP_PORT,
        communicationProtocol: CommunicationProtocolEnum.HTTP,
    });
    const SECRET_STORE_NAME = "localsecretstore";
    // 使用 Dapr SDK 获取 Secret
    var secret = await client.secret.get(SECRET_STORE_NAME, "secret");
    console.log("Result: " + secret);
    // 使用 Dapr SDK 获取批量 Secret
    secret = await client.secret.getBulk(SECRET_STORE_NAME);
    console.log("Result for bulk: " + secret);
}

main();

相关链接

3 - 如何使用:配置 secret 访问范围

通过设置访问范围限制应用程序从 secret 存储中读取的 secret

当您为应用程序配置了 secret 存储后,Dapr 应用程序默认可以访问该存储中定义的所有 secret。

您可以通过在应用程序配置中定义 secret 访问范围策略,来限制 Dapr 应用程序对特定 secret 的访问权限。

secret 访问范围策略适用于任何secret 存储,包括:

  • 本地 secret 存储
  • Kubernetes secret 存储
  • 公有云 secret 存储

有关如何设置secret 存储的详细信息,请阅读如何:检索 secret

观看此视频以了解如何在应用程序中使用 secret 访问范围的演示。

场景 1:拒绝访问 secret 存储中的所有 secret

在此示例中,所有 secret 访问都被拒绝给运行在 Kubernetes 集群上的应用程序,该集群配置了名为 mycustomsecretstoreKubernetes secret 存储。除了用户定义的自定义存储外,示例还配置了 Kubernetes 默认存储(名为 kubernetes),以确保所有 secret 都被拒绝访问。了解有关 Kubernetes 默认 secret 存储的更多信息

定义以下 appconfig.yaml 配置,并使用命令 kubectl apply -f appconfig.yaml 将其应用于 Kubernetes 集群。

apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
  name: appconfig
spec:
  secrets:
    scopes:
      - storeName: kubernetes
        defaultAccess: deny
      - storeName: mycustomsecreststore
        defaultAccess: deny

对于需要拒绝访问 Kubernetes secret 存储的应用程序,请按照这些说明,并将以下注释添加到应用程序 pod:

dapr.io/config: appconfig

配置完成后,应用程序将无法访问 Kubernetes secret 存储中的任何 secret。

场景 2:仅允许访问 secret 存储中的某些 secret

此示例使用名为 vault 的 secret 存储。这可以是设置在应用程序上的 Hashicorp secret 存储组件。要允许 Dapr 应用程序仅访问 vault secret 存储中的 secret1secret2,请定义以下 appconfig.yaml

apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
  name: appconfig
spec:
  secrets:
    scopes:
      - storeName: vault
        defaultAccess: deny
        allowedSecrets: ["secret1", "secret2"]

vault secret 存储的默认访问是 deny,但应用程序可以根据 allowedSecrets 列表访问特定的 secret。了解如何将配置应用于 sidecar

场景 3:拒绝访问 secret 存储中的某些敏感 secret

定义以下 config.yaml

apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
  name: appconfig
spec:
  secrets:
    scopes:
      - storeName: vault
        defaultAccess: allow # 这是默认值,可以省略
        deniedSecrets: ["secret1", "secret2"]

此示例配置明确拒绝访问名为 vault 的 secret 存储中的 secret1secret2,同时允许访问所有其他 secret。了解如何将配置应用于 sidecar

权限优先级

allowedSecretsdeniedSecrets 列表的设置优先于 defaultAccess 策略。

场景defaultAccessallowedSecretsdeniedSecrets权限
1 - 仅默认访问deny/allowdeny/allow
2 - 默认拒绝并允许列表deny[“s1”]仅 “s1” 可访问
3 - 默认允许并拒绝列表allow[“s1”]仅 “s1” 不可访问
4 - 默认允许并允许列表allow[“s1”]仅 “s1” 可访问
5 - 默认拒绝并拒绝列表deny[“s1”]deny
6 - 默认拒绝/允许并同时有列表deny/allow[“s1”][“s2”]仅 “s1” 可访问

相关链接