Running Nginx in AWS Nitro
Nginx is a good example of an application that would benefit from running in an AWS Nitro Enclave. In a production environment, it needs to have access to sensitive data (the TLS certificate), and it can serve web applications that connect to other services. Being able to completely isolate and protect the Nginx application from malicious users (even those who might have elevated privileges to the parent instance) is very valuable.
In this example, you simplify the setup and ignore the TLS configuration. You will focus on running Nginx as an HTTP server and configure the AWS Nitro Enclave to allow HTTP clients to connect to Nginx, even though Nginx is running in the AWS Nitro Enclave.
The steps to run Nginx in an enclave are similar to the ones in the previous section, except that there a couple of new steps (indicated in bold):
-
identify a Docker image that contains an application,
-
convert the Docker image into an Enclave Image File (EIF),
-
configure the network interfaces on the parent instance
-
start the Anjuna Nitro Network Proxy
-
start an AWS Nitro Enclave using the previously created Enclave Image File.
For Nginx to be able to communicate with clients outside the enclave,
the anjuna-nitro-netd-parent
is used to forward the network traffic to/from the enclave.
This communication is done through the only data-exchange interface available in AWS Nitro,
the vsock
interface.
Without this daemon,
the enclave would not have a method to send/receive data from clients that are not in the enclave.
On this virtual interface, the enclave and the parent instance are assigned the same IP address.
When anjuna-nitro-netd-parent
is running,
the parent instance can communicate with the enclave using localhost
.
For example, requests to localhost:80
on the parent instance are directed to the application
listening on port 80 inside the enclave.
In this example, you will start an Nginx server in the enclave,
which is configured to listen on port 80 (HTTP).
You will then verify that the Nginx server is running by sending a curl
command
from the parent instance.
Identify a simple Docker image
You will use the official Nginx Docker image on Docker Hub.
Build an enclave image file (EIF)
Since the Docker image is already built and published in Docker Hub, you can convert it into an Enclave Image File.
If you have not already done so, use your license
by putting the license file at /opt/anjuna/license.yaml
.
Then, run the following command to automatically pull the Nginx Docker image from Docker Hub and convert it into an EIF.
$ anjuna-nitro-cli build-enclave --docker-uri nginx:latest --output-file nginx.eif
Start the Anjuna Nitro Network Proxy
Run the following command:
$ anjuna-nitro-netd-parent --enclave-name nginx --expose 80 --daemonize
This command is responsible for moving the network packets between the AWS Nitro Enclave and the parent instance, and must be running for the enclave to communicate with the outside world.
If your application exposes multiple ports (for example port 80 and port 8080),
you can use the --expose
parameter multiple times.
The enclave name is a user-provided
identifier that the Anjuna Nitro Runtime uses to connect running enclaves with supporting services
(networking, persistent storage, etc).
It is important that the same enclave name is provided to the network proxy and to the run-enclave command
described below, or the enclave will not work as expected.
|
This command starts the Anjuna Nitro Network Proxy as a background process. If you need to expose a different set of ports, you need to kill the Network Proxy process and run it again with the new set of ports. For example, to expose both port 80 and 443, run the following command:
$ pkill -f 'anjuna-nitro-netd-parent --enclave-name nginx' (1)
$ anjuna-nitro-netd-parent --enclave-name nginx --expose 80 --expose 443 --daemonize
1 | stops the proxy exposing just port 80 |
If the enclave is running and you want to expose additional ports, you will need to terminate the enclave before killing the Network Proxy process. |
Make sure that you kill the correct Network Proxy process that was launched with the same enclave name that your Nginx enclave will use. |
Start the AWS Nitro Enclave
$ anjuna-nitro-cli run-enclave --enclave-name nginx --cpu-count 2 --memory 1024 --eif-path nginx.eif --debug-mode
The number of vCPU cores must be an even number due to hyperthreading. |
Verify that Nginx is running
$ curl localhost:80
You should see the following output:
<!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 AWS Nitro Enclave.
Exposing the AWS Nitro Enclave to external hosts
In the previous section, you started an AWS Nitro Enclave running Nginx and connected
to it from the parent instance, using the IP address localhost
.
In a typical scenario, Nginx should be reachable from other hosts:
-
If the AWS Nitro parent instance is on an AWS VPC, other hosts on this VPC might try to connect to Nginx.
-
This AWS Nitro parent instance might be reachable from the internet (your web browser for example).
Whenever you terminate an AWS Nitro Enclave, you should also terminate its Network Proxy to clean up its resources. Run the following commands to terminate and restart the AWS Nitro Enclave running Nginx and the Network Proxy. Nginx will become reachable through the host’s external IP address.
$ anjuna-nitro-cli terminate-enclave --enclave-name nginx
$ pkill -f 'anjuna-nitro-netd-parent --enclave-name nginx'
$ anjuna-nitro-netd-parent --enclave-name nginx --expose 80 --daemonize
$ anjuna-nitro-cli run-enclave --enclave-name nginx --cpu-count 2 --memory 1024 --eif-path nginx.eif --debug-mode
This is only an example for going through this tutorial. In most cases, you should never expose the port 80 to serve HTTP content, and you should use TLS on port 443. In that case, the command will become:
|
Run the following command on another host (replace <nitro-instance-ip> with the actual IP address of your AWS Nitro parent instance):
$ curl <nitro-instance-ip>:80
You might need to update the security rules (inbound rules) to allow traffic to be accepted by the AWS Nitro host. |