Azure AD 托管标识: 使用托管标识获取密钥存储凭据





5.00/5 (1投票)
托管标识如何支持 Spring Web 应用程序从 Azure 密钥存储获取凭据,
在本系列三篇文章的前两篇中,我们探讨了使用 Azure AD 托管标识来连接托管在 Azure 应用服务上的应用程序,然后是 Azure Kubernetes 服务。除了使应用程序能够访问数据库等服务外,托管标识还可以从密钥库中检索凭据。
本系列的第三篇也是最后一篇文章将指导您使用托管标识处理 Azure Vault,用于部署在 Azure Kubernetes 服务上的 Spring Boot 应用程序。Azure Key Vault 存储各种服务的凭据,包括 Azure 和外部服务。
最好从键值存储中获取 API 访问密钥,而不是在代码中管理它们,从而保护凭据和它们解锁的服务免受未经授权的访问,并减少出错的机会。我们可以将管理密钥的任务外包给专门存储它们的服务,而不是自己管理密钥。因此,我们将创建一个特定于应用程序的标识,并使用该标识访问 Azure Key Vault。
必备组件
要遵循本教程,您应该熟悉 Java 并首先设置一些东西
- 访问 Azure 云平台。注册可享受 12 个月热门服务免费使用以及 200 美元的积分。
- 访问 SendGrid 电子邮件平台。每天最多可发送 100 封电子邮件,免费注册。
- Rkord 应用程序。这个 Spring Boot 演示应用程序支持用户记笔记。我们使用 Spring MVC、Thymeleaf 框架和 Cosmos DB 开发了该应用程序。此前,它托管在 Azure 应用服务上,然后是 Azure Kubernetes 服务。
您可以在 GitHub 上找到本文版本 Rkord 应用程序的完整代码。
创建 Spring Boot 应用程序
到目前为止,Rkord 应用程序可以以 Markdown 格式记录用户笔记。它还使用“最旧优先”的方法显示以前的用户笔记。
应用程序的新要求是通过电子邮件共享用户笔记,无需任何特定的电子邮件格式。邮件消息仅包含所选用户笔记的 HTML 格式。此外,我们的应用程序将使用 SendGrid
外部服务发送邮件。
要使用邮件功能增强应用程序,请首先添加 SendGrid
Java SDK
<dependency>
<groupId>com.sendgrid</groupId>
<artifactId>sendgrid-java</artifactId>
<version>4.8.1</version>
</dependency>
更新笔记控制器
通过电子邮件共享笔记需要一个带有收件人电子邮件地址参数的 POST
API。因此,将以下方法添加到 NotesController
类。该方法首先使用指定的 ID 检索用户笔记。然后,它使用邮件助手类生成邮件消息并调用 SendGrid
电子邮件发送 API。
@PostMapping("/note/{id}/share")
public String shareNote(@PathVariable String id, @RequestParam String emailAddress) {
Notes note=notesRepository.findById(id).block();
String subject = "A Note has been shared";
Email to = new Email(emailAddress);
Content content = new Content("text/html",note.getMessage());
Mail mail = new Mail(from, subject, to, content);
Request request = new Request();
try {
request.setMethod(Method.POST);
request.setEndpoint("mail/send");
request.setBody(mail.build());
sendGrid.api(request);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
return "redirect:/";
}
请注意,电子邮件消息支持各种类型的内容,如纯文本、HTML、XML 等。Rkord 应用程序仅需要 text/html
类型。
更新笔记 HTML
接下来,更新 Thymeleaf 模板 notes.html(在 src/main/resources/template 下),以在每个显示的用户笔记下方渲染一个带有电子邮件按钮的文本字段。Bootstrap 输入组功能创建用户界面 (UI) 组件。
<div class="mb-3" th:each="msg : ${userNotes}">
<div th:utext="${msg.message}" class="alert alert-primary"></div>
<form th:action="@{/note/__${msg.id}__/share}" method="post">
<div class="input-group">
<button class="btn btn-outline-secondary"
type="submit" id="button-addon1">Email</button>
<input type="text" name="emailAddress"
id="emailAddress" class="form-control"
placeholder="Recipient's email address"
aria-label="Recipient's email address"
aria-describedby="button-addon1">
</div>
</form>
</div>
配置 SendGrid
NoteContoller
方法需要一个 SendGrid
实例和关联的邮件发件人地址。类路径中没有可用的 SendGrid
启动配置。因此,创建以下配置类,它提供所需的 bean
@Configuration
public class SendgridConfig {
@Value("${sendgrid.key}")
private String key;
@Value("${sendgrid.from}")
private String from;
@Bean
public SendGrid sendGridBean() {
SendGrid sg = new SendGrid(key);
return sg;
}
@Bean
public Email emailFrom() {
return new Email(from);
}
}
您必须使用 SendGrid.key
指定您的 SendGrid
API 密钥,并使用 sendgrid.from
属性指定配置的发件人电子邮件地址。
sendgrid.key=A_VALID_KEY
sendgrid.from=mail@example.com
应用程序应该成功构建。如 前一篇文章 中所述,您可以提交更改并将应用程序部署到 Azure Kubernetes 服务。
创建 Azure Key Vault 服务实例
上述应用程序按预期工作。但是,它在代码中管理访问密钥,这可能会导致安全问题,例如您的帐户意外收费、未经授权的访问、恶意内容、潜在攻击等。
最好避免管理 API 密钥,而是将它们外包给专门存储密钥的服务。您可以将 API 密钥存储在 Azure Key Vault 存储中,Rkord 应用程序使用托管标识访问该存储。
首先从 Azure 门户创建 Key Vault 服务实例。指定名称、资源组和预期的定价层。查看指定的配置,然后单击创建以生成实例。
接下来,通过单击生成/导入到密钥控制台添加 SendGrid
API 密钥。将密钥名称指定为 SENDGRID-KEY
,值为 API 密钥。
设置 Key Vault RBAC
此前,我们启用了 Azure Kubernetes 集群的托管标识交换。托管标识服务提供以下凭据
- Kubernetes 服务凭据,用于访问 API 服务器
- Kubelet 服务凭据,由节点用于访问其他服务
应用程序 Pod 将使用 Kubelet 服务凭据访问 Key Vault。因此,使用此命令确定 kubelet 服务主体
az aks show --resource-group rkord-notes-rg --name rkord-dev-aks
--query "identityProfile.kubeletidentity"
接下来,允许 Key Vault 访问上述服务主体。打开访问策略控制台以创建所需的访问策略。从从模板配置下拉列表中选择密钥管理。该值将配置所需的权限。接下来,将 AKS 代理池标识指定为策略的主体,然后单击添加。
集成 Azure Key Vault 服务
Azure Key Vault 服务必须使用特定语言的 SDK 进行集成。因此,将 SDK 添加到项目依赖项集中
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-security-keyvault-secrets</artifactId>
<version>4.3.5</version>
</dependency>
由于托管标识与 Key Vault 服务集成,因此将 azure-identity
库添加到项目依赖项列表中
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-identity</artifactId>
<version>1.3.7</version>
</dependency>
您必须配置 Key Vault 客户端以使用托管标识进行连接。然后,加载所需的密钥并创建 SendGrid
bean 实例。
应用程序测试不需要此查找。它们将使用虚拟密钥,因为测试不执行邮件发送。因此,将现有的 SendGridConfig
类移动到 test 文件夹。
此前,我们已创建配置以加载用于 Cosmos DB 集成的托管标识 (使用 ManagedIdentityCredential
)。与 Key Vault 一起使用时,无需进行必要的配置更改。
@Profile("prod")
@Configuration
public class CosmosDBConfig extends AbstractCosmosConfiguration {
// Removed for Bevity
@Bean
public ManagedIdentityCredential dbCredential() {
ManagedIdentityCredential managedIdentityCredential =
new ManagedIdentityCredentialBuilder()
.build();
return managedIdentityCredential;
}
}
接下来,创建以下配置类,该类将托管标识与 Key Vault 客户端一起使用。连接到 Key Vault 服务后,您可以根据实例中保存的命名密钥加载值。配置类需要 Key Vault 实例位置的属性,因此将它们添加到 src/main/resources 目录中的 application.properties 文件中。
@Profile("prod")
@Configuration
public class SendgridConfig {
@Value("${sendgrid.from}")
private String from;
@Value("${vault.loc}")
private String loc;
@Bean
public SendGrid sendGridBean(ManagedIdentityCredential identityCredential) {
SecretClient client = new SecretClientBuilder()
.vaultUrl(loc)
.credential(identityCredential)
.buildClient();
KeyVaultSecret key = client.getSecret("SENDGRID-KEY");
SendGrid sg = new SendGrid(key.getValue());
return sg;
}
@Bean
public Email emailFrom() {
return new Email(from);
}
}
上述类用配置文件注解标记,因此仅当相应的 Spring 配置文件被激活时才起作用。此前,我们通过修改 Dockerfile 中的 CMD
来启用容器的配置文件,如下所示
CMD ["java", "-jar", "-Dspring.profiles.active=prod","/rkord.jar"]
将更改推送到 GitHub 存储库以调用构建和部署。部署成功后,我们从 AKS 入口控制台确定应用程序 URL。
您可以通过为相应的笔记提供电子邮件地址来通过电子邮件发送用户笔记。
摘要
您现在知道如何将密钥存储在 Azure Key Vault 中并使用托管标识访问密钥存储。该过程为连接到外部第三方服务和 Azure 服务提供了安全的凭据交换。托管标识与 Azure Key Vault 相结合,解决了凭据管理和安全性的挑战,使开发人员能够专注于为应用程序增加价值。
在本系列中,我们探讨了如何使用托管标识来帮助 Azure 应用服务和 Azure Kubernetes 服务上的应用程序访问数据库。我们还使用托管标识获取安全存储在密钥存储中的凭据。现在您拥有了所需的所有工具,可以确保您的服务安全,同时仍然允许您的应用程序访问它们所需的服务和数据。
立即设置托管标识,将这些相同的原则应用于您部署在 Azure 上的 Java 应用程序。
要详细了解 Java Azure 身份库,请参阅 Java 和 Azure Identity 的 Azure 身份验证。