Exercise - Restrict access to the Azure Container Apps environment

Completed

In this unit, you ensure that the PostgreSQL database can be accessed only by the Quarkus application, and not by other external clients. You can currently access the database from any client by using Azure CLI and running Quarkus locally. This configuration isn't secure. You need to add a firewall rule to allow only IP addresses within the Azure Container Apps environment to access the database server.

Access the PostgreSQL server by using the CLI

First, make sure you can access the PostgreSQL server by using the Azure CLI. To do that, run this command:

az postgres flexible-server execute \
    --name "$AZ_POSTGRES_SERVER_NAME" \
    --database-name "$AZ_POSTGRES_DB_NAME" \
    --admin-user "$AZ_POSTGRES_USERNAME" \
    --admin-password "$AZ_POSTGRES_PASSWORD" \
    --querytext "select * from Todo" \
    --output table

You should be able to see the content of the database. If you can, the database can be accessed outside of the environment.

Remove the permissive firewall rule

Azure Database for PostgreSQL provides security by default. Its firewall usually doesn't allow incoming connections. But when you created the PostgreSQL server, you specified the --public-access "All" parameter to enable external access, which configured the firewall to be open to the public.

You can list the existing firewall rules by running this command:

az postgres flexible-server firewall-rule list \
    --name "$AZ_POSTGRES_SERVER_NAME" \
    --resource-group "$AZ_RESOURCE_GROUP" \
    --output table

You should see the following output:

EndIpAddress     Name                       ResourceGroup            StartIpAddress
---------------  -------------------------  -----------------------  ----------------
255.255.255.255  AllowAll_2023-1-3_10-20-4  rgazure-deploy-quarkus  0.0.0.0

Notice that the range of allowed IP addresses is 0.0.0.0 through 255.255.255.255. A firewall rule like this allows any client to access the database. To ensure that only the Quarkus application can access the database, you need to update the firewall rules of the PostgreSQL server. In this case, it's just a matter of removing the public rule. To remove it, run the following command:

az postgres flexible-server firewall-rule delete \
    --name "$AZ_POSTGRES_SERVER_NAME" \
    --resource-group "$AZ_RESOURCE_GROUP" \
    --rule-name <name of the AllowAll firewall rule> \
    --yes

Now try to query the database by running a SQL statement from the CLI:

az postgres flexible-server execute \
    --name "$AZ_POSTGRES_SERVER_NAME" \
    --database-name "$AZ_POSTGRES_DB_NAME" \
    --admin-user "$AZ_POSTGRES_USERNAME" \
    --admin-password "$AZ_POSTGRES_PASSWORD" \
    --querytext "select * from Todo" \
    --output table

The call eventually times out. You should see this message:

Unable to connect to flexible server: connection to server failed: Operation timed out

Because you removed all the firewall rules, now even the Quarkus application can't access the database. If you try to retrieve the to-dos from the database, the request fails. Run the following cURL request:

curl https://$AZ_APP_URL/api/todos

Add a new firewall rule

You need to configure the firewall to allow access to only the Quarkus application. You need to add a new firewall rule. To add the rule, run this command:

az postgres flexible-server firewall-rule create \
    --name "$AZ_POSTGRES_SERVER_NAME" \
    --resource-group "$AZ_RESOURCE_GROUP" \
    --rule-name "Allow_Azure-internal-IP-addresses" \
    --start-ip-address "0.0.0.0" \
    --end-ip-address "0.0.0.0"

Setting the start-ip-address and the end-ip-address to 0.0.0.0 allows access from all Azure-internal IP addresses but doesn't allow access from external IP addresses. This practice helps to secure the database from external access.

If you try to access the database from the CLI by running the following command, the attempt should fail:

az postgres flexible-server execute \
    --name "$AZ_POSTGRES_SERVER_NAME" \
    --database-name "$AZ_POSTGRES_DB_NAME" \
    --admin-user "$AZ_POSTGRES_USERNAME" \
    --admin-password "$AZ_POSTGRES_PASSWORD" \
    --querytext "select * from Todo" \
    --output table

But if you try use the following command to retrieve the to-dos from the database via the Quarkus application that's running on Container Apps, the attempt succeeds:

curl https://$AZ_APP_URL/api/todos

This command returns the list of all to-do items from the database. The PostgreSQL server can be accessed from the Quarkus application that's running on an Azure service, but it can't be accessed from outside of Azure.