This project includes an example of an ASP.NET based REST API deployed as an Azure Container Instance (ACI) with TLS support, with the TLS certificates hosted in an Azure File Share.
Table of Contents:
Azure Container Isntances is a service that allows you to spin up containerized workloads fast, without managing VMs. This sample project demonstrates how you use an Azure Container Registry to build, publish, and eventually deploy a container to an Azure Container Instance with a TLS certificate that's hosted on an Azure File Share.
This example makes use of an ASP.NET application running on a Linux-based container, loading the certificate data programmatically using a simple volume mount from a File Share, as diagrammed below:
A few notes:
- The .NET application assumes an RSA-signed TLS certificate. You can modify the example here to match whichever encryption algorithm you prefer (e.g., AES instead of RSA).
- As called out in the Azure documentation one specific limitation of the File Share volume method is that at the moment, it requires your container's runtime to run as root.
If you don't yet have a TLS certificate and a private key, use the following steps to generate them.
You can do that easily with openssl
, as demostrated below.
First, generate a new private key:
openssl req -new -newkey \
rsa:2048 -nodes \
-keyout aci_tls_pk.key \
-out aci_tls_cr.csr
Then generate a certificate signed by the key you generated above. Note that you'll be prompted to enter the certificate's data:
openssl x509 -req -days 365 \
-in aci_tls_cr.csr \
-signkey aci_tls_pk.key \
-out aci_tls_cert.crt
You should now have three new files in your current directory:
aci_tls_cr.csr
: Certificate request fileaci_tls_pk.key
: The RSA private key that signs your TLS certificateaci_tls_cert.crt
: The TLS certificate
This resource will guide you through the create of a Storage Account and File Share to be mounted on and used by your Container Instance.
Below you can find a summary of the steps you can take to create them:
# $ACI_STORAGE_ACCOUNT_NAME = Desired storage account name
az storage account create \
--resource-group ${RESOURCE_GROUP} \
--name ${ACI_STORAGE_ACCOUNT_NAME} \
--location ${LOCATION} \
--sku Standard_LRS
Next, create a Storage Share to be used by your Container Instance:
az storage share create \
--name ${ACI_SHARE_NAME} \
--account-name ${ACI_STORAGE_ACCOUNT_NAME}
Finally, upload your TLS certficate (aci_tls_cert.crt
) and its signing private key (aci_tls_pk.key
).
You can refer to this guide
for instructions to use the Azure CLI to copy files from your host onto the Azure File Share.
PLEASE NOTE: This command assumes Docker is installed on the machine on which you're building the container image.
First, you'll have to build the container image. You can do so locally by running the following command:
make build
You can verify the image has been built successfully by running docker images
. You should see
a line indicating that the aci-demo
is present in your Docker daemon, e.g.:
REPOSITORY TAG IMAGE ID CREATED SIZE
aci-demo latest bb5badacc01e 8 seconds ago 104MB
Before you can interact with your ACR repo using your local Docker environment, you will need to log into ACR:
# ACR_REG_NAME is a placeholder for the name of your ACR registry
az acr login --name ${ACR_REG_NAME}
After a successful login, you will be able to interact with the ACR registry via your Docker daemon.
PLEASE NOTE:
It is highly advisable to use a Managed Identity instead of a Service Principle. Consider creating a Managed Identity for ACI to pull images from your ACR registry.
This section outlines the steps you should take to create a service principal that allows Azure Container Instances (ACI) to pull images from your Azure Container Registry (ACR).
Find out in this documentation page.
PLEASE NOTE:
You may require to enable the ACI provider in your subscription on new subscriptions. See more information here.
az container create \
--subscription ${SUBSCRIPTION_ID} \
--resource-group ${RESOURCE_GROUP} \
--name ${ACI_NAME} \
--image ${REPO_NAME}/${IMAGE_NAME}:${IMAGE_TAG} \
--registry-username ${SERVICE_PRINCIPAL_ID} \
--registry-password ${SERVICE_PRINCIPAL_PASSWORD} \
--dns-name-label ${ACI_NAME} \
--ports 443 \
--azure-file-volume-account-name ${ACI_STORAGE_ACCOUNT_NAME} \
--azure-file-volume-account-key ${STORAGE_KEY} \
--azure-file-volume-share-name ${ACI_SHARE_NAME} \
--azure-file-volume-mount-path /tls-cert/
Let's unpack the command above:
- The command tells the Azure CLI to pull the container's image
from ACR, where
${REPO_NAME}/${IMAGE_NAME}:${IMAGE_TAG}
is the format of the full image, e.g.,acitls01.azurecr.io/aci-tls-01:latest
- Provide the registry credentials based on the principal ID and password
from step 4 of the process. Please note that if you used a Managed Identity
(highly recommended), you can omit the
registry-username
andregistry-password
parameters. - Provide the Azure File Share credentials and the path on the container where the file share will be mounted.
Should everything work as expected, you should be able to submit a cURL
request
to the API. For instance, if the FQDN for your container instance is
aci-tls-example.eastus.azurecontainer.io
, you can run the following command
to test the API:
# -s for a silent output
# -k to ignore TLS verification, since our certificate is self-signed
curl -X GET \
-s \
-k \
https://aci-tls-example.eastus.azurecontainer.io/weatherForecast
The result can look like the following JSON object:
[
{
"date": "2022-03-23T10:05:32.330176+00:00",
"temperatureC": 21,
"temperatureF": 69,
"summary": "Bracing"
},
{
"date": "2022-03-24T10:05:32.3301861+00:00",
"temperatureC": -15,
"temperatureF": 6,
"summary": "Sweltering"
},
{
"date": "2022-03-25T10:05:32.3301866+00:00",
"temperatureC": 45,
"temperatureF": 112,
"summary": "Mild"
},
{
"date": "2022-03-26T10:05:32.3301867+00:00",
"temperatureC": -4,
"temperatureF": 25,
"summary": "Bracing"
},
{
"date": "2022-03-27T10:05:32.3301877+00:00",
"temperatureC": -19,
"temperatureF": -2,
"summary": "Freezing"
}
]