These days more and more web applications are being migrated into containers. While this is generally a good idea which increases security (if done right), it is creating some new challenges regarding the protection with a web application firewall (WAF). As long as you run the containers in your own network, you can still use the existing WAF in your network to handle the traffic. But when you deploy the containers in the cloud this will not work anymore. The cloud providers do provide some basic WAF functionality which you can enable (generating additional costs) but this does not really compete with a full blown WAF yet. The good thing is, that Fortinet was the first vendor which released a Docker image for its FortiWeb product. In this post I am going to show you how you can deploy a FortiWeb with Docker to protect your containerized web application.
What is a FortiWeb?
FortiWeb is the web application firewall in the product portfolio of Fortinet. Since they released the product a few years back it has done an amazing journey and is now a leader in the market (Gartner) and independent tests from NSS labs show, that the product is very capable to protect web applications from various attacks while not impacting their performance. You can get a FortiWeb in different flavors, starting with hardware appliances, virtual machines, images for all of the leading public cloud providers and nowadays even as a Docker image.
Dockerized web application
To show you how stuff works I have deployed a DVWA (damn vulnerable web application) in a Docker environment. DVWA is an application created to demonstrate various vulnerabilities in web applications. The app is vulnerable to all of the OWASP top 10 web vulnerabilities. To dockerize the app I have created the following docker-compose.yml file. I have used Docker-Compose to orchestrate the application, obviously you can use any other solution like Kubernetes or anything else. On the right side is a schema of the application.
As you can see, the application consists out of 3 containers so far. A nginx webserver which is serving the static files of the application and exposes port 80 (HTTP) to the outside world. Nginx is talking to a PHP container which is handling all of the PHP files and serves them back to nginx. Finally, the app needs a MySQL database here I used a MariaDB container. There are two persistent volumes which contain the files of the DVWA application and the database. Additionally, the nginx container needs some configuration file so it knows what it should do.
When I bring up the containers on my local machine, I can afterwards access the app via http://localhost. The first time you need to setup the database connection and after that you can login to the DVWA application (Username: admin / Password: password).
Now let’s run some code and SQL injection on the site to show that it is actually vulnerable.
Go to the “Command Injection” page and enter something like “1.1.1.1; cat /etc/passwd” or any other command you like.
Also run some SQL injection on the “SQL Injection” page. Enter “%‘ and 1=0 union select null, concat(user,‘:‘,password) from users #” as the UserID. It will give us back all of the users with their password for the app.
We have proven that the app is vulnerable and now we are going to protect it with our WAF. Obviously in the real world you would also fix the issues in the application itself :-).
Build and deploy the FortiWeb Docker Image
Now we are going to deploy the FortiWeb before the nginx container. The FortiWeb will act as reverse proxy filtering out all of the evil stuff and forwarding only the good requests to the nginx. To do that, we need to stop exposing port 80 to the nginx container and assign that port to the FortiWeb container. You can see our new schema below.
As you can see I have added some more exposed ports. We could use the FortiWeb to serve the application with SSL (tcp/443) if we want. I also added the port 8443 and 8022 so that I can manage the FortiWeb. This is only for the initial configuration, when we deploy the web application we should remove these ports to reduce the attack surface.
I have also added two more persistent volumes to store the data and logs of the FortiWeb.
First we have to build our fortiweb Docker image. When we download the FortiWeb docker release from the Fortinet Support-Portal, we will get a Dockerfile and some filesystems along with it.
Let’s build the image with: docker build –t fortiweb .
Then we will change our docker-compose.yml file and add the FortiWeb to it. We add the following service and remove the exposed port from nginx.
fortiweb: container_name: 'fortiweb' build: ./image-docker-64 image: 'fortiweb' restart: always environment: - FWB_ADMIN_PASSWORD=password volumes: - fortiweb-data:/data - fortiweb-log:/var/log ports: - "80:80" - "443:443" - "8443:43" - "8022:22" networks: - dvwa-network
To bring up our app with the FortiWeb in front of it, run „docker-compose up –d“.
We should be able to access our FortiWeb Admin-Webinterface via https://localhost:8443. Login with admin user and the password you specified in the docker-compose file.
Now we need to configure the FortiWeb, so it is acting as reverse proxy and protecting our web application. I have created a policy which is listening on port 80 and forwarding requests to the nginx container. Please note that I have added the builtin „Inline High Level Security“ profile to the policy which should stop all attacks.
As soon as the policy is in place, I am able again to connect to the web application via http://localhost. The app looks exactly the same but if I try the SQL Injection or any other vulnerability, I get blocked by the FortiWeb.
And in the logs of the FortiWeb I can also see that an attack was blocked.
The containerized web application is now protected by the FortiWeb WAF! After everything is tested you can deploy your setup to production. If it is possible you should also deploy the persistent volume (fortiweb-data) along with it since it contains the whole configuration and other data. If you cannot deploy the whole volume, you can extract the configuration from the volume under „/data/config/“. There should be two .gz files which contain the configuration.
Links
More details on FortiWeb: https://www.avantec.ch/loesungen/fortinet/fortiweb/
Web application firewall (WAF): https://en.wikipedia.org/wiki/Web_application_firewall
NSS Labs test on FortiWeb: https://www.fortinet.com/content/dam/fortinet/assets/analyst-reports/Brochure-NSS-Lab-Independent-Validation.pdf
The_Unicorn
The_Unicorn ist Principal Security Engineer bei AVANTEC. Die Lösungen von Check Point, Fortinet und Vectra haben es ihm besonders angetan. The_Unicorn hat Informatik studiert. Seine Leidenschaft neben IT-Security ist Fussball.
Using k8S you can have a look into https://github.com/fortinet-solutions-cse/fortiweb_ingress_ctlr
It’s a „devops tool“ we started for using FWEB with K8S Ingress Ctrl.
Some short demo here: https://www.youtube.com/watch?v=Tr8rkCfz6aU