Share via


Configurar MicroProfile com o Azure Key Vault

Este tutorial demonstra como configurar um aplicativo MicroProfile para recuperar segredos do Cofre de Chaves do Azure usando as APIs de Configuração do MicroProfile. Os desenvolvedores se beneficiam da API MicroProfile Config padrão aberta para recuperar e injetar dados de configuração em seus microsserviços.

Pré-requisitos

  • Uma assinatura do Azure: se você ainda não tiver uma assinatura do Azure, poderá ativar o benefício de assinante do MSDN ou se inscrever para uma conta gratuita.
  • CLI do Azure para ambientes do tipo Unix. Esse artigo requer apenas a variante Bash da CLI do Azure.
    • Instale a CLI do Azure e entre interativamente com o comando az login para fazer logon no Azure antes de usar DefaultAzureCredential o código.
      az login
      
    • Este artigo requer pelo menos a versão 2.55.0 da CLI do Azure. Se você está usando o Azure Cloud Shell, a última versão já está instalada.
  • O Azure Cloud Shell tem todos esses pré-requisitos pré-instalados. Para saber mais, confira Início Rápido para o Azure Cloud Shell.
  • Se você estiver executando os comandos neste guia localmente (em vez de usar o Azure Cloud Shell), conclua as seguintes etapas:
    • Prepare um computador local com sistema operacional semelhante ao Unix instalado (por exemplo, Ubuntu, macOS ou do Subsistema do Windows para Linux).
    • Instale uma implementação Java SE versão 17 ou posterior (por exemplo, compilação Microsoft do OpenJDK).
    • Instale o Maven 3.5.0 ou posterior.
    • Instale o cURL.

Conectando o MicroProfile Config ao Azure Key Vault

Vamos dar uma olhada rápida no poder de combinar o Cofre de Chaves do Azure e a API de Configuração do MicroProfile. Aqui está um trecho de código de um campo em uma classe que é anotado com @Inject e @ConfigProperty. O name especificado na anotação é o nome do segredo a ser pesquisado no Cofre de Chaves do Azure e o é usado se o defaultValue segredo não for descoberto. O valor secreto armazenado no Cofre de Chaves do Azure, ou o valor padrão se esse segredo não existir, é injetado automaticamente no campo em tempo de execução. Injetar valores de propriedade dessa forma proporciona inúmeros benefícios. Por exemplo, você não precisa mais passar valores em construtores e métodos setter, e a configuração é externalizada do código. Um dos benefícios mais poderosos é ter conjuntos separados de valores para ambientes de desenvolvimento, teste e prod.

@Inject
@ConfigProperty(name = "key-name", defaultValue = "Unknown")
String keyValue;

Também é possível acessar a configuração do MicroProfile imperativamente, conforme mostrado no exemplo a seguir:

public class DemoClass {
    @Inject
    Config config;

    public void method() {
        System.out.println("Hello: " + config.getValue("key-name", String.class));
    }
}

Este exemplo usa a implementação Open Liberty do MicroProfile. Para obter uma lista completa de implementações compatíveis, consulte Implementações compatíveis com MicroProfile. O exemplo também demonstra como conteinerizar e executar o aplicativo no Azure.

Este exemplo usa a extensão do Azure de baixo atrito para a biblioteca ConfigSource personalizada do MicroProfile Key Vault. Para obter mais informações sobre essa biblioteca, consulte a biblioteca README.

Aqui estão as etapas necessárias para executar esse código em seu computador local, começando com a criação de um recurso do Azure Key Vault.

Criamos um recurso do Azure Key Vault

Use a CLI do Azure para criar o recurso Cofre de Chaves do Azure e preenchê-lo com dois segredos.

Primeiro, entre no Azure e defina uma assinatura para ser a assinatura ativa atual.

az login
az account set --subscription <subscription-id>

Em seguida, crie um grupo de recursos com um nome exclusivo, por exemplo, mp-kv-rg-ejb010424.

export RESOURCE_GROUP_NAME=mp-kv-rg-ejb010424
az group create \
    --name ${RESOURCE_GROUP_NAME} \
    --location eastus

