UFW and Docker Security on Linux machine
Tags: aws, docker, linux
Published: 2021-08-27 08:53:11

Uncomplicated Firewall (UFW) is served as a frontend tool for *iptables* in Linux-based machine. It's used to provide easy interface to manage firewall so you don't have to manage them through complicated *iptables* and *netfilter* commands.

So today I tried **experimenting** UFW with NGINX running as a Docker container on Amazon Linux 2 EC2 instance in my AWS environments. 

Before this, I have launched an Amazon Linux 2 EC2 instance and have SSH and TCP port 80 allowed for incoming request in the security group attached to the instance. 


## Install UFW

First, ssh into the EC2 instance.

```
$ ssh -i example.pem ec2-user@1.23.45.678
```

By default, UFW is not pre-installed on Amazon Linux 2 and not available in RHEL repository. We will need to install EPEL repository to our system. 

```
$ sudo yum update -y 
$ sudo yum install epel-release -y
```

Then, install UFW by running command below:

```
$ sudo yum install --enablerepo="epel" ufw -y
```

Then, start UFW service and enable it to start on boot time.

```
$ sudo ufw enable
```

Run command below to ensure UFW is running:

```
$ sudo ufw status
```

## Install Docker

Next, install Docker runtime in the instance:

```
$ sudo amazon-linux-extras install docker
$ sudo service docker start
$ sudo usermod -a -G docker ec2-user
```

Confirm Docker is installed and you see version as output:

```
$ sudo docker -v

Docker version 20.10.7, build f0df350
```

Then, run a NGINX container using command below:

```
$ sudo docker run -d --name my-nginx -p 80:80 nginx
```

This command will pull the Docker image from Docker Hub and run as a container on local Docker runtime. Run command below to see if `my-nginx` container is running:

```
$ sudo docker ps

CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS                               NAMES
c3aee3db60f1   nginx     "/docker-entrypoint.…"   22 seconds ago   Up 21 seconds   0.0.0.0:80->80/tcp, :::80->80/tcp   my-nginx
```

Next, run `curl` command to see if your website is running perfect or go to your browser and search.

```
$ curl -L 1.23.45.678:80
<!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>
```

You will see a beautiful NGINX website in front of you!
![Nginx](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y4t0aphh9goz8z5685jj.png)


## Problem arises

Next, here is something fun: I want to deny anyone looking for this website through UFW!

Go back to your EC2 instance. Run the command below to enable the rule of denying incoming request with port 80 in UFW:

```
$ sudo ufw deny 80


Rule updated
Rule updated (v6)
```

Validate the deny rule is enabled:

```
$ sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
SSH                        ALLOW       Anywhere
224.0.0.251 mDNS           ALLOW       Anywhere
22                         ALLOW       Anywhere
80                         DENY        Anywhere
SSH (v6)                   ALLOW       Anywhere (v6)
ff02::fb mDNS              ALLOW       Anywhere (v6)
22 (v6)                    ALLOW       Anywhere (v6)
80 (v6)                    DENY        Anywhere (v6)

```

Now, test on your host machine and check again. You should not be able to see the NGINX website on your host machine!


```
$ curl -L 1.23.45.678:80
<!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>
```

Why are you still here.....

![Nginx-2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y4t0aphh9goz8z5685jj.png)

## What's the problem and how to fix it

From [Docker documentation](https://docs.docker.com/network/iptables/), I only learned that by default, Docker directly manipulates iptables for network isolation. 

There are several ways to disable this. One of it is that we don't expose the port 80. 

Another way is, we can disable this Docker behaviour by creating or modifying /etc/docker/daemon.json.

```
$ sudo vi /etc/docker/daemon.json

{ "iptables": false }

$ sudo service docker restart
```

By this, we don't have to worry if other port is exposed and open when we run another container with different ports exposed.

Last, try to connect again:

```
$ curl -L 1.23.45.678:80

curl: (7) Failed to connect to 1.23.45.678 port 80: Operation timed out
```

Done!

## Conclusion

This article may not explain well about the fundamental of Linux security and you may think why do I need UFW when there's security group attached on EC2 instance and you can configure the allow/deny rules easily from security group. 


Well, it's for experiment purpose! I never learned about UFW or security related topics in Linux and I thought security group is the only solution to secure my instances. 

Let me know in the comments about your thoughts too! 

Happy coding! 💻