diff --git a/docs/01_lab_plan/0103.md b/docs/01_lab_plan/0103.md index 2ff8e4b..5ed75bc 100644 --- a/docs/01_lab_plan/0103.md +++ b/docs/01_lab_plan/0103.md @@ -11,9 +11,9 @@ Now that you identified the viable compute platforms, you need to decide which A The Azure platform offers several database-as-a-services options, including [Azure SQL Database](https://docs.microsoft.com/azure/azure-sql/database/sql-database-paas-overview?view=azuresql), [Azure Database for MySQL](https://docs.microsoft.com/azure/mysql/), [Azure Cosmos DB](https://docs.microsoft.com/azure/cosmos-db/introduction), and [Azure Database for PostgreSQL](https://docs.microsoft.com/azure/postgresql/). Your choice of the database technology should be based on the following requirements for the Spring Petclinic application: -* The target database service should simplify the migration path from the on-premises MySQL deployment. +* The target database service should simplify the migration path from the on-premises MySQL and PostgreSQL deployment. * The target database service must support automatic backups. * The target database service needs to support automatic patching. -Based on these requirements, you decided to use Azure Database for MySQL Flexible Server. +Based on these requirements, you will be having two options, either you can use PostgreSQL or MySQL based on your preference. diff --git a/docs/01_lab_plan/0104.md b/docs/01_lab_plan/0104.md index 41af7ab..4c69308 100644 --- a/docs/01_lab_plan/0104.md +++ b/docs/01_lab_plan/0104.md @@ -23,7 +23,7 @@ In case you chose to use Azure Spring Apps, you have the option to deploy Azure In case you chose AKS as the hosting platform, you will need at least one subnet in a virtual network to run the nodes of your AKS cluster. This subnet for now can be small, such as `/26`, which allows for a total of 64 IP addresses (although some of them are pre-allocated for the platform use). -The Azure Database for MySQL deployment will not require any virtual network connectivity for the first phase of the migration of the application. This will also change in one of the subsequent exercises, when you will implement additional security measures to protect the full application stack. +The Azure Database for MySQL or PostgreSQL deployment will not require any virtual network connectivity for the first phase of the migration of the application. This will also change in one of the subsequent exercises, when you will implement additional security measures to protect the full application stack. ## Are there any supporting services you would need for running the application? diff --git a/docs/02_lab_migrate/0201.md b/docs/02_lab_migrate/0201.md index eb59573..f8fbf82 100644 --- a/docs/02_lab_migrate/0201.md +++ b/docs/02_lab_migrate/0201.md @@ -53,7 +53,7 @@ As a first step you will need to create your Azure Container Apps (ACA) environm az provider register --namespace Microsoft.OperationalInsights ``` -1. Run the following commands to create a resource group that will contain all of your resources (replace the `` placeholder with the name of any Azure region in which you can create an ACA and an Azure Database for MySQL Flexible Server instance, see [this page](https://azure.microsoft.com/explore/global-infrastructure/products-by-region/?products=container-apps) for regional availability details of those services: +1. Run the following commands to create a resource group that will contain all of your resources (replace the `` placeholder with the name of any Azure region in which you can create an ACA and an Azure Database for MySQL or PostgreSQL Flexible Server instance, see [this page](https://azure.microsoft.com/explore/global-infrastructure/products-by-region/?products=container-apps) for regional availability details of those services: ```bash UNIQUEID=$(openssl rand -hex 3) diff --git a/docs/02_lab_migrate/0203.md b/docs/02_lab_migrate/0203.md index 5c823b1..5602111 100644 --- a/docs/02_lab_migrate/0203.md +++ b/docs/02_lab_migrate/0203.md @@ -1,7 +1,7 @@ --- -title: '3. MySQL database' +title: '3.1 MySQL database' layout: default -nav_order: 3 +nav_order: 4 parent: 'Lab 2: Migrate to Azure Container Apps' --- diff --git a/docs/02_lab_migrate/0203_postgres_application.yaml b/docs/02_lab_migrate/0203_postgres_application.yaml new file mode 100644 index 0000000..baf3e20 --- /dev/null +++ b/docs/02_lab_migrate/0203_postgres_application.yaml @@ -0,0 +1,80 @@ +# COMMON APPLICATION PROPERTIES + +# embedded database init, supports PostgreSQL too trough the 'PostgreSQL' spring profile +spring: +datasource: + url: jdbc:postgresql://.database.azure.com:5432/petclinic?sslmode=require + username: myadmin + password: +sql: + init: + schema-locations: classpath*:db/postgres/schema.sql + data-locations: classpath*:db/postgres/data.sql + mode: ALWAYS +jms: + queue: + visits-requests: visits-requests + visits-confirmations: visits-confirmations + servicebus: + enabled: false # disable messaging support by default + namespace: ${SERVICEBUS_NAMESPACE} + pricing-tier: premium + passwordless-enabled: true + credential: + managed-identity-enabled: true + client-id: ${CLIENT_ID} +sleuth: + sampler: + probability: 1.0 +cloud: + config: + # Allow the microservices to override the remote properties with their own System properties or config file + allow-override: true + # Override configuration with any local property source + override-none: true +jpa: + open-in-view: false + hibernate: + ddl-auto: none + show-sql: true + +# Spring Boot 1.5 makes actuator secure by default +management.security.enabled: false +# Enable all Actuators and not only the two available by default /health and /info starting Spring Boot 2.0 +management.endpoints.web.exposure.include: "*" + +# Temporary hack required by the Spring Boot 2 / Spring Cloud Finchley branch +# Waiting issue https://github.com/spring-projects/spring-boot/issues/13042 +spring.cloud.refresh.refreshable: false + +# Logging +logging.level.org.springframework: INFO + +# enable health probes +management.health.livenessState.enabled: true +management.health.readinessState.enabled: true +management.endpoint.health.probes.enabled: true + +# Metrics +management: +endpoint: + metrics: + enabled: true + prometheus: + enabled: true +endpoints: + web: + exposure: + include: '*' +metrics: + export: + prometheus: + enabled: true +eureka: +client: + serviceUrl: + defaultZone: http://discovery-server:8761/eureka/ + enableSelfPreservation: true + registryFetchIntervalSeconds: 20 +instance: + preferIpAddress: true \ No newline at end of file diff --git a/docs/02_lab_migrate/0203_postgresql.md b/docs/02_lab_migrate/0203_postgresql.md new file mode 100644 index 0000000..c1f9349 --- /dev/null +++ b/docs/02_lab_migrate/0203_postgresql.md @@ -0,0 +1,101 @@ +--- +title: '3.2 PostgreSQL database [OPTIONAL]' +layout: default +nav_order: 3 +parent: 'Lab 2: Migrate to Azure Container Apps' +--- + +# Create an Azure PostgreSQL Database service + +You now have the compute service that will host your applications and the config server that will be used by your migrated application. Before you start deploying individual microservices as Azure Container Apps, you need to first create an Azure Database for PostgreSQL Flexible Server-hosted database for them. To accomplish this, you can use the following guidance: + +- [Quickstart: Create an Azure Database for PostgreSQL Flexible Server using Azure CLI](https://learn.microsoft.com/azure/PostgreSQL/flexible-server/quickstart-create-server-cli). + +You will also need to update the config for your applications to use the newly provisioned PostgreSQL Server. This will involve updating the application.yml config file in your private git config repo with the values provided in the PostgreSQL Server connection string. + +Your PostgreSQL database will also have a firewall enabled. This firewall will by default block all incoming calls. You will need to open this firewall in case you want to connect to it from your microservices running in the ACA environment. + +## Step by step guidance + +1. Run the following commands to create an instance of PostgreSQL Flexible server. Note that the name of the server must be globally unique, so adjust it accordingly in case the randomly generated name is already in use. Keep in mind that the name can contain only lowercase letters, numbers and hyphens. In addition, replace the `` placeholder with a complex password and record its value. + {: .note } + > Here we use PostgreSQL admin password for apps to connect to sql server, this is for demo/test/learn purpose, not recommand in production environment. Please refer to [Lab 04: Connect to Database securely using identity](https://azure-samples.github.io/java-microservices-aca-lab/docs/04_lab_secrets/04_openlab_secrets_aca.html) for the secured managed identity solution. + + ```bash + POSTGRES_SERVER_NAME=postgres-$APPNAME-$UNIQUEID + POSTGRES_ADMIN_USERNAME=sqladmin + POSTGRES_ADMIN_PASSWORD="" + DATABASE_NAME=petclinic + + az postgres flexible-server create \ + --admin-user myadmin \ + --admin-password "$POSTGRES_ADMIN_PASSWORD" \ + --name "$POSTGRES_SERVER_NAME" \ + --resource-group "$RESOURCE_GROUP" + ``` + + {: .note } + > During the creation you will be asked whether access for your IP address should be added and whether access for all IP's should be added. Answer `n` for no on both questions. + + {: .note } + > In case this statement fails with the message `ERROR: Unable to prompt for confirmation as no tty available`, add the `--yes` flag to the above statement. This will auto-install any missing resource providers. + + {: .note } + > Wait for the provisioning to complete. This might take about 3 minutes. + +1. Once the Azure Database for PostgreSQL Flexible Server instance gets created, it will output details about its settings. In the output, you will find the server connection string. Record its value since you will need it later in this exercise. + +1. Run the following commands to create a database in the Azure Database for PostgreSQL Flexible Server instance. + + ```bash + az postgres flexible-server db create \ + --server-name $POSTGRES_SERVER_NAME \ + --resource-group $RESOURCE_GROUP \ + -d $DATABASE_NAME + ``` + +1. You will also need to allow connections to the server from your ACA environment. For now, to accomplish this, you will create a server firewall rule to allow inbound traffic from all Azure Services. + + Check the status of your sql server + ![SQL Server Networking](../../images/sql-server-manage-firewall.png) + + Checking `Allow Azure services and resources to access this server` adds an IP based firewall rule with start and end IP address of `0.0.0.0`, See [Connections from inside Azure](https://learn.microsoft.com/en-us/azure/azure-sql/database/firewall-configure?view=azuresql#connections-from-inside-azure). + + This way your apps running in Azure Container Apps will be able to reach the PostgreSQL database. In one of the upcoming exercises, you will restrict this connectivity to limit it exclusively to the apps hosted by your ACA. + + ```bash + az postgres flexible-server firewall-rule create \ + --rule-name allAzureIPs \ + --name $POSTGRES_SERVER_NAME \ + --resource-group $RESOURCE_GROUP \ + --start-ip-address 0.0.0.0 --end-ip-address 0.0.0.0 + ``` + + Check the sql server firewall rules with command + ```bash + az postgres flexible-server firewall-rule list \ + --name $POSTGRES_SERVER_NAME \ + --resource-group $RESOURCE_GROUP \ + ``` + +1. From the Git Bash window, in the config repository you cloned locally, use your favorite text editor to open the _application.yml_ file. Replace the full contents of the _application.yml_ file with the contents of [this application.yml](0203_postgres_application.yaml) file. The updated _application.yml_ file includes the following changes: + + * It removes the default `0` value for the `server.port` on line 5. + * It changes the default `spring.sql.init` values to use `PostgreSQL` configuration on lines 15 to 19. + * It adds a `spring.datasource` property for your PostgreSQL database on lines 10 to 14. + * It adds extra `eureka` config on lines 61 to 66. + * It removes the `chaos-monkey` and `PostgreSQL` profiles. + +1. In the part you pasted, update the values of the target datasource endpoint on line 6, the corresponding admin user account on line 7, and its password on line 8 to match your configuration. Set these values by using the information in the Azure Database for PostgreSQL Flexible Server connection string you recorded earlier in this task. + +1. Save the changes and push the updates you made to the _application.yml_ file to your private GitHub repo by running the following commands from the Git Bash prompt: + + ```bash + git add . + git commit -m 'azure postgres info' + git push + ``` + + {: .note } + > At this point, the admin account user name and password are stored in clear text in the application.yml config file. In one of upcoming exercises, you will remediate this potential vulnerability by removing clear text credentials from your configuration. + \ No newline at end of file diff --git a/docs/02_lab_migrate/0204.md b/docs/02_lab_migrate/0204.md index e716108..ab0bdb6 100644 --- a/docs/02_lab_migrate/0204.md +++ b/docs/02_lab_migrate/0204.md @@ -1,7 +1,7 @@ --- title: '4. Java Components' layout: default -nav_order: 4 +nav_order: 5 parent: 'Lab 2: Migrate to Azure Container Apps' --- diff --git a/docs/02_lab_migrate/0205.md b/docs/02_lab_migrate/0205.md index 0faa26b..01d00b0 100644 --- a/docs/02_lab_migrate/0205.md +++ b/docs/02_lab_migrate/0205.md @@ -1,7 +1,7 @@ --- title: '5. Deploy to ACA' layout: default -nav_order: 5 +nav_order: 6 parent: 'Lab 2: Migrate to Azure Container Apps' --- @@ -66,7 +66,7 @@ Make sure the api-gateway and admin-server microservices have public IP addresse --runtime java ``` -1. Wait for the provisioning to finish, now you can create the other microservices, `customers`, `vets` and `visits`. These will be internal microservices, exposed by the `api-gateway`. Since these microservices connect to the MySQL database, you will also assign them the user assigned managed identity. +1. Wait for the provisioning to finish, now you can create the other microservices, `customers`, `vets` and `visits`. These will be internal microservices, exposed by the `api-gateway`. Since these microservices connect to the MySQL or PostgreSQL database, you will also assign them the user assigned managed identity. ```bash APP_NAME=customers-service diff --git a/docs/02_lab_migrate/0206.md b/docs/02_lab_migrate/0206.md index 9a745b9..6372e18 100644 --- a/docs/02_lab_migrate/0206.md +++ b/docs/02_lab_migrate/0206.md @@ -1,7 +1,7 @@ --- title: '6. Test' layout: default -nav_order: 6 +nav_order: 7 parent: 'Lab 2: Migrate to Azure Container Apps' --- @@ -48,15 +48,23 @@ You will need to look for the `properties.configuration.ingress.fqdn` property. You now have the Spring Petclinic application running properly on Azure Container Apps. -1. In case you are not seeing any data in your application, you can troubleshoot this issue by interactively connecting to your MySQL Flexible Server and querying your databases and tables. +1. In case you are not seeing any data in your application, you can troubleshoot this issue by interactively connecting to your MySQL or PostgreSQL Flexible Server and querying your databases and tables. ```bash - az mysql flexible-server connect -n $MYSQL_SERVER_NAME -u myadmin -p $MYSQL_ADMIN_PASSWORD --interactive + az mysql flexible-server connect -n $MySQL_SERVER_NAME -u myadmin -p $MySQL_ADMIN_PASSWORD --interactive show databases; use petclinic; show tables; select * from owners; ``` + ```bash + az postgres flexible-server connect -n $POSTGRES_SERVER_NAME -u myadmin -p $POSTGRES_ADMIN_PASSWORD --interactive + show databases; + use petclinic; + show tables; + select * from owners; + + {: .note } - > For the MySQL Flexible Server connection to work, you will need to have your local IP address added to the MySQL Flexible Server firewall. + > For the MySQL or PostgreSQL Flexible Server connection to work, you will need to have your local IP address added to the MySQL or PostgreSQL Flexible Server firewall. diff --git a/docs/02_lab_migrate/0207.md b/docs/02_lab_migrate/0207.md index c779c2e..012c24f 100644 --- a/docs/02_lab_migrate/0207.md +++ b/docs/02_lab_migrate/0207.md @@ -1,7 +1,7 @@ --- title: '7. Review' layout: default -nav_order: 7 +nav_order: 8 parent: 'Lab 2: Migrate to Azure Container Apps' --- @@ -11,7 +11,7 @@ In this lab, you migrated your existing Spring Petclinic microservices applicati - Create an Azure Container Apps environment - Set up a configuration repository -- Created an Azure MySQL Database service +- Created an Azure MySQL or PostgreSQL Database service - Created the config and discovery server as java components on ACA - Deployed the microservices of the Spring Petclinic app as Azure container apps - Tested the application through the publicly available endpoint diff --git a/docs/02_lab_migrate/02_openlab_setup_aca.md b/docs/02_lab_migrate/02_openlab_setup_aca.md index 10cf5b8..f081b8e 100644 --- a/docs/02_lab_migrate/02_openlab_setup_aca.md +++ b/docs/02_lab_migrate/02_openlab_setup_aca.md @@ -19,7 +19,7 @@ After you complete this lab, you will be able to: - Create an Azure Container Apps environment - Set up a configuration repository -- Create an Azure MySQL Database service +- Create an Azure MySQL or PostgreSQL Database service - Create the java components for your config and discovery server - Deploy the microservices of the Spring Petclinic app to ACA and bind them to java components - Test the application through the publicly available endpoint @@ -38,7 +38,7 @@ During the process you'll: - Create an Azure Container Apps environment - Set up a configuration repository -- Create an Azure MySQL Database service +- Create an Azure MySQL or PostgreSQL Database service - Create the java components for your config and discovery server - Deploy the microservices of the Spring Petclinic app to ACA and bind them to java components - Test the application through the publicly available endpoint diff --git a/docs/04_lab_secrets_postgres/0401_postgres.md b/docs/04_lab_secrets_postgres/0401_postgres.md new file mode 100644 index 0000000..9a1cee2 --- /dev/null +++ b/docs/04_lab_secrets_postgres/0401_postgres.md @@ -0,0 +1,74 @@ +--- +title: '1. Create db admin account' +layout: default +nav_order: 1 +parent: 'Lab 4: Connect to Database securely using identity [PostgreSQL]' +--- + +# Create a database administrator account + +You are already using a managed Identity to connect to the Azure Container Registry. You can use this same identity to also connect to the database. This will allow you to remove the username and password from the config repository. + +- [Configure passwordless database connections for Java apps](https://learn.microsoft.com/azure/developer/java/ee/how-to-configure-passwordless-datasource?toc=%2Fazure%2Fdeveloper%2Fintro%2Ftoc.json&bc=%2Fazure%2Fdeveloper%2Fintro%2Fbreadcrumb%2Ftoc.json&tabs=postgresql-passwordless-flexible-server) + +## Step by step guidance + +1. Before creating the administrator account, you need to enable Microsoft Entra Authentication from the portal. + +1. In the Azure Portal, navigate to your PostgreSQL server page. + +1. On your PostgreSQL page, select Authentication (1) from left menu under security, check PostgreSQL and Microsoft Entra authentication (2) option and save it using the Save (3) option from top menu. + + ![](/images/postgres-enable.png) + +1. You will need to allow the user assigned managed identity access to the database. To configure this, you will need to first make your current logged in user account database administrator. For this to work on a PostgreSQL database you first need an additional managed identity. + + ```bash + DB_ADMIN_USER_ASSIGNED_IDENTITY_NAME=uid-dbadmin-$APPNAME-$UNIQUEID + + ADMIN_IDENTITY_RESOURCE_ID=$(az identity create \ + --name $DB_ADMIN_USER_ASSIGNED_IDENTITY_NAME \ + --resource-group $RESOURCE_GROUP \ + --query id \ + --output tsv) + ``` + +1. This identity needs to be assigned to your PostgreSQL server. + + ```bash + az postgres flexible-server identity assign \ + --resource-group $RESOURCE_GROUP \ + --server-name $POSTGRES_SERVER_NAME \ + --identity $DB_ADMIN_USER_ASSIGNED_IDENTITY_NAME + + + az postgres flexible-server identity list \ + --resource-group $RESOURCE_GROUP \ + --server-name $POSTGRES_SERVER_NAME + ``` + +1. Get the current logged in user and object ID. This will give you the info of the user account you are currently logged in with in the Azure CLI. + + ```bash + CURRENT_USER=$(az account show --query user.name --output tsv) + echo $CURRENT_USER + CURRENT_USER_OBJECTID=$(az ad signed-in-user show --query id --output tsv) + echo $CURRENT_USER_OBJECTID + ``` + +1. Next you create a database administrator based on your current user account. + + ```bash + az postgres flexible-server ad-admin create \ + --resource-group $RESOURCE_GROUP \ + --server-name $POSTGRES_SERVER_NAME \ + --object-id $CURRENT_USER_OBJECTID \ + --display-name $CURRENT_USER \ + + DB_ID=$(az postgres flexible-server db show \ + --server-name $POSTGRES_SERVER_NAME \ + --resource-group $RESOURCE_GROUP \ + -d $DATABASE_NAME \ + --query id \ + -o tsv) + ``` \ No newline at end of file diff --git a/docs/04_lab_secrets_postgres/0402_postgres.md b/docs/04_lab_secrets_postgres/0402_postgres.md new file mode 100644 index 0000000..da6f040 --- /dev/null +++ b/docs/04_lab_secrets_postgres/0402_postgres.md @@ -0,0 +1,126 @@ +--- +title: '2. Create service connections' +layout: default +nav_order: 2 +parent: 'Lab 4: Connect to Database securely using identity [PostgreSQL]' +--- + +# Create service connections from the microservices to the database server + +The apps deployed as the Spring Petclinic microservices will now connect using a service connector to the PostgreSQL Flexible server. A service connector will set up the needed environment variables the service needs to make the connection. You can use the following guidance to create a service connector: + +- [Connect an Azure Database for PostgreSQL instance to your application in Azure Container Apps](https://learn.microsoft.com/azure/service-connector/quickstart-portal-container-apps?tabs=SMI). + +The following three apps of your application use the database hosted by the Azure Database for PostgreSQL Flexible Server instance, so they will need to be assigned a service connector: + +- `customers-service` +- `vets-service` +- `visits-service` + +Since each of these apps already has a user assigned managed identity assigned to them, you will make use of this same identity to get access to the database. + +## Step by step guidance + +1. For creating a service connector you will need to add the `serviceconnector-passwordless` extension: + + ```bash + az extension add --name serviceconnector-passwordless --upgrade + ``` + +1. You will also need your subscription ID for creating the service connections: + + ```bash + SUBID=$(az account show --query id -o tsv) + ``` + +1. You will also need resource ID of the apps: + + ```bash + CUSTOMERS_ID=$(az containerapp show \ + --resource-group $RESOURCE_GROUP \ + --name customers-service \ + --query id \ + -o tsv) + + VISITS_ID=$(az containerapp show \ + --resource-group $RESOURCE_GROUP \ + --name visits-service \ + --query id \ + -o tsv) + + VETS_ID=$(az containerapp show \ + --resource-group $RESOURCE_GROUP \ + --name vets-service \ + --query id \ + -o tsv) + ``` + +1. Create now the service connections for the `customers-service`. For this you also need the client ID of the identity you created earlier. + + ```bash + CLIENT_ID=$(az identity show --resource-group $RESOURCE_GROUP --name $ACA_IDENTITY --query 'clientId' --output tsv) + echo $CLIENT_ID + az containerapp connection create postgres-flexible \ + --connection postgres_conn \ + --source-id $CUSTOMERS_ID \ + --target-id $DB_ID \ + --client-type SpringBoot \ + --user-identity client-id=$CLIENT_ID subs-id=$SUBID \ + -c customers-service + ``` + +1. You can test the validity of this new connection with the `validate` command: + + ```bash + CUSTOMERS_CONN_ID=$(az containerapp connection list \ + --resource-group $RESOURCE_GROUP \ + --name customers-service \ + --query [].id -o tsv) + + az containerapp connection validate \ + --id $CUSTOMERS_CONN_ID + ``` + + The output of this command should show that the connection was made successful. + +1. In the same way create the service connections for the `vets-service` and `visits-service`: + + ```bash + az containerapp connection create postgres-flexible \ + --connection postgres_conn \ + --source-id $VETS_ID \ + --target-id $DB_ID \ + --client-type SpringBoot \ + --user-identity client-id=$CLIENT_ID subs-id=$SUBID \ + -c vets-service + + az containerapp connection create postgres-flexible \ + --connection postgres_conn \ + --source-id $VISITS_ID \ + --target-id $DB_ID \ + --client-type SpringBoot \ + --user-identity client-id=$CLIENT_ID subs-id=$SUBID \ + -c visits-service + ``` + +1. You can test the validity of this new connection with the `validate` command: + + ```bash + VETS_CONN_ID=$(az containerapp connection list \ + --resource-group $RESOURCE_GROUP \ + --name vets-service \ + --query [].id -o tsv) + + az containerapp connection validate \ + --id $VETS_CONN_ID + + VISITS_CONN_ID=$(az containerapp connection list \ + --resource-group $RESOURCE_GROUP \ + --name visits-service \ + --query [].id -o tsv) + + az containerapp connection validate \ + --id $VISITS_CONN_ID + ``` + +1. In the Azure Portal, navigate to your `customers-service` container app. In the `customers-service` app, select the `Service Connector` menu item. Notice in this screen you can see the details of your service connector. Notice that the service connector has all the config values set like `spring.datasource.url`, `spring.datasource.username`, but for instance no `spring.datasource.password`. These values get turned into environment variables at runtime for your app. Instead of `spring.datasource.password` it has a `spring.cloud.azure.credential.client-id`, which is the client ID of your managed identity. It also defines 2 additional variables `spring.datasource.azure.passwordless-enabled` and `spring.cloud.azure.credential.managed-identity-enabled` for enabling the passwordless connectivity. \ No newline at end of file diff --git a/docs/04_lab_secrets_postgres/0404_postgres.md b/docs/04_lab_secrets_postgres/0404_postgres.md new file mode 100644 index 0000000..08ff0f7 --- /dev/null +++ b/docs/04_lab_secrets_postgres/0404_postgres.md @@ -0,0 +1,18 @@ +--- +title: '3. Review' +layout: default +nav_order: 3 +parent: 'Lab 4: Connect to Database securely using identity [PostgreSQL]' +--- + +# Review + +In this lab, you secured the secrets of your Spring Petclinic microservices application in Azure. In this lab you have + +- Created a database administrator account +- Created service connections from the microservices to the database server +- Updated the applications to use passwordless connectivity + +The below image illustrates the end state you have build in this lab. + +![lab 4 overview](../../images/acalab4.png) diff --git a/docs/04_lab_secrets_postgres/04_openlab_secrets_aca.md b/docs/04_lab_secrets_postgres/04_openlab_secrets_aca.md new file mode 100644 index 0000000..4cedead --- /dev/null +++ b/docs/04_lab_secrets_postgres/04_openlab_secrets_aca.md @@ -0,0 +1,42 @@ +--- +title: 'Lab 4: Connect to Database securely using identity [PostgreSQL]' +layout: default +nav_order: 7 +has_children: true +--- + +# Lab 04: Connect to Database securely using identity + +# Student manual + +## Lab scenario + +Your team is now running a first version of the spring-petclinic microservice application in Azure. However you don't like the fact that your application secrets live directly in configuration code. You would like to have a better way to protect application secrets like your database connection string . In this lab you will better protect your application secrets. + +## Objectives + +After you complete this lab, you will be able to: + +- Create a database administrator account +- Create service connections from the microservices to the database server +- Update the applications to use passwordless connectivity + +The below image illustrates the end state you will be building in this lab. + +![lab 4 overview](../../images/acalab4.png) + +## Lab Duration + +- **Estimated Time**: 60 minutes + +## Instructions + +During this lab, you will: + + +- Create a database administrator account +- Create service connections from the microservices to the database server +- Update the applications to use passwordless connectivity + +{: .note } +> The instructions provided in this exercise assume that you successfully completed the previous exercise and are using the same lab environment, including your Git Bash session with the relevant environment variables already set. diff --git a/docs/05_lab_openai/05_openlab_openai_aca.md b/docs/05_lab_openai/05_openlab_openai_aca.md index a0b4934..e65af4d 100644 --- a/docs/05_lab_openai/05_openlab_openai_aca.md +++ b/docs/05_lab_openai/05_openlab_openai_aca.md @@ -1,7 +1,7 @@ --- title: 'Lab 5: Integrate with Azure OpenAI' layout: default -nav_order: 7 +nav_order: 8 has_children: true --- diff --git a/docs/06_lab_automation/06_openlab_automation.md b/docs/06_lab_automation/06_openlab_automation.md index 2e6cd61..d6f57c7 100644 --- a/docs/06_lab_automation/06_openlab_automation.md +++ b/docs/06_lab_automation/06_openlab_automation.md @@ -1,7 +1,7 @@ --- title: 'Lab 6: Deploy to Azure automatically' layout: default -nav_order: 8 +nav_order: 9 has_children: true --- diff --git a/docs/07_lab_security/0704.md b/docs/07_lab_security/0704.md index 8f3507f..200191a 100644 --- a/docs/07_lab_security/0704.md +++ b/docs/07_lab_security/0704.md @@ -225,6 +225,8 @@ For making use of internal networking and getting a private inbound IP address f -o tsv) ``` +### For MySQL Setup + 1. Recreate now the service connection for the `customers-service`. ```bash @@ -291,6 +293,75 @@ For making use of internal networking and getting a private inbound IP address f --id $VISITS_CONN_ID ``` +### For PostgreSQL Setup + +1. Recreate now the service connection for the `customers-service`. + + ```bash + az containerapp connection create Postgres-flexible \ + --connection Postgres_conn \ + --source-id $CUSTOMERS_ID \ + --target-id $DB_ID \ + --client-type SpringBoot \ + --user-identity client-id=$CLIENT_ID subs-id=$SUBID \ + -c customers-servicee + ``` + +1. You can test the validity of this new connection with the `validate` command: + + ```bash + CUSTOMERS_CONN_ID=$(az containerapp connection list \ + --resource-group $RESOURCE_GROUP \ + --name customers-service \ + --query [].id -o tsv) + + az containerapp connection validate \ + --id $CUSTOMERS_CONN_ID + ``` + + The output of this command should show that the connection was made successful. + +1. In the same way create the service connections for the `vets-service` and `visits-service`: + + ```bash + az containerapp connection create Postgres-flexible \ + --connection Postgres_conn \ + --source-id $VETS_ID \ + --target-id $DB_ID \ + --client-type SpringBoot \ + --user-identity client-id=$CLIENT_ID subs-id=$SUBID \ + -c vets-service + + az containerapp connection create Postgres-flexible \ + --connection Postgres_conn \ + --source-id $VISITS_ID \ + --target-id $DB_ID \ + --client-type SpringBoot \ + --user-identity client-id=$CLIENT_ID subs-id=$SUBID \ + -c visits-service + ``` + +1. You can test the validity of this new connection with the `validate` command: + + ```bash + VETS_CONN_ID=$(az containerapp connection list \ + --resource-group $RESOURCE_GROUP \ + --name vets-service \ + --query [].id -o tsv) + + az containerapp connection validate \ + --id $VETS_CONN_ID + + VISITS_CONN_ID=$(az containerapp connection list \ + --resource-group $RESOURCE_GROUP \ + --name visits-service \ + --query [].id -o tsv) + + az containerapp connection validate \ + --id $VISITS_CONN_ID + ``` + + #### Rebuild with azd automation 1. edit parameter file `infra/bicep/main.parameters.json`, add new parameter diff --git a/docs/07_lab_security/0706.md b/docs/07_lab_security/0706.md index 69bb787..7966327 100644 --- a/docs/07_lab_security/0706.md +++ b/docs/07_lab_security/0706.md @@ -56,4 +56,4 @@ You now have completed all steps required to test whether your application is ac 1. On your lab computer, start a web browser and, in the web browser window navigate to the URL that consists of the `https://` prefix followed by the custom DNS name you specified when updating the local hosts file. Your browser may display a warning notifying you that your connection is not private, but this is expected since you are relying on self-signed certificate. Acknowledge the warning but proceed to displaying the target web page. You should be able to see the PetClinic application start page again. {: .note } - > While the connection to the MySQL database should be working at this point, keep in mind that this connectivity is established via a its public endpoint, rather than the private one. You will remediate this in the next exercise of this lab. + > While the connection to the MySQL or PostgreSQL database should be working at this point, keep in mind that this connectivity is established via a its public endpoint, rather than the private one. You will remediate this in the next exercise of this lab. diff --git a/docs/07_lab_security/07_openlab_security_aca.md b/docs/07_lab_security/07_openlab_security_aca.md index 70ecc62..260e80f 100644 --- a/docs/07_lab_security/07_openlab_security_aca.md +++ b/docs/07_lab_security/07_openlab_security_aca.md @@ -1,7 +1,7 @@ --- title: 'Lab 7: Protect endpoints using Web Application Firewalls' layout: default -nav_order: 9 +nav_order: 10 has_children: true --- diff --git a/docs/08_lab_private/08_openlab_private_endpoints_aca.md b/docs/08_lab_private/08_openlab_private_endpoints_aca.md index 4afd2a4..eb2e990 100644 --- a/docs/08_lab_private/08_openlab_private_endpoints_aca.md +++ b/docs/08_lab_private/08_openlab_private_endpoints_aca.md @@ -1,7 +1,7 @@ --- title: 'Lab 8: Secure MySQL database and Key Vault using a Private Endpoint' layout: default -nav_order: 10 +nav_order: 11 has_children: true --- diff --git a/docs/08_lab_private_postgres/0801.md b/docs/08_lab_private_postgres/0801.md new file mode 100644 index 0000000..245b6da --- /dev/null +++ b/docs/08_lab_private_postgres/0801.md @@ -0,0 +1,107 @@ +--- +title: '1. PostgreSQL' +layout: default +nav_order: 1 +parent: 'Lab 8: Secure PostgreSQL database and Key Vault using a Private Endpoint [PostgreSQL]' +--- + +# Lock down the Azure Database for PostgreSQL Flexible Server instance by using a private endpoint + +To start, you need to lock down access to your PostgreSQL database by using a private endpoint. This will protect the database content. A private endpoint is represented by a private IP address within a virtual network. Once you enable it, you can block public access to your PostgreSQL Flexible Server. To accomplish this, you can use the following guidance: + +- [Create and manage Private Link for Azure Database for PostgreSQL - Flexible Server using CLI](https://learn.microsoft.com/azure/PostgreSQL/flexible-server/how-to-networking-private-link-azure-cli). +- [Private Link for Azure Database for PostgreSQL - Flexible Server](https://learn.microsoft.com/azure/PostgreSQL/flexible-server/concepts-networking-private-link) + +## Step by step guidance + +1. To start, you need to create an additional subnet for the private endpoints. + + ```bash + PRIVATE_ENDPOINTS_SUBNET_CIDR=10.1.4.0/24 + PRIVATE_ENDPOINTS_SUBNET_NAME=private-endpoints-subnet + + az network vnet subnet create \ + --name $PRIVATE_ENDPOINTS_SUBNET_NAME \ + --resource-group $RESOURCE_GROUP \ + --vnet-name $VIRTUAL_NETWORK_NAME \ + --address-prefix $PRIVATE_ENDPOINTS_SUBNET_CIDR + ``` + +1. Next, disable private endpoint network policies in the subnet you will use to create the private endpoints. + + ```bash + az network vnet subnet update \ + --name $PRIVATE_ENDPOINTS_SUBNET_NAME \ + --resource-group $RESOURCE_GROUP \ + --vnet-name $VIRTUAL_NETWORK_NAME \ + --disable-private-endpoint-network-policies true + ``` + +1. You can now create a private endpoint for the PostgreSQL instance. + + ```bash + POSTGRES_RESOURCE_ID=$(az resource show -g $RESOURCE_GROUP -n $POSTGRES_SERVER_NAME --resource-type "Microsoft.DBforPostgreSQL/flexibleServers" --query "id" -o tsv) + + az network private-endpoint create \ + --name pe-openlab-postgressql \ + --resource-group $RESOURCE_GROUP \ + --vnet-name $VIRTUAL_NETWORK_NAME \ + --subnet $PRIVATE_ENDPOINTS_SUBNET_NAME \ + --private-connection-resource-id $POSTGRES_RESOURCE_ID \ + --group-id postgresqlServer \ + --connection-name openlab-postgresql-connection \ + --location $LOCATION + ``` + + {: .note } + > Once you created the private endpoint, you will set up a private Azure DNS zone named `privatelink.postgresql.database.azure.com` with an `A` DNS record matching the original DNS name with the suffix `postgresql.database.azure.com` but replacing that suffix with `privatelink.postgresql.database.azure.com`. Your apps connecting to the PostgreSQL will not need to be updated, but instead they can continue using the existing connection settings. + + +1. To implement this configuration, start by creating a new private DNS zone and linking it to your virtual network. + + ```bash + az network private-dns zone create \ + --resource-group $RESOURCE_GROUP \ + --name "privatelink.postgresql.database.azure.com" + + az network private-dns link vnet create \ + --resource-group $RESOURCE_GROUP \ + --zone-name "privatelink.postgresql.database.azure.com"\ + --name MyPostgreSQLDNSLink \ + --virtual-network $VIRTUAL_NETWORK_NAME \ + --registration-enabled false + ``` + +1. Next, create a new `A` record pointing to the IP address of the newly created private endpoint. + + ```bash + POSTGRES_NIC_ID=$(az network private-endpoint show --name pe-openlab-postgresql --resource-group $RESOURCE_GROUP --query 'networkInterfaces[0].id' -o tsv) + POSTGRES_NIC_IPADDRESS=$(az resource show --ids $POSTGRES_NIC_ID --api-version 2019-04-01 -o json | jq -r '.properties.ipConfigurations[0].properties.privateIPAddress') + + az network private-dns record-set a create \ + --name $POSTGRES_SERVER_NAME \ + --zone-name privatelink.postgresql.database.azure.com \ + --resource-group $RESOURCE_GROUP + + az network private-dns record-set a add-record \ + --record-set-name $POSTGRES_SERVER_NAME \ + --zone-name privatelink.PostgreSQL.database.azure.com \ + --resource-group $RESOURCE_GROUP \ + -a $POSTGRES_NIC_IPADDRESS + ``` + +1. You can now disable all public access towards your PostgreSQL. + + ```bash + az PostgreSQL flexible-server update \ + --name $POSTGRES_SERVER_NAME \ + --resource-group $RESOURCE_GROUP \ + --public-access Disabled + ``` + +1. You should be able to browse the spring petclinic app and see the data again. + + {: .note } + > Notice that for this change you didn't need to make any changes to your apps, nor did you need to recreate any service connections. + +1. In the Azure Portal navigate to your newly created PostgreSQL Flexible Server and select the `Networking` menu. In the menu you will notice public access is not allowed and the private endpoint is configured on the server. \ No newline at end of file diff --git a/docs/08_lab_private_postgres/0802.md b/docs/08_lab_private_postgres/0802.md new file mode 100644 index 0000000..bf339a9 --- /dev/null +++ b/docs/08_lab_private_postgres/0802.md @@ -0,0 +1,67 @@ +--- +title: '2. Key Vault' +layout: default +nav_order: 2 +parent: 'Lab 8: Secure PostgreSQL database and Key Vault using a Private Endpoint [PostgreSQL]' +--- + +# Lock down the Key Vault instance by using a private endpoint + +Once you have locked down the internet access to the PostgreSQL database, you will apply a private endpoint to the Key Vault as well to protect the Key Vault content. Once you enable it, you can block public access to your Key Vault as well. To accomplish this, you can use the following guidance: + +- [Integrate Key Vault with Azure Private Link](https://docs.microsoft.com/azure/key-vault/general/private-link-service?tabs=cli). + +## Step by step guidance + +1. Since you already created the subnet for the private endpoints, You can directly create a private endpoint for the Key Vault instance. + + ```bash + KEYVAULT_RESOURCE_ID=$(az resource show -g ${RESOURCE_GROUP} -n ${KEYVAULT_NAME} --query "id" --resource-typ "Microsoft.KeyVault/vaults" -o tsv) + + az network private-endpoint create --resource-group $RESOURCE_GROUP \ + --vnet-name $VIRTUAL_NETWORK_NAME \ + --subnet $PRIVATE_ENDPOINTS_SUBNET_NAME \ + --name pe-openlab-keyvault \ + --private-connection-resource-id "$KEYVAULT_RESOURCE_ID" \ + --group-id vault \ + --connection-name openlab-keyvault-connection \ + --location $LOCATION + ``` + + {: .note } + > Once you created the private endpoint, you will set up a private Azure DNS zone named `privatelink.vaultcore.azure.net` with an `A` DNS record matching the original DNS name with the suffix `vaultcore.azure.net` but replacing that suffix with `privatelink.vaultcore.azure.net`. Your apps connecting to the Key Vault will not need to be updated, but instead they can continue using the existing connection settings. This is the same as with the PostgreSQL Server. + +1. To implement this configuration, start by creating a new private DNS zone and linking it to your virtual network. + + ```bash + az network private-dns zone create \ + --resource-group $RESOURCE_GROUP \ + --name "privatelink.vaultcore.azure.net" + + az network private-dns link vnet create \ + --resource-group $RESOURCE_GROUP \ + --zone-name "privatelink.vaultcore.azure.net" \ + --name MyVaultDNSLink \ + --virtual-network $VIRTUAL_NETWORK_NAME \ + --registration-enabled false + ``` + +1. Next, create a new `A` record pointing to the IP address of the newly created private endpoint. + + ```bash + KEYVAULT_NIC_ID=$(az network private-endpoint show --name pe-openlab-keyvault --resource-group $RESOURCE_GROUP --query 'networkInterfaces[0].id' -o tsv) + KEYVAULT_NIC_IPADDRESS=$(az resource show --ids $KEYVAULT_NIC_ID --api-version 2019-04-01 -o json | jq -r '.properties.ipConfigurations[0].properties.privateIPAddress') + + az network private-dns record-set a add-record -g $RESOURCE_GROUP -z "privatelink.vaultcore.azure.net" -n $KEYVAULT_NAME -a $KEYVAULT_NIC_IPADDRESS + az network private-dns record-set list -g $RESOURCE_GROUP -z "privatelink.vaultcore.azure.net" + ``` + +1. You can now disable all public access towards your Key Vault. + + ```bash + az keyvault update \ + --name $KEYVAULT_NAME \ + --resource-group $RESOURCE_GROUP \ + --public-network-access Disabled + ``` + diff --git a/docs/08_lab_private_postgres/0803.md b/docs/08_lab_private_postgres/0803.md new file mode 100644 index 0000000..9a67a8a --- /dev/null +++ b/docs/08_lab_private_postgres/0803.md @@ -0,0 +1,11 @@ +--- +title: '3. Test' +layout: default +nav_order: 3 +parent: 'Lab 8: Secure PostgreSQL database and Key Vault using a Private Endpoint [PostgreSQL]' +--- + +# Test your setup + +As the last step of this exercise and the lab, test your setup again. You should still be able to navigate to your application through the custom domain that you configured on your Application Gateway and view the listing of owners and veterinarians. + diff --git a/docs/08_lab_private_postgres/0804.md b/docs/08_lab_private_postgres/0804.md new file mode 100644 index 0000000..621b313 --- /dev/null +++ b/docs/08_lab_private_postgres/0804.md @@ -0,0 +1,18 @@ +--- +title: '4. Review' +layout: default +nav_order: 4 +parent: 'Lab 8: Secure PostgreSQL database and Key Vault using a Private Endpoint [PostgreSQL]' +--- + +# Review + +In this lab, you implemented a configuration in which PaaS services used by Azure Spring Apps applications accept only connections that originate from within the virtual network hosting these apps. In this lab you + +- Locked down the Azure Database for PostgreSQL Flexible Server instance by redeploying it in a subnet +- Locked down the Key Vault instance by using a private endpoint +- Tested your setup + +The below image illustrates the end state you have build in this lab. + +![lab 8 overview](../../images/acalab8.png) diff --git a/docs/08_lab_private_postgres/08_openlab_private_endpoints_aca.md b/docs/08_lab_private_postgres/08_openlab_private_endpoints_aca.md new file mode 100644 index 0000000..4668dc2 --- /dev/null +++ b/docs/08_lab_private_postgres/08_openlab_private_endpoints_aca.md @@ -0,0 +1,42 @@ +--- +title: 'Lab 8: Secure PostgreSQL database and Key Vault using a Private Endpoint [PostgreSQL]' +layout: default +nav_order: 12 +has_children: true +--- + +# Lab 8: Secure PostgreSQL database and Key Vault using a Private Endpoint + +# Student manual + +## Lab scenario + +You now have your application deployed into a virtual network and the microservices connection requests from the internet must pass through your Application Gateway instance with Web Application Firewall enabled. However, the apps communicate with the backend services, such Azure Database for PostgreSQL Flexible Server and Key Vault via their public endpoints. In this exercise, you will lock them down by implementing a configuration in which they only accept connections that originate from within your virtual network. + +## Objectives + +After you complete this lab, you will be able to: + +- Lock down the Azure Database for PostgreSQL Flexible Server instance by redeploying it in a subnet +- Lock down the Key Vault instance by using a private endpoint +- Test your setup + +The below image illustrates the end state you will be building in this lab. + +![lab 8 overview](../../images/acalab8.png) + +## Lab Duration + +- **Estimated Time**: 60 minutes + +## Instructions + +During this lab, you will: + +- Lock down the Azure Database for PostgreSQL Flexible Server instance by redeploying it in a subnet +- Lock down the Key Vault instance by using a private endpoint +- Test your setup + +{: .note } +> The instructions provided in this exercise assume that you successfully completed the previous exercise and are using the same lab environment, including your Git Bash session with the relevant environment variables already set. + diff --git a/docs/09_lab_messaging/0901.md b/docs/09_lab_messaging/0901.md index c4d39de..b8cc7eb 100644 --- a/docs/09_lab_messaging/0901.md +++ b/docs/09_lab_messaging/0901.md @@ -83,7 +83,7 @@ The connection to the Service Bus needs to be stored in the `spring.jms.serviceb az role assignment create --assignee $SP_ID --scope $SERVICEBUS_ID --role "Azure Service Bus Data Receiver" ``` -1. In the config repository you will need to add the service bus connection information. Replace the contents of the current `application.yml` file with the contents of the [0901_application.yml file](0901_application.yml). The service bus namespace and identity client id will be injected via environment variables. This file includes the following change: +1. In the config repository you will need to add the service bus connection information. Replace the contents of the current `application.yml` file with the contents of the [0901_application.yml file](0901_application.yml) for MySQL and [0901_postgres_application.yml file](0901_postgres_application.yml) for PostgreSQL. The service bus namespace and identity client id will be injected via environment variables. This file includes the following change: - An additional `spring.jms` section after the `spring.sql` section. diff --git a/docs/09_lab_messaging/0901_postgres_application.yml b/docs/09_lab_messaging/0901_postgres_application.yml new file mode 100644 index 0000000..3485cf6 --- /dev/null +++ b/docs/09_lab_messaging/0901_postgres_application.yml @@ -0,0 +1,74 @@ +# COMMON APPLICATION PROPERTIES + +server: + # start services on random port by default + # port: 0 + # The stop processing uses a timeout which provides a grace period during which existing requests will be allowed to complete but no new requests will be permitted + shutdown: graceful + +# embedded database init, supports PostgreSQL too trough the 'PostgreSQL' spring profile +spring: + sql: + init: + schema-locations: classpath*:db/postgres/schema.sql + data-locations: classpath*:db/postgres/data.sql + mode: ALWAYS + jms: + queue: + visits-requests: visits-requests + visits-confirmations: visits-confirmations + servicebus: + enabled: true + namespace: ${SERVICEBUS_NAMESPACE} + pricing-tier: premium + passwordless-enabled: true + credential: + managed-identity-enabled: true + client-id: ${CLIENT_ID} + sleuth: + sampler: + probability: 1.0 + cloud: + config: + # Allow the microservices to override the remote properties with their own System properties or config file + allow-override: true + # Override configuration with any local property source + override-none: true + jpa: + open-in-view: false + hibernate: + ddl-auto: none + +# Spring Boot 1.5 makes actuator secure by default +management.security.enabled: false +# Enable all Actuators and not only the two available by default /health and /info starting Spring Boot 2.0 +management.endpoints.web.exposure.include: "*" + +# Temporary hack required by the Spring Boot 2 / Spring Cloud Finchley branch +# Waiting issue https://github.com/spring-projects/spring-boot/issues/13042 +spring.cloud.refresh.refreshable: false + +# Logging +logging.level.org.springframework: INFO + +# Metrics +management: + endpoint: + metrics: + enabled: true + prometheus: + enabled: true + endpoints: + web: + exposure: + include: '*' + metrics: + export: + prometheus: + enabled: true +eureka: + client: + serviceUrl: + defaultZone: http://discovery-server:8761/eureka/ + instance: + preferIpAddress: true diff --git a/docs/09_lab_messaging/0902.md b/docs/09_lab_messaging/0902.md index 0921d24..6d6323c 100644 --- a/docs/09_lab_messaging/0902.md +++ b/docs/09_lab_messaging/0902.md @@ -51,6 +51,7 @@ In the java-microservices-aca-lab repository's src directory, the `spring-petcli sed -i "s|$APP_NAME|my-service|g" Dockerfile rm spring-petclinic-$APP_NAME-$VERSION.jar ``` +### For MySQL Setup 1. Update the container app to connect to database securely using identity. ```bash @@ -69,6 +70,25 @@ In the java-microservices-aca-lab repository's src directory, the `spring-petcli -c messaging-emulator ``` +### For PostgreSQL Setup + + 1. Update the container app to connect to database securely using identity. + ```bash + EMULATOR_ID=$(az containerapp show \ + --resource-group $RESOURCE_GROUP \ + --name $APP_NAME \ + --query id \ + -o tsv) + + az containerapp connection create Postgres-flexible \ + --connection Postgres_conn \ + --source-id $EMULATOR_ID \ + --target-id $DB_ID \ + --client-type SpringBoot \ + --user-identity client-id=$CLIENT_ID subs-id=$SUBID \ + -c messaging-emulator + ``` + 1. You configured the messaging-emulator with an external ingress. You can go to the portal and check application url for the messaging-emulator container app. ```bash messaging_emulator_FQDN=$(az containerapp show \ diff --git a/docs/09_lab_messaging/09_openlab_messaging_aca.md b/docs/09_lab_messaging/09_openlab_messaging_aca.md index 5c0ac36..dc898f7 100644 --- a/docs/09_lab_messaging/09_openlab_messaging_aca.md +++ b/docs/09_lab_messaging/09_openlab_messaging_aca.md @@ -1,7 +1,7 @@ --- title: 'Lab 9: Send messages between microservices' layout: default -nav_order: 11 +nav_order: 13 has_children: true --- diff --git a/docs/10_lab_reliable_application/10_reliable_java_aca.md b/docs/10_lab_reliable_application/10_reliable_java_aca.md index 58a9448..4df5fe7 100644 --- a/docs/10_lab_reliable_application/10_reliable_java_aca.md +++ b/docs/10_lab_reliable_application/10_reliable_java_aca.md @@ -1,7 +1,7 @@ --- title: 'Lab 10: Build reliable Java application on ACA' layout: default -nav_order: 12 +nav_order: 14 has_children: true --- diff --git a/docs/11_lab_scale/11_openlab_scale_aca.md b/docs/11_lab_scale/11_openlab_scale_aca.md index ff32eab..246d78c 100644 --- a/docs/11_lab_scale/11_openlab_scale_aca.md +++ b/docs/11_lab_scale/11_openlab_scale_aca.md @@ -1,7 +1,7 @@ --- title: 'Lab 11: Set up autoscaling for microservices on ACA' layout: default -nav_order: 13 +nav_order: 15 has_children: true --- diff --git a/images/postgres-enable.png b/images/postgres-enable.png new file mode 100644 index 0000000..b1777a3 Binary files /dev/null and b/images/postgres-enable.png differ