Tutorial: Connect to a PostgreSQL Database from Java Tomcat App Service without secrets using a managed identity
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 PostgreSQL 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 PostgreSQL database.
- Deploy the sample app to Azure App Service on Tomcat using WAR packaging.
- Configure a Tomcat web application to use Microsoft Entra authentication with PostgreSQL Database.
- Connect to PostgreSQL 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/Tomcat/
Create an Azure Database for PostgreSQL
Follow these steps to create an Azure Database for Postgres in your subscription. The Tomcat app connects to this database and store its data when running, persisting the application state no matter where you run the application.
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>
Create an Azure Resource Group, noting the resource group name.
export RESOURCE_GROUP=<resource-group-name> export LOCATION=eastus az group create --name $RESOURCE_GROUP --location $LOCATION
Create an Azure Database for PostgreSQL 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 POSTGRESQL_ADMIN_USER=azureuser # PostgreSQL admin access rights won't be used because Azure AD authentication is leveraged to administer the database. export POSTGRESQL_ADMIN_PASSWORD=<admin-password> export POSTGRESQL_HOST=<postgresql-host-name> # Create a PostgreSQL server. az postgres flexible-server create \ --resource-group $RESOURCE_GROUP \ --name $POSTGRESQL_HOST \ --location $LOCATION \ --admin-user $POSTGRESQL_ADMIN_USER \ --admin-password $POSTGRESQL_ADMIN_PASSWORD \ --public-access 0.0.0.0 \ --sku-name Standard_D2s_v3
Create a database for the application.
export DATABASE_NAME=checklist az postgres flexible-server db create \ --resource-group $RESOURCE_GROUP \ --server-name $POSTGRESQL_HOST \ --database-name $DATABASE_NAME
Deploy the application to App Service
Follow these steps to build a WAR file and deploy to Azure App Service on Tomcat using a WAR packaging.
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 -f pom.xml
Create an Azure App Service resource on Linux using Tomcat 9.0.
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 B1 \ --is-linux # Create an App Service resource. az webapp create \ --resource-group $RESOURCE_GROUP \ --name $APPSERVICE_NAME \ --plan $APPSERVICE_PLAN \ --runtime "TOMCAT:10.0-java11"
Deploy the WAR package to App Service.
az webapp deploy \ --resource-group $RESOURCE_GROUP \ --name $APPSERVICE_NAME \ --src-path target/app.war \ --type war
Connect the Postgres database with identity connectivity
Next, connect the database using Service Connector.
Install the Service Connector passwordless extension for the Azure CLI:
az extension add --name serviceconnector-passwordless --upgrade
Then, connect your app to a Postgres 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 postgres-flexible \
--resource-group $RESOURCE_GROUP \
--name $APPSERVICE_NAME \
--target-resource-group $RESOURCE_GROUP \
--server $POSTGRESQL_HOST \
--database $DATABASE_NAME \
--system-identity \
--client-type java
This command creates a connection between your web app and your PostgreSQL server, and manages authentication through a system-assigned managed identity.
Next, update App Settings and add plugin in connection string
export AZURE_POSTGRESQL_CONNECTIONSTRING=$(\
az webapp config appsettings list \
--resource-group $RESOURCE_GROUP \
--name $APPSERVICE_NAME \
| jq -c -r '.[] \
| select ( .name == "AZURE_POSTGRESQL_CONNECTIONSTRING" ) \
| .value')
az webapp config appsettings set \
--resource-group $RESOURCE_GROUP \
--name $APPSERVICE_NAME \
--settings 'CATALINA_OPTS=-DdbUrl="'"${AZURE_POSTGRESQL_CONNECTIONSTRING}"'&authenticationPluginClassName=com.azure.identity.extensions.jdbc.postgresql.AzurePostgresqlAuthenticationPlugin"'
Test the 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 steps
Learn more about running Java apps on App Service on Linux in the developer guide.
Learn how to secure your app with a custom domain and certificate.