Agora, crie um recurso do Cofre de Chaves do Azure com um nome exclusivo (por exemplo, kvejb010424), adicione dois segredos e exporte o uri do Cofre de Chaves como uma variável de ambiente.

export KEY_VAULT_NAME=kv-ejb010424
az keyvault create \
    --resource-group "${RESOURCE_GROUP_NAME}" \
    --name "${KEY_VAULT_NAME}" \
    --location eastus

az keyvault secret set \
    --vault-name "${KEY_VAULT_NAME}" \
    --name secret \
    --value 1234
az keyvault secret set \
    --vault-name "${KEY_VAULT_NAME}" \
    --name anotherSecret \
    --value 5678

export AZURE_KEYVAULT_URL=$(az keyvault show \
    --resource-group "${RESOURCE_GROUP_NAME}" \
    --name "${KEY_VAULT_NAME}" \
    --query properties.vaultUri \
    --output tsv)
echo $AZURE_KEYVAULT_URL

A variável de AZURE_KEYVAULT_URL ambiente é necessária para configurar a biblioteca para trabalhar com o exemplo posteriormente. Mantenha o terminal aberto e use-o para executar o aplicativo localmente mais tarde.

É isso! Agora você tem o Cofre de Chaves em execução no Azure com dois segredos. Agora você pode clonar o repositório de exemplo e configurá-lo para usar esse recurso em seu aplicativo.

Colocá-lo em funcionamento localmente

Este exemplo é baseado em um aplicativo de exemplo disponível no GitHub. Alterne para o terminal aberto antes e execute os seguintes comandos para clonar o repositório e executar o aplicativo localmente:

git clone https://github.com/Azure/azure-microprofile.git
cd azure-microprofile
git checkout 20240116
cd integration-tests/open-liberty-sample
mvn package liberty:run

Se você vir uma mensagem sobre You are in 'detached HEAD' state, essa mensagem é segura para ignorar.

Observação

A biblioteca usa a credencial padrão do Azure para autenticar no Azure.

Como você autenticou uma conta por meio do comando da CLI az login do Azure localmente, DefaultAzureCredential autentica com essa conta para acessar o Cofre de Chaves do Azure.

Aguarde até ver uma saída semelhante a The defaultServer server is ready to run a smarter planet. Abra um novo terminal e execute os seguintes comandos para testar o exemplo:

# Get the value of secret "secret" stored in the Azure key vault. You should see 1234 in the response.
echo $(curl -s http://localhost:9080/config/value/secret -X GET)

# Get the value of secret "anotherSecret" stored in the Azure key vault. You should see 5678 in the response.
echo $(curl -s http://localhost:9080/config/value/anotherSecret -X GET)

# Get the names of secrets stored in the Azure key vault. You should see ["anotherSecret","secret"] in the response.
echo $(curl -s http://localhost:9080/config/propertyNames -X GET)

# Get the name-value paris of secrets stored in the Azure key vault. You should see {"anotherSecret":"5678","secret":"1234"} in the response.
echo $(curl -s http://localhost:9080/config/properties -X GET)

Você deve ver as saídas esperadas descritas nos comentários. Volte para o terminal onde o aplicativo está sendo executado. Pressione Ctrl + C para interromper o aplicativo.

Examinar o aplicativo de exemplo

Vamos obter uma compreensão mais profunda de como o MicroProfile Config funciona em geral e a biblioteca Custom ConfigSource do MicroProfile Key Vault funciona em particular.

Dependência da biblioteca

Inclua o MicroProfile Key Vault Custom ConfigSource em seu aplicativo com a seguinte dependência do Maven:

<dependency>
  <groupId>com.azure.microprofile</groupId>
  <artifactId>azure-microprofile-config-keyvault</artifactId>
</dependency>

Conectando-se ao Cofre de Chaves do Azure

A azure-microprofile-config-keyvault biblioteca conecta seu aplicativo ao Cofre de Chaves do Azure sem introduzir dependências diretas nas APIs do Azure. A biblioteca fornece uma implementação da interface ConfigSource da especificação MicroProfile Config que sabe como ler do Cofre de Chaves do Azure. O restante da implementação do MicroProfile Config é fornecido pelo tempo de execução do Open Liberty. Para obter um link para a especificação, consulte Próximas etapas.

A biblioteca define a propriedade de configuração para vincular seu aplicativo a azure.keyvault.url um cofre de chaves específico. A especificação MicroProfile Config define as "Regras de mapeamento de variáveis de ambiente" para como o valor de uma propriedade config, como azure.keyvault.url, é descoberto em tempo de execução. Uma dessas regras afirma que as propriedades são convertidas em variáveis de ambiente. A propriedade azure.keyvault.url faz com que a variável AZURE_KEYVAULT_URL de ambiente seja consultada.

Classes-chave no aplicativo de exemplo

Vamos examinar o recurso REST que os comandos cURL anteriores têm chamado. Esse recurso REST é definido na classe ConfigResource.java no integration-tests/open-liberty-sample projeto.

@Path("/config")
public class ConfigResource {

    @Inject
    private Config config;

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    @Path("/value/{name}")
    public String getConfigValue(@PathParam("name") String name) {
        return config.getConfigValue(name).getValue();
    }

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/propertyNames")
    public Set<String> getConfigPropertyNames() {
        ConfigSource configSource = getConfigSource(AzureKeyVaultConfigSource.class.getSimpleName());
        return configSource.getPropertyNames();
    }

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/properties")
    public Map<String, String> getConfigProperties() {
        ConfigSource configSource = getConfigSource(AzureKeyVaultConfigSource.class.getSimpleName());
        return configSource.getProperties();
    }

    private ConfigSource getConfigSource(String name) {
        return StreamSupport.stream(config.getConfigSources().spliterator(), false)
                .filter(source -> source.getName().equals(name))
                .findFirst()
                .orElseThrow(() -> new RuntimeException("ConfigSource not found: " + name));
    }
}

O getConfigValue() método usa a implementação injetada Config para procurar um valor das fontes de configuração do aplicativo. Todas as Config pesquisas de valor na implementação são encontradas por meio do algoritmo de pesquisa definido pela especificação MicroProfile Config. A azure-microprofile-config-keyvault biblioteca adiciona o Cofre de Chaves do Azure como uma fonte de configuração.

O getConfigSource() método evita o algoritmo de pesquisa e vai direto para as AzureKeyVaultConfigSource propriedades para resolver. Este método é usado pelo getConfigPropertyNames() e getConfigProperties() métodos.

Executar em Aplicativos de Contêiner do Azure

Nesta seção, você coloca o aplicativo em contêiner, configura uma identidade gerenciada atribuída pelo usuário para acessar o Cofre de Chaves do Azure e implanta o aplicativo em contêiner nos Aplicativos de Contêiner do Azure.

Volte para o terminal onde você executou o aplicativo localmente e use-o ao longo desta seção.

Configurar um Registro de Contêiner do Azure

Use o Registro de Contêiner do Azure para colocar o aplicativo em contêiner e armazenar a imagem do aplicativo.

Primeiro, crie um Registro de Contêiner do Azure com um nome exclusivo, por exemplo, acrejb010424.

export ACR_NAME=acrejb010424
az acr create \
    --resource-group $RESOURCE_GROUP_NAME \
    --name $ACR_NAME \
    --sku Basic \
    --admin-enabled

Aguarde alguns minutos após o retorno desse comando antes de continuar.

Conteinerizar o aplicativo

Em seguida, coloque o aplicativo em contêiner e envie a imagem do aplicativo para o Registro de Contêiner do Azure. Verifique se você está no caminho do aplicativo de exemplo, por exemplo, azure-microprofile/integration-tests/open-liberty-sample.

az acr build \
    --registry ${ACR_NAME} \
    --image open-liberty-mp-azure-keyvault:latest \
    .

Você deve ver a saída da compilação que conclui com uma mensagem semelhante ao Run ID: ca1 was successful after 1m28s. Se você não vir uma mensagem semelhante, solucione e resolva o problema antes de continuar.

Use os comandos a seguir para recuperar as informações de conexão necessárias para acessar a imagem ao implantar o aplicativo nos Aplicativos de Contêiner do Azure posteriormente.

export ACR_LOGIN_SERVER=$(az acr show \
    --name $ACR_NAME \
    --query 'loginServer' \
    --output tsv)
export ACR_USER_NAME=$(az acr credential show \
    --name $ACR_NAME \
    --query 'username' \
    --output tsv)
export ACR_PASSWORD=$(az acr credential show \
    --name $ACR_NAME \
    --query 'passwords[0].value' \
    --output tsv)

Configurar uma identidade gerenciada atribuída pelo usuário

Como dito anteriormente, a biblioteca usa a credencial padrão do Azure para autenticar no Azure. Ao implantar o aplicativo nos Aplicativos de Contêiner do Azure, você define a variável AZURE_CLIENT_ID de ambiente para configurar DefaultAzureCredential para autenticar como uma identidade gerenciada definida pelo usuário, que tem permissões para acessar o Cofre de Chaves do Azure e é atribuída aos Aplicativos de Contêiner do Azure posteriormente.

Primeiro, use os comandos a seguir para criar uma identidade gerenciada atribuída pelo usuário com um nome exclusivo, por exemplo, uamiejb010424. Para obter mais informações, acesse Criar uma identidade gerenciada atribuída pelo usuário.

export USER_ASSIGNED_IDENTITY_NAME=uamiejb010424
az identity create \
    --resource-group ${RESOURCE_GROUP_NAME} \
    --name ${USER_ASSIGNED_IDENTITY_NAME}

Em seguida, use os comandos a seguir para conceder a ele permissões para obter e listar segredos do Cofre de Chaves do Azure. Para obter mais informações, consulte Atribuir a política de acesso.

export USER_ASSIGNED_IDENTITY_OBJECT_ID="$(az identity show \
    --resource-group "${RESOURCE_GROUP_NAME}" \
    --name "${USER_ASSIGNED_IDENTITY_NAME}" \
    --query 'principalId' \
    --output tsv)"

az keyvault set-policy --name "${KEY_VAULT_NAME}" \
    --resource-group "${RESOURCE_GROUP_NAME}" \
    --secret-permissions get list \
    --object-id "${USER_ASSIGNED_IDENTITY_OBJECT_ID}"

A saída deve conter o seguinte JSON para ser considerada bem-sucedida:

"permissions": {
  "certificates": null,
  "keys": null,
  "secrets": [
    "list",
    "get"
  ],
  "storage": null
}

Se a saída não contiver esse JSON, solucione e resolva o problema antes de continuar.

Em seguida, use os seguintes comandos para recuperar a ID e a ID do cliente da identidade gerenciada atribuída pelo usuário para que você possa atribuí-la aos Aplicativos de Contêiner do Azure posteriormente para acessar o Cofre de Chaves do Azure:

export USER_ASSIGNED_IDENTITY_ID="$(az identity show \
    --resource-group "${RESOURCE_GROUP_NAME}" \
    --name "${USER_ASSIGNED_IDENTITY_NAME}" \
    --query 'id' \
    --output tsv)"
export USER_ASSIGNED_IDENTITY_CLIENT_ID="$(az identity show \
    --name "${USER_ASSIGNED_IDENTITY_NAME}" \
    --resource-group "${RESOURCE_GROUP_NAME}" \
    --query 'clientId' \
    --output tsv)"
echo $USER_ASSIGNED_IDENTITY_ID
echo $USER_ASSIGNED_IDENTITY_CLIENT_ID

Implantar o aplicativo nos Aplicativos de Contêiner do Azure

Você colocou o aplicativo em contêiner e configurou uma identidade gerenciada atribuída pelo usuário para acessar o Cofre de Chaves do Azure. Agora você pode implantar o aplicativo em contêiner nos Aplicativos de Contêiner do Azure.

Primeiro, crie um ambiente para os Aplicativos de Contêiner do Azure. Um ambiente em aplicativos de contêiner do Azure cria um marco de delimitação seguro em um grupo de aplicativos de contêiner. Os Aplicativos de Contêiner implantados no mesmo ambiente são implantados na mesma rede virtual e gravam logs no mesmo workspace do Log Analytics. Use o comando az containerapp env create para criar um ambiente com um nome exclusivo (por exemplo, acaenvejb010424), conforme mostrado no exemplo a seguir:

export ACA_ENV=acaenvejb010424
az containerapp env create \
    --resource-group $RESOURCE_GROUP_NAME \
    --location eastus \
    --name $ACA_ENV

Em seguida, use o comando az containerapp create para criar uma instância de Aplicativos de Contêiner com um nome exclusivo (por exemplo, acaappejb010424) para executar o aplicativo depois de extrair a imagem do Registro de Contêiner, conforme mostrado no exemplo a seguir:

export ACA_NAME=acaappejb010424
az containerapp create \
    --resource-group ${RESOURCE_GROUP_NAME} \
    --name ${ACA_NAME} \
    --environment ${ACA_ENV} \
    --image ${ACR_LOGIN_SERVER}/open-liberty-mp-azure-keyvault:latest  \
    --registry-server $ACR_LOGIN_SERVER \
    --registry-username $ACR_USER_NAME \
    --registry-password $ACR_PASSWORD \
    --user-assigned ${USER_ASSIGNED_IDENTITY_ID} \
    --env-vars \
        AZURE_CLIENT_ID=${USER_ASSIGNED_IDENTITY_CLIENT_ID} \
        AZURE_KEYVAULT_URL=${AZURE_KEYVAULT_URL} \
    --target-port 9080 \
    --ingress 'external'

Observação

Você atribui a identidade gerenciada atribuída pelo usuário à instância de Aplicativos de Contêiner com o parâmetro --user-assigned ${USER_ASSIGNED_IDENTITY_ID}.

A instância de Aplicativos de Contêiner pode acessar o Cofre de Chaves do Azure com duas variáveis de ambiente fornecidas nos parâmetros --env-vars AZURE_CLIENT_ID=${USER_ASSIGNED_IDENTITY_CLIENT_ID} AZURE_KEYVAULT_URL=${AZURE_KEYVAULT_URL}. Lembre-se, a AZURE_KEYVAULT_URL variável de ambiente é consultada devido às Regras de Mapeamento de Variáveis de Ambiente definidas pela especificação MicroProfile Config.

Em seguida, recupere uma URL totalmente qualificada para acessar o aplicativo usando o seguinte comando:

export APP_URL=https://$(az containerapp show \
    --resource-group ${RESOURCE_GROUP_NAME} \
    --name ${ACA_NAME} \
    --query properties.configuration.ingress.fqdn \
    --output tsv)

Finalmente, execute os seguintes comandos novamente para testar o exemplo em execução na instância de Aplicativos de Contêiner:

# Get the value of secret "secret" stored in the Azure key vault. You should see 1234 in the response.
echo $(curl -s ${APP_URL}/config/value/secret -X GET)

# Get the value of secret "anotherSecret" stored in the Azure key vault. You should see 5678 in the response.
echo $(curl -s  ${APP_URL}/config/value/anotherSecret -X GET)

# Get the names of secrets stored in the Azure key vault. You should see ["anotherSecret","secret"] in the response.
echo $(curl -s  ${APP_URL}/config/propertyNames -X GET)

# Get the name-value paris of secrets stored in the Azure key vault. You should see {"anotherSecret":"5678","secret":"1234"} in the response.
echo $(curl -s  ${APP_URL}/config/properties -X GET)

Você deve ver as saídas esperadas descritas nos comentários. Se você não vê-los, o aplicativo ainda pode estar iniciando. Aguarde um pouco e tente novamente.

Limpar os recursos

Para evitar cobranças do Azure, limpe recursos desnecessários. Quando os recursos não forem mais necessários, execute os seguintes comandos para limpá-los.

az keyvault delete \
    --resource-group "${RESOURCE_GROUP_NAME}" \
    --name "${KEY_VAULT_NAME}"

az keyvault purge \
    --name "${KEY_VAULT_NAME}" \
    --no-wait

az group delete \
    --name ${RESOURCE_GROUP_NAME} \
    --yes \
    --no-wait

Próximas etapas

Você pode aprender mais com as seguintes referências: