Running Nginx in an Anjuna Confidential Container
In this section, you will run a simple confidential container in a secure enclave with the Anjuna CLI. Starting from the Docker container for Nginx, you will configure and run an Anjuna Confidential Container, verify it is using AMD SEV, and inspect its measured boot values.
The following basic steps are needed to start an Anjuna Confidential Container:
-
Identify a Docker image that contains an application
-
Build the Docker image into a CSP compatible disk image for an Anjuna Confidential Container
-
Upload the disk image to the CSP’s storage
-
Start an Anjuna Confidential Container using the previously created disk image
Using the Anjuna CLI, you can automatically start existing containers in an Azure Confidential VM. This documentation refers to these as Anjuna Confidential Containers.
Depending on the application, these additional steps may be needed:
-
Configure the network and firewall rules for the Anjuna Confidential Container
-
Check the SEV attestation report and Measured Boot output to ensure that the Confidential VM has not been tampered with
In this section, you will learn about the basic usage of the Anjuna CLI to build and run an Anjuna Confidential Container.
Identify a Simple Docker Image
You will use the official Nginx Docker image to start a simple web server as an Anjuna Confidential Container.
To simplify the setup in this example, there is no TLS configuration. Instead, you will run Nginx as an HTTP server and learn how to configure the Anjuna Confidential Container to allow HTTP clients to connect to Nginx.
Build the Anjuna Confidential Container disk image
The Anjuna CLI works with unmodified Docker images.
In this example, the Anjuna CLI will pull the Nginx Docker image from the public Docker Hub.
If you are using a private Docker registry,
use the docker login
command to authenticate to your registry before running the following command.
-
Microsoft Azure
$ anjuna-azure-cli disk create --docker-uri=nginx:latest --disk-size 20G
This command will create a disk image file named disk.vhd
in the current working directory.
The disk image contains a bootloader that starts a Linux kernel that boots
directly into the Nginx application, as defined by the ENTRYPOINT
and CMD
parameters of the Docker container.
All the dependencies needed to run Nginx are included in the disk image, so when the Confidential VM starts, it will not need to download the Docker image.
Upload the disk image
In order to create an Anjuna Confidential Container, the disk image must be uploaded to the cloud provider first. This may require pre-existing cloud resources.
Disk upload prerequisites
-
Microsoft Azure
This section requires being authenticated to your Microsoft Azure subscription with the Azure CLI (az ).
See Install and authenticate to your cloud provider’s CLI
for reference.
|
The following command displays your account and subscription,
then sets an environment variable to the subscription for later use.
If you have multiple subscriptions, you will need to select the correct one (use az account list
to see your accounts).
$ az account show
$ export MY_AZURE_SUBSCRIPTION=$(az account show -o json | jq -r .id)
You will need to have the following resources ready before you issue the anjuna-azure-cli disk upload
command.
The anjuna-azure-cli
command does not create the resources.
-
Resource Group: This command will create a resource group called
myResourceGroup
$ az group create --name myResourceGroup --location eastus
-
Storage Account: The command below creates a storage account named
anjunaquickstart<SUFFIX>
in the resource groupmyResourceGroup
, with public access disabled to the blobs or containers in the account.$ export RANDOM_SUFFIX=$(cat /dev/urandom | LC_ALL=C tr -dc "[:lower:]" | head -c 10) $ export STORAGE_ACCOUNT_NAME="anjunaquickstart${RANDOM_SUFFIX}" $ az storage account create \ --resource-group myResourceGroup \ --allow-blob-public-access false \ --name ${STORAGE_ACCOUNT_NAME}
-
Storage Container: A storage container is similar to a directory and is used to organize data blobs. It is created inside a storage account. Hierarchically,
resource group → storage account → storage container → blob (disk)
The command shown below creates a storage container called
mystoragecontainer
in the storage account from above:$ az storage container create \ --name mystoragecontainer \ --account-name ${STORAGE_ACCOUNT_NAME} \ --resource-group myResourceGroup
-
Azure Compute (Shared Image) Gallery: Image galleries are used to organize and share OS images and applications.
The command below will create a gallery called
myGallery
in the resource group calledmyResourceGroup
.$ az sig create --resource-group myResourceGroup --gallery-name myGallery
Refer to Creating a Compute Gallery for more details.
-
Image Definition: Image definitions are a logical grouping for versions of an image. Hierarchically,
resource group → image gallery → image definition → image (for the confidential container)
The command below will create an image definition called
myFirstDefinition
inmyGallery
. This document explains the options used in the command.$ az sig image-definition create \ --resource-group myResourceGroup \ --gallery-name myGallery \ --gallery-image-definition myFirstDefinition \ --publisher Anjuna \ --offer CVMGA \ --os-type Linux \ --sku AnjGALinux \ --os-state specialized \ --features SecurityType=ConfidentialVMSupported \ --hyper-v-generation V2 \ --architecture x64
Anjuna requires the following settings. The other parameters for the definition can be configured as needed.
Architecture: "x64" Features: { SecurityType: "ConfidentialVmSupported" } HyperVGeneration: "V2" OsState: "Specialized" OsType: "Linux"
After you have created the necessary cloud resources, you can upload the disk image.
-
Microsoft Azure
This command uploads the local disk image to an Azure Storage Container and creates a shared image in a Compute Gallery. The shared image is saved as an Image Version of a pre-existing Image Definition.
$ anjuna-azure-cli disk upload \
--disk disk.vhd \
--image-name nginx-disk.vhd \
--storage-account ${STORAGE_ACCOUNT_NAME} \
--storage-container mystoragecontainer \
--resource-group myResourceGroup \
--image-gallery myGallery \
--image-definition myFirstDefinition \
--image-version 0.1.0 \
--location eastus \
--subscription-id ${MY_AZURE_SUBSCRIPTION}
Create a network with the proper firewall rules
You will need to update the Anjuna Confidential Container’s cloud network configuration to make it reachable through the internet from your management host.
-
Microsoft Azure
The example below shows one way to create network resources in order to be able to communicate using TCP over port 80.
It also attaches a public IP address to the Network Interface called myNic
.
$ # Replace these with your own values as needed
$ export RESOURCE_GROUP_NAME="myResourceGroup"
$ export LOCATION="eastus"
$ export VNET_NAME="myVnet"
$ export SUBNET_NAME="mySubnet"
$ export NSG_NAME="myNSG"
$ export PUBLIC_IP_NAME="myPublicIP"
$ export NIC_NAME="myNic"
$ # Create a Virtual Network, Subnet, an
$ az network vnet create --resource-group ${RESOURCE_GROUP_NAME} --location ${LOCATION} --name ${VNET_NAME} --address-prefix 10.0.0.0/16
$ # Create a Subnet
$ az network vnet subnet create --resource-group ${RESOURCE_GROUP_NAME} --vnet-name ${VNET_NAME} --name ${SUBNET_NAME} --address-prefixes 10.0.0.0/24
$ # Create a Network Security Group
$ az network nsg create --resource-group ${RESOURCE_GROUP_NAME} --name ${NSG_NAME}
$ # Create a Security Rule allowing TCP traffic over port 80
$ az network nsg rule create --resource-group ${RESOURCE_GROUP_NAME} --nsg-name ${NSG_NAME} --name Allow-80 --protocol Tcp --direction Inbound --priority 1000 --source-address-prefix '*' --source-port-range '*' --destination-address-prefix '*' --destination-port-range 80 --access Allow
$ # Associate the Network Security Group with the Subnet
$ az network vnet subnet update --resource-group ${RESOURCE_GROUP_NAME} --vnet-name ${VNET_NAME} --name ${SUBNET_NAME} --network-security-group ${NSG_NAME}
$ # Create a Public IP address
$ az network public-ip create --resource-group ${RESOURCE_GROUP_NAME} --name ${PUBLIC_IP_NAME} --sku Basic
$ # Create a Network Interface with the Public IP address
$ az network nic create --resource-group ${RESOURCE_GROUP_NAME} --name ${NIC_NAME} --vnet-name ${VNET_NAME} --subnet ${SUBNET_NAME} --network-security-group ${NSG_NAME} --public-ip-address ${PUBLIC_IP_NAME}
Controlling log access
The Anjuna CLI for SEV supports cloud logging, which may need additional configuration.
-
Microsoft Azure
Currently, the Anjuna CLI for SEV on Azure supports logging to the Azure Serial Console.
The Anjuna CLI already handles the configuration required for the Anjuna Confidential Container to write logs to the Azure Serial Console.
Additionally, when the --storage-account
parameter is provided to the instance create
command,
the Azure boot diagnostics are written to that storage account.
To control access to the Serial Console logs, see Prerequisites to access the Azure Serial Console and Configure Azure Storage firewalls and virtual networks.
Start the Anjuna Confidential Container
Run the following command to start the Anjuna Confidential Container on a new instance.
-
Microsoft Azure
The following command uses the cloud resources created in Disk upload prerequisites. You may need to change the parameter values if you chose different names. |
$ export INSTANCE_NAME=anjuna-azure-nginx-instance
$ anjuna-azure-cli instance create \
--name ${INSTANCE_NAME} \
--location eastus \
--image-gallery myGallery \
--image-definition myFirstDefinition \
--image-version 0.1.0 \
--resource-group myResourceGroup \
--storage-account ${STORAGE_ACCOUNT_NAME} \
--nics myNic
Verify that the Nginx Confidential VM is running
Once the instance create
command completes,
your Anjuna Confidential Container will be running.
You can run the following command to see its status:
-
Microsoft Azure
$ anjuna-azure-cli instance describe \
--name ${INSTANCE_NAME} \
--resource-group myResourceGroup
The command should produce output similar to this:
Name ResourceGroup PowerState PublicIps Fqdns Location Zones --------------------------- ------------------ -------------- --------------- ------- ---------- ------- anjuna-azure-nginx-instance myResourceGroup VM Running 172.171.202.232 eastus
Verify that Nginx is running
Using the IP address of the Anjuna Confidential Container, make a request to Nginx:
-
Microsoft Azure
$ export IP_ADDRESS=$(anjuna-azure-cli instance describe \
--resource-group myResourceGroup --name ${INSTANCE_NAME} \
--json --query publicIps | grep -oE "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" | awk 'NR==1')
$ curl ${IP_ADDRESS}:80
You should see HTML output similar to the following:
<!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>
Congratulations! Nginx is running and is accessible from outside the Anjuna Confidential Container.
View application logs
Once the application is running, you can view its logs using the Anjuna CLI.
-
Microsoft Azure
You can tail the application logs with the following command:
$ anjuna-azure-cli instance log --tail \
--name ${INSTANCE_NAME} \
--resource-group myResourceGroup
You can also use the Azure Portal to view the Serial Console.