Tutorial: Connect to a MySQL Database from Java JBoss EAP App Service with passwordless connection

Azure App Service provides a highly scalable, self-patching web hosting service in Azure. It also provides a managed identity for your app, which is a turn-key solution for securing access to Azure Database for MySQL and other Azure services. Managed identities in App Service make your app more secure by eliminating secrets from your app, such as credentials in the environment variables.

In this tutorial, you learn how to:

  • Create a MySQL database.
  • Deploy a sample JBoss EAP app to Azure App Service using a WAR package.
  • Configure a Spring Boot web application to use Microsoft Entra authentication with MySQL Database.
  • Connect to MySQL Database with Managed Identity using Service Connector.

If you don't have an Azure subscription, create an Azure free account before you begin.

Prerequisites

Clone the sample app and prepare the repo

Run the following commands in your terminal to clone the sample repo and set up the sample app environment.

git clone https://github.com/Azure-Samples/Passwordless-Connections-for-Java-Apps
cd Passwordless-Connections-for-Java-Apps/JakartaEE/jboss-eap/

Create an Azure Database for MySQL

Follow these steps to create an Azure Database for MySQL resource in your subscription. The Spring Boot app connects to this database and store its data when running, persisting the application state no matter where you run the application.

  1. Sign into the Azure CLI, and optionally set your subscription if you have more than one connected to your login credentials.

    az login
    az account set --subscription <subscription-ID>
    
  2. Create an Azure resource group.

    export RESOURCE_GROUP=<resource-group-name>
    export LOCATION=eastus
    
    az group create --name $RESOURCE_GROUP --location $LOCATION
    
  3. Create an Azure Database for MySQL server. The server is created with an administrator account, but it isn't used because we're going to use the Microsoft Entra admin account to perform administrative tasks.

    export MYSQL_ADMIN_USER=azureuser
    
    # MySQL admin access rights won't be used because Azure AD authentication is leveraged to administer the database.
    export MYSQL_ADMIN_PASSWORD=<admin-password>
    export MYSQL_HOST=<mysql-host-name>
    
    # Create a MySQL server.
    az mysql flexible-server create \
        --name $MYSQL_HOST \
        --resource-group $RESOURCE_GROUP \
        --location $LOCATION \
        --admin-user $MYSQL_ADMIN_USER \
        --admin-password $MYSQL_ADMIN_PASSWORD \
        --public-access 0.0.0.0 \
        --tier Burstable \
        --sku-name Standard_B1ms \
        --storage-size 32
    
  4. Create a database for the application.

    export DATABASE_NAME=checklist
    
    az mysql flexible-server db create \
        --resource-group $RESOURCE_GROUP \
        --server-name $MYSQL_HOST \
        --database-name $DATABASE_NAME
    

Create an App Service

Create an Azure App Service resource on Linux. JBoss EAP requires Premium SKU.

export APPSERVICE_PLAN=<app-service-plan>
export APPSERVICE_NAME=<app-service-name>

# Create an App Service plan
az appservice plan create \
    --resource-group $RESOURCE_GROUP \
    --name $APPSERVICE_PLAN \
    --location $LOCATION \
    --sku P1V3 \
    --is-linux

# Create an App Service resource.
az webapp create \
    --resource-group $RESOURCE_GROUP \
    --name $APPSERVICE_NAME \
    --plan $APPSERVICE_PLAN \
    --runtime "JBOSSEAP:7-java8"

Connect the MySQL database with identity connectivity

Next, connect the database using Service Connector.

  1. Install the Service Connector passwordless extension for the Azure CLI:

    az extension add --name serviceconnector-passwordless --upgrade
    
  2. Create a user-assigned managed identity for Microsoft Entra authentication using the following command. For more information, see Set up Microsoft Entra authentication for Azure Database for MySQL - Flexible Server.

    export USER_IDENTITY_NAME=<your-user-assigned-managed-identity-name>
    export IDENTITY_RESOURCE_ID=$(az identity create \
        --name $USER_IDENTITY_NAME \
        --resource-group $RESOURCE_GROUP \
        --query id \
        --output tsv)
    
  3. Ask your Global Administrator or Privileged Role Administrator to grant the following permissions to the new user-assigned identity: User.Read.All, GroupMember.Read.All, and Application.Read.ALL. For more information, see the Permissions section of Active Directory authentication.

  4. Connect your app to a MySQL database with a system-assigned managed identity using Service Connector. To make this connection, run the az webapp connection create command.

    az webapp connection create mysql-flexible \
        --resource-group $RESOURCE_GROUP \
        --name $APPSERVICE_NAME \
        --target-resource-group $RESOURCE_GROUP \
        --server $MYSQL_HOST \
        --database $DATABASE_NAME \
        --system-identity mysql-identity-id=$IDENTITY_RESOURCE_ID \
        --client-type java
    

    This Service Connector command does the following tasks in the background:

    • Enable system-assigned managed identity for the app $APPSERVICE_NAME hosted by Azure App Service.

    • Set the Microsoft Entra admin to the current signed-in user.

    • Add a database user for the system-assigned managed identity in step 1 and grant all privileges of the database $DATABASE_NAME to this user. You can get the user name from the connection string in the output from the previous command.

    • Add a connection string to App Settings in the app named AZURE_MYSQL_CONNECTIONSTRING.

      Note

      If you see the error message The subscription is not registered to use Microsoft.ServiceLinker, run the command az provider register --namespace Microsoft.ServiceLinker to register the Service Connector resource provider, then run the connection command again.

