Assuming you already have an Event Hubs namespace and an Event Hub in it, let's create a Service Principal and associate the Event Hub Send and Receive role to access the Event Hubs namespace.
We'll then use the Service Principal in Java code to authenticate and send events to the Event Hub.
az ad sp create-for-rbac -n eh-service-principal --skip-assignment
{
"appId": "[AZURE_CLIENT_ID]",
"displayName": "eh-service-principal",
"password": "[AZURE_CLIENT_SECRET]",
"tenant": "[AZURE_TENANT_ID]"
}
export RESOURCE_GROUP=anutc-rg
export EVENTHUBS_NAMESPACE=anutc-eh
EVENTHUBS_ID=$(az eventhubs namespace show --resource-group $RESOURCE_GROUP --name $EVENTHUBS_NAMESPACE -o tsv --query 'id')
echo $EVENTHUBS_ID
EH_SENDER_ROLE_ID=$(az role definition list -n "Azure Event Hubs Data Sender" -o tsv --query '[0].id')
echo $EH_SENDER_ROLE_ID
EH_RCEIVER_ROLE_ID=$(az role definition list -n "Azure Event Hubs Data Receiver" -o tsv --query '[0].id')
echo $EH_RCEIVER_ROLE_ID
az role assignment create --assignee $AZURE_CLIENT_ID --role $EH_SENDER_ROLE_ID --scope $EVENTHUBS_ID
az role assignment create --assignee $AZURE_CLIENT_ID --role $EH_RCEIVER_ROLE_ID --scope $EVENTHUBS_ID
We'll test that the Service Principal can obtain the token.
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-identity</artifactId>
<version>1.7.0-beta.3</version>
</dependency>
import com.azure.core.credential.AccessToken;
import com.azure.core.credential.TokenRequestContext;
import com.azure.identity.ClientSecretCredential;
import com.azure.identity.ClientSecretCredentialBuilder;
ClientSecretCredential credential = new ClientSecretCredentialBuilder()
.clientId("[AZURE_CLIENT_ID]")
.clientSecret("[AZURE_CLIENT_SECRET]")
.tenantId("[AZURE_TENANT_ID]")
.build();
AccessToken token = credential.getTokenSync(new TokenRequestContext().addScopes("https://eventhubs.azure.net/.default"));
System.out.println("Token:" + token.getToken());
Code uses the "CustomEndpointAddress" feature of Event Hubs SDK to communicate to EH behind an Application Gateway with AMQP_WEB_SOCKET transport.
(If no AppGateway is configured, simply remove the "customEndpointAddress(..)" setter in the code below)
(Refer https://gist.github.com/anuchandy/40c67c64f371f38f5ce5de4cd3a52dc5 for details on how to set up the AppGateway to route traffic to Event Hubs)
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-identity</artifactId>
<version>1.7.0-beta.3</version>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-messaging-eventhubs-checkpointstore-blob</artifactId>
<version>1.16.0-beta.1</version>
</dependency>
public static void main(String[] args) throws Exception {
List<EventData> telemetryEvents = Arrays.asList(
new EventData("Roast beef".getBytes(UTF_8)),
new EventData("Cheese".getBytes(UTF_8)),
new EventData("Tofu".getBytes(UTF_8)),
new EventData("Turkey".getBytes(UTF_8)));
ClientSecretCredential credential = new ClientSecretCredentialBuilder()
.clientId("[AZURE_CLIENT_ID]")
.clientSecret("[AZURE_CLIENT_SECRET]")
.tenantId("[AZURE_TENANT_ID]")
.build();
EventHubProducerClient producer = new EventHubClientBuilder()
.credential("<eventhubs-namespace>.servicebus.windows.net", "first", credential)
.transportType(AmqpTransportType.AMQP_WEB_SOCKETS)
.customEndpointAddress("https://<public-ip-of-app-gateway>") // e.g. "https://20.232.196.115"
.buildProducerClient();
EventDataBatch currentBatch = producer.createBatch();
for (EventData event : telemetryEvents) {
if (currentBatch.tryAdd(event)) {
continue;
}
producer.send(currentBatch);
currentBatch = producer.createBatch();
if (!currentBatch.tryAdd(event)) {
System.err.printf("Event is too large for an empty batch. Skipping. Max size: %s. Event: %s%n",
currentBatch.getMaxSizeInBytes(), event.getBodyAsString());
}
}
producer.send(currentBatch);
System.out.println("Done Sending!");
}
I've referenced this awesome blog for service principal part https://dzone.com/articles/azure-event-hubs-quotrole-based-access-controlquot