Настройка MicroProfile для использования с Azure Key Vault

В этом руководстве показано, как настроить приложение MicroProfile для получения секретов из Azure Key Vault с помощью API конфигурации MicroProfile. Разработчики получают преимущества от открытого стандартного API конфигурации MicroProfile для получения и внедрения данных конфигурации в микрослужбы.

Необходимые компоненты

  • Подписка Azure. Если у вас ее еще нет, вы можете активировать преимущества для подписчиков MSDN или зарегистрироваться для получения бесплатной учетной записи.
  • Azure CLI для сред, таких как Unix. В этой статье требуется только вариант Azure CLI Bash.
    • Установите Azure CLI и войдите в интерактивном режиме с помощью команды az login , чтобы войти в Azure перед использованием DefaultAzureCredential в коде.
      az login
      
    • Для этой статьи требуется по крайней мере версия 2.55.0 Azure CLI. Если вы используете Azure Cloud Shell, последняя версия уже установлена.
  • Azure Cloud Shell имеет все эти предварительные требования. Дополнительные сведения см . в кратком руководстве по Azure Cloud Shell.
  • Если вы выполняете команды в этом руководстве локально (вместо использования Azure Cloud Shell), выполните следующие действия:
    • Подготовьте локальный компьютер с установленной операционной системой Unix (например, Ubuntu, macOS или подсистема Windows для Linux).
    • Установите реализацию Java SE версии 17 или более поздней (например, сборку Microsoft OpenJDK).
    • Установите Maven 3.5.0 или более поздней версии.
    • Установите cURL.

Подключение конфигурации MicroProfile в Azure Key Vault

Давайте рассмотрим возможности объединения Azure Key Vault и API конфигурации MicroProfile. Ниже приведен фрагмент кода поля в классе, который заметен с @Inject и @ConfigProperty. Указанное name в заметке имя секрета для поиска в Azure Key Vault и defaultValue используется, если секрет не обнаружен. Значение секрета, хранящееся в Azure Key Vault, или значение по умолчанию, если такой секрет не существует, автоматически внедряется в поле во время выполнения. Внедрение значений свойств таким образом обеспечивает многочисленные преимущества. Например, больше не нужно передавать значения в конструкторах и методах задания, а конфигурация является внешней из кода. Одним из самых мощных преимуществ является наличие отдельных наборов значений для сред разработки, тестирования и разработки.

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

Также можно получить доступ к конфигурации MicroProfile императивно, как показано в следующем примере:

