Skip to content

Commit

Permalink
fixes apache#6660: azure-key-vault refresh context coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
JiriOndrusek committed Feb 5, 2025
1 parent 46df87e commit 0284fe1
Show file tree
Hide file tree
Showing 8 changed files with 336 additions and 44 deletions.
1 change: 1 addition & 0 deletions integration-test-groups/azure/README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ or skipped, if the given service is not supported by Azurite.
Unsupported by Azurite:

* `azure-eventhubs`
* `azure-key-vault`

=== Real Azure API

Expand Down
64 changes: 64 additions & 0 deletions integration-test-groups/azure/azure-key-vault/README.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
== Azure key vault isolated integration tests

=== Real Azure API

Prerequisites:

* A https://docs.microsoft.com/en-us/azure/storage/common/storage-account-create?toc=%2Fazure%2Fstorage%2Fblobs%2Ftoc.json&tabs=azure-portal[general-purpose v2 Azure storage account] and
https://docs.microsoft.com/en-us/azure/storage/blobs/storage-quickstart-blobs-portal[create a container]
* The https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-change-feed?tabs=azure-portal#enable-and-disable-the-change-feed[change feed] is enabled on your storage account
* View the https://docs.microsoft.com/en-us/azure/storage/common/storage-account-keys-manage?tabs=azure-portal#view-account-access-keys[account keys] and set the following environment variables
* An https://docs.microsoft.com/en-us/azure/event-hubs/event-hubs-create[Azure Event Hub]
* An https://docs.microsoft.com/en-us/azure/event-hubs/event-hubs-get-connection-string[Event Hubs connection string]
* A https://learn.microsoft.com/en-us/azure/key-vault/general/overview[Key Vault] configured in your Azure account

To add resources required for key-vault tests, you can use `key-vault-resources.sh` script as follows. Ensure that you have installed (and logged in) the https://docs.microsoft.com/en-us/cli/azure/[Azure CLI] beforehand.
The script prerequisites are permissions, resource group and event hub namespace.
If you need such resources created as well, please follow instructions from the parent module.

[source,shell]
----
$ ./key-vault-resources.sh create
----

The script outputs a set of export commands that you may want to paste to your shell.

Here are the environment variables you need to set:

[source,shell]
----
export RESOURCE_GROUP=<existing-resource-group>
export ZONE=<your-zone>
export EH_NAMESPACE=<existing event hub namespace>
export AZURE_STORAGE_ACCOUNT_NAME=<existing event hub storage account name>
----

To clean up, run

[source,shell]
----
$ ./key-vault-resources.sh delete
----

=== What is created by the script

* eventhub used for testing context reload
* storage container required for storing position of eventhub consumer

Following properties are generated by the script and are required for the test execution:
[source,shell]
----
export AZURE_EVENT_HUBS_BLOB_CONTAINER_NAME=<container for storing position of eventhub consumer>
export AZURE_VAULT_EVENT_HUBS_CONNECTION_STRING=<connection string for eventhub>
export AZURE_STORAGE_ACCOUNT_KEY=<storage account key required for context refresh configuration>
----

Following properties have to be set manually before test execution

[source,shell]
----
export AZURE_CLIENT_ID=<your-azure-app-client-id>
export AZURE_CLIENT_SECRET=<your-azure-app-client-secret>
export AZURE_TENANT_ID=<your-azure-app-tenant-id>
export AZURE_VAULT_NAME=<your-azure-key-vault-name>
----
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#!/bin/bash
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

#script to create/delete all resources required for key-vault refresh test.
#In comparison with ../azure-resources/sh, the script is not creating any permissions, resource groups, ...
#Following properties has to be se upon running the script
#export RESOURCE_GROUP=<existing-resource-group>
#export ZONE=<your-zone>
#export EH_NAMESPACE=<existing event hub namespace>
#export AZURE_STORAGE_ACCOUNT_NAME=<existing event hub storage account name>

if ! which az > /dev/null 2>&1; then
echo "$(basename $0) requires the Azure CLI."
echo
echo "https://docs.microsoft.com/en-us/cli/azure/"
echo
exit 1
fi

suffix="$(az ad signed-in-user show --query displayName -o tsv | tr '[:upper:]' '[:lower:]' | tr -cd '[:alnum:]' | cut -c-12)"
suffix="${suffix}4"

export AZURE_VAULT_REFRESH_EH_NAME=camel-quarkus-secret-refresh-hub-${suffix}
export AZURE_BLOB_CONTAINER_NAME=cq-container-${suffix}