Deploy the application

Follow these steps to prepare data in a database and deploy the application.

Create Database schema

  1. Open a firewall to allow connection from your current IP address.

    # Create a temporary firewall rule to allow connections from your current machine to the MySQL server
    export MY_IP=$(curl http://whatismyip.akamai.com)
    az mysql flexible-server firewall-rule create \
        --resource-group $RESOURCE_GROUP \
        --name $MYSQL_HOST \
        --rule-name AllowCurrentMachineToConnect \
        --start-ip-address ${MY_IP} \
        --end-ip-address ${MY_IP}
    
  2. Connect to the database and create tables.

    export DATABASE_FQDN=${MYSQL_HOST}.mysql.database.azure.com
    export CURRENT_USER=$(az account show --query user.name --output tsv)
    export RDBMS_ACCESS_TOKEN=$(az account get-access-token \
        --resource-type oss-rdbms \
        --output tsv \
        --query accessToken)
    mysql -h "${DATABASE_FQDN}" --user "${CURRENT_USER}" --enable-cleartext-plugin --password="$RDBMS_ACCESS_TOKEN" < azure/init-db.sql
    
  3. Remove the temporary firewall rule.

    az mysql flexible-server firewall-rule delete \
        --resource-group $RESOURCE_GROUP \
        --name $MYSQL_HOST \
        --rule-name AllowCurrentMachineToConnect
    

Deploy the application

  1. Update the connection string in App Settings.

    Get the connection string generated by Service Connector and add passwordless authentication plugin. This connection string is referenced in the startup script.

    export PASSWORDLESS_URL=$(\
        az webapp config appsettings list \
            --resource-group $RESOURCE_GROUP \
            --name $APPSERVICE_NAME \
        | jq -c '.[] \
        | select ( .name == "AZURE_MYSQL_CONNECTIONSTRING" ) \
        | .value' \
        | sed 's/"//g')
    # Create a new environment variable with the connection string including the passwordless authentication plugin
    export PASSWORDLESS_URL=${PASSWORDLESS_URL}'&defaultAuthenticationPlugin=com.azure.identity.extensions.jdbc.mysql.AzureMysqlAuthenticationPlugin&authenticationPlugins=com.azure.identity.extensions.jdbc.mysql.AzureMysqlAuthenticationPlugin'
    az webapp config appsettings set \
        --resource-group $RESOURCE_GROUP \
        --name $APPSERVICE_NAME \
        --settings "AZURE_MYSQL_CONNECTIONSTRING_PASSWORDLESS=${PASSWORDLESS_URL}"
    
  2. The sample app contains a pom.xml file that can generate the WAR file. Run the following command to build the app.

    mvn clean package -DskipTests
    
  3. Deploy the WAR and the startup script to the app service.

    az webapp deploy \
        --resource-group $RESOURCE_GROUP \
        --name $APPSERVICE_NAME \
        --src-path target/ROOT.war \
        --type war
    az webapp deploy \
        --resource-group $RESOURCE_GROUP \
        --name $APPSERVICE_NAME \
        --src-path src/main/webapp/WEB-INF/createMySQLDataSource.sh \
        --type startup
    

Test sample web app

Run the following command to test the application.

export WEBAPP_URL=$(az webapp show \
    --resource-group $RESOURCE_GROUP \
    --name $APPSERVICE_NAME \
    --query defaultHostName \
    --output tsv)

# Create a list
curl -X POST -H "Content-Type: application/json" -d '{"name": "list1","date": "2022-03-21T00:00:00","description": "Sample checklist"}' https://${WEBAPP_URL}/checklist

# Create few items on the list 1
curl -X POST -H "Content-Type: application/json" -d '{"description": "item 1"}' https://${WEBAPP_URL}/checklist/1/item
curl -X POST -H "Content-Type: application/json" -d '{"description": "item 2"}' https://${WEBAPP_URL}/checklist/1/item
curl -X POST -H "Content-Type: application/json" -d '{"description": "item 3"}' https://${WEBAPP_URL}/checklist/1/item

# Get all lists
curl https://${WEBAPP_URL}/checklist

# Get list 1
curl https://${WEBAPP_URL}/checklist/1

Clean up resources

In the preceding steps, you created Azure resources in a resource group. If you don't expect to need these resources in the future, delete the resource group by running the following command in the Cloud Shell:

az group delete --name myResourceGroup

This command may take a minute to run.

Next step

Learn more about running Java apps on App Service on Linux in the developer guide.