public class DemoClass {
    @Inject
    Config config;

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

В этом примере используется реализация MicroProfile Open Liberty. Полный список совместимых реализаций см. в разделе "Реализация совместимости MicroProfile". В примере также показано, как контейнеризировать и запустить приложение в Azure.

В этом примере используется расширение Azure с низким уровнем трения для библиотеки MicroProfile Key Vault Custom ConfigSource. Дополнительные сведения об этой библиотеке см . в библиотеке README.

Ниже описаны действия, необходимые для запуска этого кода на вашем локальном компьютере, начиная с создания ресурса Azure Key Vault.

Создание ресурса Azure Key Vault

Вы используете Azure CLI для создания ресурса Azure Key Vault и заполнения его двумя секретами.

Сначала войдите в Azure и задайте подписку для текущей активной подписки.

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

Затем создайте группу ресурсов с уникальным именем, например mp-kv-rg-ejb010424.

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

Теперь создайте ресурс Azure Key Vault с уникальным именем (например, kvejb010424), добавьте два секрета и экспортируйте URI Key Vault в качестве переменной среды.

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

Переменная AZURE_KEYVAULT_URL среды необходима для настройки библиотеки для работы с примером позже. Откройте терминал и используйте его для локального запуска приложения.

Вот и все! Теперь у вас есть Key Vault, работающий в Azure с двумя секретами. Теперь вы можете клонировать пример репозитория и настроить его для использования этого ресурса в приложении.

Настройка и запуск на локальном компьютере

Этот пример основан на примере приложения, доступного на сайте GitHub. Перейдите в терминал, который вы открыли перед и выполните следующие команды, чтобы клонировать репозиторий и запустить приложение локально:

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

Если вы видите сообщение о You are in 'detached HEAD' stateтом, это сообщение безопасно игнорировать.

Примечание.

Библиотека использует учетные данные Azure по умолчанию для проверки подлинности в Azure.

Так как вы выполнили проверку подлинности учетной записи с помощью команды Azure CLI az login локально, DefaultAzureCredential выполняет проверку подлинности с помощью этой учетной записи для доступа к Azure Key Vault.

Подождите, пока не увидите выходные данные, аналогичные The defaultServer server is ready to run a smarter planet. Откройте новый терминал и выполните следующие команды, чтобы протестировать пример:

# 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)

Ожидаемые выходные данные, описанные в комментариях. Вернитесь к терминалу, в котором работает приложение. Нажмите клавиши CTRL + C, чтобы остановить приложение.

Проверка примера приложения

Давайте получим более глубокое представление о том, как работает Конфигурация MicroProfile в целом, и библиотека Custom ConfigSource Для MicroProfile Key Vault.

Зависимость библиотеки

Включите MicroProfile Key Vault Custom ConfigSource в приложение со следующими зависимостями Maven:

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

Подключение в Azure Key Vault

Библиотека azure-microprofile-config-keyvault подключает приложение к Azure Key Vault без ввода прямых зависимостей в API Azure. Библиотека предоставляет реализацию интерфейса Config спецификации MicroProfile Config , который знает, как читать из Azure Key Vault. Оставшаяся часть реализации MicroProfile Config предоставляется средой выполнения Open Liberty. Ссылку на спецификацию см. в следующих шагах.

Библиотека определяет azure.keyvault.url свойство конфигурации для привязки приложения к определенному хранилищу ключей. Спецификация Конфигурации MicroProfile определяет правила сопоставления переменных среды для определения значения свойства конфигурации, например azure.keyvault.urlобнаружения во время выполнения. Одно из этих правил указывает, что свойства преобразуются в переменные среды. Свойство azure.keyvault.url приводит к тому, что переменная AZURE_KEYVAULT_URL среды будет обращаться к ней.

Ключевые классы в примере приложения

Давайте рассмотрим ресурс REST, который вызывает предыдущие команды cURL. Этот ресурс REST определяется в классе ConfigResource.java в integration-tests/open-liberty-sample проекте.

@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));
    }
}

Метод getConfigValue() использует внедренную Config реализацию для поиска значения из источников конфигурации приложения. Все подстановки значений реализации Config обнаруживаются с помощью алгоритма поиска, определенного спецификацией MicroProfile Config. Библиотека azure-microprofile-config-keyvault добавляет Azure Key Vault в качестве источника конфигурации.

Метод getConfigSource() избегает алгоритма поиска и переходит прямо к AzureKeyVaultConfigSource свойствам. Этот метод используется методом и getConfigProperties() методамиgetConfigPropertyNames().

Запуск в приложениях контейнеров Azure

В этом разделе описана контейнеризация приложения, настройка управляемого удостоверения, назначаемого пользователем, для доступа к Azure Key Vault и развертывание контейнерного приложения в приложениях контейнеров Azure.

Вернитесь к терминалу, где вы запустили приложение локально, и используйте его в этом разделе.

Настройка Реестр контейнеров Azure

Вы используете Реестр контейнеров Azure для контейнеризации приложения и хранения образа приложения.

Сначала создайте Реестр контейнеров Azure с уникальным именем, например acrejb010424.

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

Подождите несколько минут после возврата этой команды, прежде чем продолжить.

Контейнеризация приложения

Затем контейнеризируйте приложение и отправьте образ приложения в Реестр контейнеров Azure. Убедитесь, что вы находитесь на пути примера приложения, например azure-microprofile/integration-test/open-liberty-sample.

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