function createResources() {
set -e
set -x
AZURE_EVENT_HUBS_CONNECTION_STRING=$(az eventhubs namespace authorization-rule keys list --resource-group ${RESOURCE_GROUP} --namespace-name ${EH_NAMESPACE} --name RootManageSharedAccessKey --query primaryConnectionString -o tsv)

az storage container create --account-name ${AZURE_STORAGE_ACCOUNT_NAME} --name ${AZURE_BLOB_CONTAINER_NAME} --auth-mode login

AZURE_STORAGE_ACCOUNT_KEY=$(az storage account keys list --account-name ${AZURE_STORAGE_ACCOUNT_NAME} --query '[0].value' -o tsv)

az eventhubs eventhub create --name ${AZURE_VAULT_REFRESH_EH_NAME} --resource-group ${RESOURCE_GROUP} --namespace-name ${EH_NAMESPACE} --cleanup-policy Delete --partition-count 1 --retention-time 1

set +x
echo "Add the following to your environment:"
echo 'export AZURE_VAULT_EVENT_HUBS_BLOB_CONTAINER_NAME="'${AZURE_BLOB_CONTAINER_NAME}'"'
echo 'export AZURE_VAULT_EVENT_HUBS_CONNECTION_STRING="'$AZURE_EVENT_HUBS_CONNECTION_STRING';EntityPath='${AZURE_VAULT_REFRESH_EH_NAME}'"'
echo 'export AZURE_STORAGE_ACCOUNT_KEY="'${AZURE_STORAGE_ACCOUNT_KEY}'"'
}


function deleteResources() {
set -x
set +e

az storage container delete --account-name ${AZURE_STORAGE_ACCOUNT_NAME} --name ${AZURE_BLOB_CONTAINER_NAME} --auth-mode login

az eventhubs eventhub delete --name ${AZURE_VAULT_REFRESH_EH_NAME} --resource-group ${RESOURCE_GROUP} --namespace-name ${EH_NAMESPACE}
}

case "$1" in
create) echo "Creating Azure resources"
createResources
;;
delete) echo "Deleting Azure resources"
deleteResources
;;
*) echo "usage: $0 [create|delete]"
;;
esac
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@
*/
package org.apache.camel.quarkus.component.azure.key.vault.it;

import java.util.concurrent.atomic.AtomicBoolean;

import com.azure.security.keyvault.secrets.models.KeyVaultSecret;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.Observes;
import jakarta.inject.Inject;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
Expand All @@ -30,13 +33,20 @@
import jakarta.ws.rs.core.Response;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.component.azure.key.vault.KeyVaultConstants;
import org.apache.camel.impl.event.CamelContextReloadedEvent;

@Path("/azure-key-vault")
@ApplicationScoped
public class AzureKeyVaultResource {
@Inject
ProducerTemplate producerTemplate;

static final AtomicBoolean contextReloaded = new AtomicBoolean(false);

void onReload(@Observes CamelContextReloadedEvent event) {
contextReloaded.set(true);
}

@Path("/secret/{secretName}")
@POST
@Consumes(MediaType.TEXT_PLAIN)
Expand Down Expand Up @@ -76,4 +86,11 @@ public Response purgeSecret(@PathParam("secretName") String secretName) {
public String getSecretFromPropertyPlaceholder() {
return producerTemplate.requestBody("direct:propertyPlaceholder", null, String.class);
}

@Path("/context/reload")
@GET
@Produces(MediaType.TEXT_PLAIN)
public boolean contextReloadStatus() {
return contextReloaded.get();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,43 +16,43 @@
*/
package org.apache.camel.quarkus.component.azure.key.vault.it;

import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.apache.camel.Processor;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.spi.PropertiesComponent;

public class AzureKeyVaultRoutes extends RouteBuilder {
@Override
public void configure() throws Exception {
from("direct:createSecret")
.to(azureKeyVault("createSecret"));
.to(azureKeyVault("createSecret", true));

from("direct:getSecret")
.to(azureKeyVault("getSecret"));
.to(azureKeyVault("getSecret", false));

from("direct:deleteSecret")
.to(azureKeyVault("deleteSecret"));
.to(azureKeyVault("deleteSecret", true));

from("direct:purgeDeletedSecret")
.to(azureKeyVault("purgeDeletedSecret"));
.to(azureKeyVault("purgeDeletedSecret", false));

from("direct:propertyPlaceholder")
.process(new Processor() {
@Override
public void process(Exchange exchange) throws Exception {
Message message = exchange.getMessage();
PropertiesComponent component = exchange.getContext().getPropertiesComponent();
component.resolveProperty("azure:camel-quarkus-secret").ifPresent(message::setBody);
}
.process(exchange -> {
Message message = exchange.getMessage();
PropertiesComponent component = exchange.getContext().getPropertiesComponent();
component.resolveProperty("azure:camel-quarkus-secret").ifPresent(message::setBody);
});
}

private String azureKeyVault(String operation) {
return "azure-key-vault://{{camel.vault.azure.vaultName}}" +
private String azureKeyVault(String operation, boolean useIdentity) {
StringBuilder sb = new StringBuilder("azure-key-vault://{{camel.vault.azure.vaultName}}" +
"?clientId=RAW({{camel.vault.azure.clientId}})" +
"&clientSecret=RAW({{camel.vault.azure.clientSecret}})" +
"&tenantId=RAW({{camel.vault.azure.tenantId}})" +
"&operation=" + operation;
"&operation=" + operation);

if (useIdentity) {
sb.append("&credentialType=AZURE_IDENTITY");
}
return sb.toString();
}
}
Loading

0 comments on commit 0284fe1

Please sign in to comment.