Control network access
I often got the question regarding how to secure the public access to Azure Container Registry (ACR). ACR already provides several features for advanced network access control. For example, you can disable public access and only allow the requests from certain Public IP ranges. However, the built-in network features have some limits like it only allows 100 IP network rules. If you need to filter the requests based on geo-location, Azure Application Gateway (AG) is a viable option.
Azure Application Gateway Web Application Firewall (WAF) v2 not only allows you to create custom rules like Geomatch but also protects the ACR from common vulnerabilities and exploits. You can also set up custom domain for the original ACR instance (NOTE: ACR has a preview feature to set up custom domain for your registry).
Put into action
To demonstrate the end-to-end, I am going to build a public registry registry.writeinseattle.com
on top of a private ACR testpeacrwestus3.azurecr.io
. I will push new image to testpeacrwestus3.azurecr.io
from my local network. The clients from United States will be able to pull the image from registry.writeinseattle.com
but the requests from other location will be blocked. The diagram shows the high-level network architecture.
┌─────────────────────────────────────────┐
│ │
│ Virtual Network │
│ │
│ ┌────────────────────┐ │
│ │ │ │
┌───────────┐ │ │ │ │
│ │ │ │ Application │ │ ┌────────────────────────┐
│ Internet ├─────┼───► Gateway │ ┌────────────┐ │ │ │
│ │ │ │ │ │ │ │ │ │ │
└───────────┘ │ │ └────────────┼─► ACR │ │ │Azure Container Registry│
│ │ │ │ Private ├─┼─────► │
│ └────────────────────┘ │ Endpoint │ │ │ │
│ └────────────┘ │ └────────────────────────┘
│ │
└─────────────────────────────────────────┘
To start, I first create the ACR testpeacrwestus3.azurecr.io
in Azure westus3
region and disable the public access. I also enable anonymous pull access on the registry. I then create a virtual network with two subnets, one for ACR private endpoint and the other for AG. Once I create the ACR private endpoint in the subnet, I get two endpoints https://testpeacrwestus3.azurecr.io
(a.k.a login endpoint) and https://testpeacrwestus3.westus3.data.azurecr.io
(a.k.a data endpoint).
Next, I create the AG (WAFv2) in another subnet. To allow clients to pull image from registry.writeinseattle.com
, I need to set up two HTTPS
listeners on AG. The listener of https://registry.writeinseattle.com
forwards the requests to the backend pool targeting https://testpeacrwestus3.azurecr.io
. The listener of https://registry.westus3.data.writeinseattle.com
forwards the requests to the backend pool targeting https://testpeacrwestus3.westus3.data.azurecr.io
. For Health probes, choose HTTPS
Protocol and /health
PATH.
After setting up the routing rules, I need to configure two response rewrite rules to redirect the client to the desired AG endpoints.
-
Registry clients follow the auth flow to parse
WWW-Authenticate
header from401 Unauthorized response
to figure out the request payload to acquire the token. The header value is something likeWww-Authenticate: Bearer realm="https://testpeacrwestus3.azurecr.io/oauth2/token",service="testpeacrwestus3.azurecr.io",scope="repository:hello-world:pull"
. I need to create a rule to rewriterealm="https://testpeacrwestus3.azurecr.io/oauth2/token"
torealm="https://registry.writeinseattle.com/oauth2/token"
. Here is the sample rule setting.If: Service variable/http_status equal (=) 401 And If: HTTP header/Response Header/WWW-Authentication equal (=) (Bearer realm=.https:\/\/)testpeacrwestus3\.azurecr\.io(.*)$ Then: Response Header Set WWW-Authentication {http_resp_WWW-Authenticate_1}registry.writeinseattle.com{http_resp_WWW-Authenticate_2}
-
When registry clients request to download image layers, ACR returns
307 Redirect response
that includeslocation
header to redirect clients to the data endpoint. I need to create a rule to rewritelocation=https://testpeacrwestus3.westus3.data.azurecr.io/...
tolocation=https://registry.westus3.data.writeinseattle.com/...
. Here is the sample rule setting.If: Service variable/http_status equal (=) 307 And If: HTTP header/Response Header/Location equal (=) (https:\/\/)testpeacrwestus3\.westus3\.data\.azurecr\.io(.*)$ Then: Response Header Set Location {http_resp_Location_1}registry.westus3.data.writeinseattle.com{http_resp_Location_2}
Finally, I add the Geomatch rule in Application Gateway WAF policy to only allow clients from United States to pull image from registry.writeinseattle.com
(NOTE: the default mode for new created policy is detection
, I need to remember to switch to prevention
mode to put into effect).
Conclusion
If you are in United States, you can try to pull a sample hello-world image docker pull registry.writeinseattle.com/hello-world:latest
. Hope you find the article is useful =).