Вы увидите выходные данные сборки, завершающиеся сообщением, похожим на Run ID: ca1 was successful after 1m28s. Если вы не видите аналогичное сообщение, устраните и устраните проблему, прежде чем продолжить.

Используйте следующие команды, чтобы получить сведения о подключении, необходимые для доступа к изображению при развертывании приложения в приложениях контейнеров Azure позже.

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)

Настройка управляемого удостоверения, назначаемого пользователем

Как упоминалось ранее, библиотека использует учетные данные Azure по умолчанию для проверки подлинности в Azure. При развертывании приложения в приложениях контейнеров Azure задайте переменную AZURE_CLIENT_ID среды, чтобы настроить DefaultAzureCredential для проверки подлинности в качестве определяемого пользователем управляемого удостоверения, которое имеет разрешения на доступ к Azure Key Vault и назначается приложениям контейнеров Azure позже.

Сначала используйте следующие команды, чтобы создать управляемое удостоверение, назначаемое пользователем, с уникальным именем, например uamiejb010424. Дополнительные сведения см. в статье "Создание управляемого удостоверения, назначаемого пользователем".

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

Затем используйте следующие команды, чтобы предоставить ему разрешения на получение и перечисление секретов из Azure Key Vault. Дополнительные сведения см. в разделе "Назначение политики доступа".

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}"

Выходные данные должны содержать следующий код JSON, чтобы считаться успешным:

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

Если выходные данные не содержат этот JSON, устраните проблему и устраните ее перед продолжением.

Затем используйте следующие команды, чтобы получить идентификатор и идентификатор клиента управляемого удостоверения, назначаемого пользователем, чтобы его можно было назначить приложениям контейнеров Azure позже для доступа к Azure Key Vault:

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

Развертывание приложения в приложениях контейнеров Azure

Вы контейнеризировали приложение и настроили управляемое удостоверение, назначаемое пользователем, для доступа к Azure Key Vault. Теперь вы можете развернуть контейнерное приложение в приложениях контейнеров Azure.

Сначала создайте среду для приложений контейнеров Azure. Среда в Azure Container Apps создает безопасную границу вокруг группы приложений-контейнеров. Развертываемые в одной среде приложения-контейнеры развертываются в одной виртуальной сети и записывают журналы в одну рабочую область Log Analytics. Используйте команду az containerapp env create для создания среды с уникальным именем (например, acaenvejb010424), как показано в следующем примере:

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

Затем используйте команду az containerapp create для создания экземпляра container Apps с уникальным именем (например, acaappejb010424) для запуска приложения после извлечения образа из реестра контейнеров, как показано в следующем примере:

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'

Примечание.

Управляемое удостоверение, назначаемое пользователем, назначается экземпляру контейнерных приложений с параметром --user-assigned ${USER_ASSIGNED_IDENTITY_ID}.

Экземпляр контейнеров приложений может получить доступ к Azure Key Vault с двумя переменными среды, предоставленными в параметрах --env-vars AZURE_CLIENT_ID=${USER_ASSIGNED_IDENTITY_CLIENT_ID} AZURE_KEYVAULT_URL=${AZURE_KEYVAULT_URL}. Помните, что переменная среды обращается к правилам сопоставления переменных среды, AZURE_KEYVAULT_URL определенным спецификацией MicroProfile Config.

Затем получите полный URL-адрес для доступа к приложению с помощью следующей команды:

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

Наконец, выполните следующие команды еще раз, чтобы проверить пример, запущенный в экземпляре приложений контейнеров:

# 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)

Ожидаемые выходные данные, описанные в комментариях. Если вы не видите их, приложение может по-прежнему запускаться. Подождите некоторое время и повторите попытку.

Очистка ресурсов

Чтобы избежать расходов за использование Azure, необходимо удалить ненужные ресурсы. Если ресурсы больше не нужны, выполните следующие команды, чтобы очистить ресурсы.

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

Следующие шаги

Дополнительные сведения см. в следующих ссылках: