注释
基本标准计划于 2025 年 3 月 17 日进入退休期。 有关详细信息,请参阅 Azure Spring Apps 停用公告。
标准消耗和专用计划于 2024 年 9 月 30 日进入停用期,并将在 2025 年 3 月底之前完全关闭。
使用 TLS/SSL 将自定义域从 Azure Spring Apps 迁移到 Azure 容器应用涉及几个步骤,以确保顺利过渡。 本文将引导你完成此过程,包括客户端流量、应用程序间流量和外部服务的流量。
先决条件
- 现有的 Azure 容器应用。 更多信息,请参阅快速入门:使用 Azure 门户部署你的第一个应用程序。
- Azure CLI。
- 现有的 TLS/SSL 证书 - 例如,存储在 Azure KeyVault 中的证书。
- (可选)如果要从 Azure 存储文件共享将证书加载到信任存储中,则需要一个现有的 Azure 存储帐户。 有关详细信息,请参阅创建 Azure 存储帐户。
流向应用程序的客户端流量
默认情况下,除非手动启用 HTTP 流量,否则容器应用中的所有入站流量均使用 HTTPS,可以使用以下命令执行此操作:
az containerapp ingress update \
--resource-group "my-resource-group" \
--name "my-app" \
--allow-insecure
有关为应用配置入口的详细信息,请参阅在 Azure 容器应用中为应用配置入口。
自定义域
若要保护 Azure 容器应用中的自定义域名系统 (DNS) 名称,你可以添加数字安全证书。 该证书支持应用之间的安全通信。
如果需要保护 Azure 容器应用中的自定义域,你可以使用免费且易于使用的专用证书。 有关详细信息,请参阅 Azure 容器应用中的自定义域名和免费托管证书。
如果本地存储了专用证书,可以将其上传。 有关详细信息,请参阅 Azure 容器应用中的自定义域名和自带证书。
如果证书来自 Azure Key Vault,请参阅将证书从 Azure 密钥保管库导入到 Azure 容器应用,了解详细信息。
如果要继续使用 Azure Spring Apps 中的原始证书和域名,可以将证书上传到容器应用或 Azure 密钥保管库。 此外,你还可以更新 DNS 提供程序中的 A 记录或 CNAME,以将原始域名重定向到容器应用 IP 或 URL。
在客户端和容器应用之间启用 mTLS
若要在客户端和容器化应用之间启用双向 TLS (mTLS),请执行以下步骤:
使用以下命令以 YAML 格式导出容器应用配置:
az containerapp show \ --resource-group "my-resource-group" \ --name "my-app" \ --output yaml > app.yaml
更新 app.yaml
clientCertificateMode
中的 值,如以下示例所示:properties: configuration: ingress: clientCertificateMode: require
你可以将此属性设置为以下值之一:
-
require
:对容器应用的所有请求都需要客户端证书。 -
accept
:客户端证书是可选的。 如果未提供客户端证书,则仍会接受请求。 -
ignore
:客户端证书被忽略。
-
使用以下命令将
clientCertificateMode
更改应用到容器应用:az containerapp update \ --resource-group "my-resource-group" \ --name "my-app" \ --yaml app.yaml
有关详细信息,请参阅在 Azure 容器应用中配置客户端证书身份验证。
你需要在代码中处理客户端证书验证。
应用程序间流量
同一应用环境中不同容器应用之间的流量默认使用 HTTP,例如 http://<app-name>
。 若要保护此流量,可以使用以下命令启用对等加密:
# enable when creating the container app
az containerapp env create \
--resource-group "my-resource-group" \
--name "my-app" \
--location "location" \
--enable-peer-to-peer-encryption
# enable for the existing container app
az containerapp env update \
--resource-group "my-resource-group" \
--name "my-app" \
--enable-peer-to-peer-encryption
启用对等加密后,一个容器应用可以使用带有 mTLS 的 HTTPS 访问其他容器应用,例如 https://<app-name>
。 mTLS 中使用的证书为系统分配。
有关详细信息,请参阅 Azure 容器应用环境中的网络的对等加密部分。
流向外部服务的流量
引用来自 Key Vault 的证书并将证书装载到卷中
定义证书时,将创建对 Azure 密钥保管库中存储的证书的引用。 Azure 容器应用自动从密钥保管库检索证书值,并使其可用作容器应用中的机密。
若要引用密钥保管库中的证书,必须先在容器应用中启用托管标识,并为该标识授予对密钥保管库机密的访问权限。
若要在容器应用中启用托管标识,请参阅 Azure 容器应用中的托管标识。
若要授予对密钥保管库证书的访问权限,请在密钥保管库中为创建的托管标识添加角色分配 Key Vault Secrets User
。 如需了解详情,请参阅单个密钥、机密和证书角色分配的最佳做法。
创建容器应用时,将使用 --secrets
参数和以下准则定义证书:
- 参数接受以空格分隔的名称/值对的集合。
- 每个对都由等于号 (
=
) 分隔。 - 若要指定密钥保管库引用,请使用
<certificate-name>=keyvaultref:<key-vault-secret-identifier-of-certificate>,identityref:<managed-identity-ID>
格式。 例如,my-cert=keyvaultref:https://mykeyvault.vault.azure.cn/secrets/mycert,identityref:/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/my-resource-group/providers/Microsoft.ManagedIdentity/userAssignedIdentities/my-identity
。
以下命令提供了一个示例:
az containerapp create \
--resource-group "my-resource-group" \
--name "my-app" \
--environment "my-environment-name" \
--image <image_name> \
--user-assigned "<user-assigned-identity-ID>" \
--secrets "my-cert=keyvaultref:<key-vault-secret-identifier-of-certificate>,identityref:<user-assigned-identity-ID>"
--secret-volume-mount "/mnt/cert"
此处,在 --secrets
参数中声明了证书。 将 <key-vault-secret-identifier-of-certificate>
替换为密钥保管库中证书的机密标识符 URI。 将 <user-assigned-identity-ID>
替换为用户分配的标识的资源 ID。 对于系统分配的标识,请使用 system
而不是资源 ID。 卷中装载的证书名为 my-cert
,类型为“机密”。 卷装载在路径 /mnt/cert 处。然后,应用程序可以将机密作为卷装载中的文件读取。
对于现有容器应用,你可以使用以下命令引用密钥保管库中的机密,并将其装载到卷:
az containerapp secret set \
--resource-group "my-resource-group" \
--name "my-app" \
--secrets "my-cert=keyvaultref:<key-vault-secret-identifier-of-certificate>,identityref:<user-assigned-identity-ID>"
az containerapp update \
--resource-group "my-resource-group" \
--name "my-app" \
--secret-volume-mount "/mnt/cert"
从代码加载证书
已加载的证书在定义的装载路径中可用 - 例如 /mnt/cert/my-cert。使用以下 Java 代码在 Azure 容器应用的应用程序中加载证书。
由于证书装载为机密,其内容在 Base64 中编码,因此可能需要在使用之前对其进行解码。
try {
byte[] encodedBytes = Files.readAllBytes(Paths.get("/mnt/cert/my-cert"));
PKCS12PfxPdu pfx = new PKCS12PfxPdu(Base64.getDecoder().decode(encodedBytes));
List<Certificate> certificates = new ArrayList<>();
for (ContentInfo contentInfo : pfx.getContentInfos()) {
if (contentInfo.getContentType().equals(PKCSObjectIdentifiers.encryptedData)) {
PKCS12SafeBagFactory safeBagFactory = new PKCS12SafeBagFactory(contentInfo,
new JcePKCSPBEInputDecryptorProviderBuilder().build("\0".toCharArray()));
PKCS12SafeBag[] safeBags = safeBagFactory.getSafeBags();
for (PKCS12SafeBag safeBag : safeBags) {
Object bagValue = safeBag.getBagValue();
if (bagValue instanceof X509CertificateHolder) {
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
InputStream in = new ByteArrayInputStream(((X509CertificateHolder) bagValue).getEncoded());
certificates.add(certFactory.generateCertificate(in));
}
}
}
}
// use the loaded certificate in 'certificates'
} catch (PKCSException | CertificateException | IOException e) {
// handle exception
}
在此示例代码中,需要将 org.bouncycastle.bcpkix-lts8on 导入项目以分析证书数据。
将证书加载到信任存储区
使用以下步骤加载证书:
设置存储帐户,例如
/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/my-resource-group/providers/Microsoft.Storage/storageAccounts/mystorageaccount
。下载并上传 JCA 库。 从 Maven 存储库 azure-security-keyvault-jca 获取最新版本的 JCA 库,并将 JAR 文件上传到存储帐户中的文件共享,例如 /jca/lib/azure-security-keyvault-jca.jar。
使用以下步骤修改和上传 Java 安全配置:
在 JDK 中创建 java.security 文件的副本。 对于 Java 版本 8 或更早版本,可以在 $JAVA_HOME/jre/lib/security/java.security 中找到 java.security 文件。 对于 Java 版本 11 或更高版本,可以在 $JAVA_HOME/conf/security 中找到 java.security 文件。
在文件中找到
security.provider.<#>=
属性并添加以下行:security.provider.<#>=com.azure.security.keyvault.jca.KeyVaultJcaProvider
在此行中,数字符号占位符
<#>
表示一个增量高于列表中的最后一个数字,例如security.provider.14
。将修改后的 java.security 文件上传到存储帐户中的文件共享,例如 /jca/security/java.security。
将需要加载到信任存储中的证书上传到存储帐户中的文件共享,例如 /jca/truststore/。
添加卷装载。 若要在容器应用中为 JCA 库和证书添加卷装载,请参阅教程:在 Azure 容器应用中创建 Azure 文件卷装载。 例如,你可以将其装载为 /mnt/jca/。
使用 JCA 相关参数更新图像。 请对 Dockerfile 进行修改,参照以下示例所示:
# filename: JAR.dockerfile FROM mcr.microsoft.com/openjdk/jdk:17-mariner ARG JAR_FILENAME COPY $JAR_FILENAME /opt/app/app.jar ENTRYPOINT ["java", "-Dsecurity.overridePropertiesFile=true", "-Djava.security.properties=/mnt/jca/security/java.security", \ "--module-path", "/mnt/jca/lib", "--add-modules=com.azure.security.keyvault.jca", "-Djavax.net.ssl.trustStoreType=AzureKeyVault", \ "-Dazure.cert-path.custom=/mnt/jca/truststore/", "-jar", "/opt/app/app.jar"]
使用以下命令重新生成映像,然后将其上传到容器注册表:
docker build -t <image-name>:<image-tag> \ -f JAR.dockerfile \ --build-arg JAR_FILENAME=<path-to-jar> \ .
创建或更新容器应用。 更多信息,请参阅快速入门:使用 Azure 门户部署你的第一个应用程序。
有关在 Java 应用程序中使用 Azure 密钥保管库的 JCA 提供程序的详细信息,请参阅 JCA 提供程序示例。
此方法与 Azure Spring Apps 的行为保持一致性。 还可以使用其他方法将证书加载到信任存储中。
通过执行这些步骤,可以使用 TLS/SSL 成功将自定义域从 Azure Spring Apps 迁移到 Azure 容器应用,从而跨所有流量类型保持安全高效的通信。