Protect Azure Container Registry build process with ACR Firewall

Ovidiu Borlean
3 min readJan 13, 2024
Photo by Sunder Muthukumaran on Unsplash

Azure Container Registry provides an automatically build process by leveraging the Azure CLI command az acr build. By default, Azure Container Registry does have the Public network access selected on All networks, this might not be compliant with the security policies across organizations.

During the build process, Azure provides a default build agent that will have an outbound connectivity from a public IP address pool on the region where the resources are deployed.

These IP ranges could be found at the following link:

Download Azure IP Ranges and Service Tags — Public Cloud from Official Microsoft Download Center

As the outbound connectivity of the agents are not predictable and could be randomly selected from these pools, protecting the build process in ACR Firewall is not a straightforward task.

Microsoft provides the option of using a dedicated agent pool (https://learn.microsoft.com/en-us/azure/container-registry/tasks-agent-pools) to use in your build operation, these agents will be configured on a existing Virtual Network and will use the outbound connectivity configuration of respective VNet.

Prerequisites:

- Azure Container Registry

- Azure Virtual Network

- Azure CLI

- NATGw — For Vnet outbound connectivity

We create a Virtual Network in West Europe region with an address space of 10.0.0.0/24 and a single subnet (default) having the same address space.

To have available the outbound connectivity for resources deployed in this network, we’ll configure and link a NatGateway resource. It will provide a Public IP address that will be shared by all agents in this subnet.

In the Nat Gateway/Subnet panel, there is the link configured for our testing VNet:

After our NAT Gateway has been successfully deployed and the Public IP address has been associated, we get the respective IP address and configure it in Container Registry/Networking panel:

As we have previous resources successfully deployed, we are ready to create our dedicated agent pool:

az acr agentpool create     --registry <YourRegistryName>  --name  <YourAgendPoolName> --tier S2     --subnet-id /subscriptions/xyz/resourceGroups/ssl/providers/Microsoft.Network/virtualNetworks/acr-vnet/subnets/default.

For testing purpose, we’ll build a sample Python application. These files are required for a successful build:

#app.py

import time
import os
import logging
from flask import Flask, jsonify, request
import subprocess as sp
app = Flask(__name__)
hostName = sp.getoutput("hostname")
logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] %(message)s')
customEndpoint = os.environ.get('FLASK_CUSTOM_ENDPOINT', "/custom")
@app.route(customEndpoint)
def custom():
return "Custom endpoint succeeded\n"
@app.route('/header')
def header():
all_hdr = request.headers
return str(all_hdr)
@app.route('/delay')
def delay():
sleepTime = 5
time.sleep(int(sleepTime))
user_agent = request.headers.get('User-Agent')
url = request.url
logging.info(f"{request.remote_addr} - - [{time.strftime('%d/%b/%Y %H:%M:%S')}] \"{request.method} {url} {request.environ.get('SERVER_PROTOCOL')}\" {user_agent}")
return "Delayed for " + str(sleepTime) + " seconds" + "\n"
@app.route('/healthz')
def healthz():
return "Health check completed V2\n"
@app.route("/")
def hello():
user_agent = request.headers.get('User-Agent')
url = request.url
hdr = request.headers.get('Host')
all_hdr = request.headers
req_ip = request.remote_addr
logging.info(f"{request.remote_addr} - - [{time.strftime('%d/%b/%Y %H:%M:%S')}] \"{request.method} {url} {request.environ.get('SERVER_PROTOCOL')}\" {user_agent}")
return_values = str(all_hdr) + url + "\n" + req_ip + "\n" + hostName + "\n"
return return_values
if __name__ == "__main__":
listenerPort = os.environ.get('FLASK_LISTENER', "8080")
print(listenerPort)
app.run(host='0.0.0.0', port=int(listenerPort))
#---requirements.txt
Flask
#---Dockerfile
FROM python:3.11-slim
ENV PORT 8000
EXPOSE 8000
WORKDIR /usr/src/app

COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

ENTRYPOINT ["python"]
CMD ["app.py"]

Initiating the build process with the Azure CLI. Please note the –agen-pool flag that needs to be added in order to use our newly created dedicated pool.

az acr build — agent-pool customagent — image test:{{.Run.ID}} — registry sslovidiu .

We have successfully build and pushed an image in our Container Registry with a strict networking rule to prevent access to our registry from other endpoints.

--

--