Giter VIP home page Giter VIP logo

ufw-docker-automated's Introduction

ufw-docker-automated

Manage Docker containers firewall with UFW!

If you use Docker, you may know docker's publish port function (docker -p 8080:80 ) directly talks to iptables and update rules accordingly. This conflicts with Ubuntu/Debian's ufw firewall manager and bypasses ufw rules.

Lot of issues were raised, but Docker didn't "fix" the issue. Fortunately some smart people found the solution to this problem and my favorite one is ufw-docker. You can read more about it on the project's readme.

Original ufw-docker project is very easy to use, but it's static, doesn't track container IP changes. If original container's IP changes somehow (e.g server reboot), your rule will be invalid. This project solves that problem by listening to the Docker API events.

Features

  • Automate ufw-docker rules
  • Automate docker container's firewall with labels
  • Zero dependency, single binary installation
  • Supports docker-compose
  • Supports both inbound/outbound rules

Supported labels

Label key Value / Syntax Example
UFW_MANAGED TRUE (Required for all rules) -l UFW_MANAGED=TRUE
UFW_ALLOW_FROM CIDR/IP-SpecificPort-Comment , Semicolon separated, default=any -l UFW_ALLOW_FROM=192.168.3.0/24-LAN;10.10.0.50/32-53-DNS
UFW_DENY_OUT TRUE (Required if outbound rules are defined) -l UFW_DENY_OUT=TRUE
UFW_ALLOW_TO CIDR/IP-SpecificPort-Comment , Semicolon separated, default=none -l UFW_ALLOW_TO=192.168.3.0/24-LAN;10.10.0.50/32-53-DNS

Example

# To use with docker-compose add labels: section to your docker-compose.yml file
version: '2.1'
services:
  nginx:
    image: nginx:alpine
    ports:
      - '8080:80'
      - '8081:81'
    labels:
      UFW_MANAGED: 'TRUE'
      UFW_ALLOW_FROM: '172.10.50.32;192.168.3.0/24;10.10.0.50/32-8080-LAN'
      UFW_DENY_OUT: 'TRUE'
      UFW_ALLOW_TO: '8.8.8.8-53-GoogleDNS;1.1.1.0/24-53-CloudflareDNS;192.168.10.24-8080-LAN'
    networks:
      - my-network

networks:
  my-network:
    driver: bridge
# Allow from any
➜ docker run -d -p 8080:80 -p 8081:81 -l UFW_MANAGED=TRUE nginx:alpine

# Allow from any + deny all out
➜ docker run -d -p 8082:82 -p 8083:83 -l UFW_MANAGED=TRUE -l UFW_DENY_OUT=TRUE nginx:alpine

# Allow from certain IP address
➜ docker run -d -p 8084:84 -p 8085:85 -l UFW_MANAGED=TRUE -l UFW_ALLOW_FROM=192.168.3.0 nginx:alpine

# Allow from certain CIDR ranges
➜ docker run -d -p 8086:86 -p 8087:87 -l UFW_MANAGED=TRUE -l UFW_ALLOW_FROM="192.168.3.0/24;10.10.0.50/32" nginx:alpine

# Allow from certain IP address, CIDR ranges + comments
➜ docker run -d -p 8088:88 -p 8089:89 -l UFW_MANAGED=TRUE -l UFW_ALLOW_FROM="172.10.5.0;192.168.3.0/24-LAN;10.10.0.50/32-DNS" nginx:alpine

# Allow from certain IP address, CIDR ranges + deny all out + allow to some IP range (specific port defined) + comments
➜ docker run -d -p 8090:90 -p 8091:91 -l UFW_MANAGED=TRUE -l UFW_ALLOW_FROM="172.10.5.0;192.168.3.0/24-LAN;10.10.0.50/32-DNS" -l UFW_DENY_OUT=TRUE -l UFW_ALLOW_TO="8.8.8.8-53-GoogleDNS;1.1.1.0/24-53-CloudflareDNS;192.168.10.0/24-LAN" nginx:alpine

# Allow from certain IP address, CIDR ranges to different Port + comments
➜ docker run -d -p 8092:92 -p 8093:93 -p 8094:94 -l UFW_MANAGED=TRUE -l UFW_ALLOW_FROM="0.0.0.0/0-88-Internet;192.168.3.0/24-89-LAN;10.10.0.50-90" nginx:alpine

# Results
➜ sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
22                         ALLOW       Anywhere

172.17.0.2 80/tcp          ALLOW FWD   Anywhere                   # pensive_davinci:bb01e89284b6
172.17.0.2 81/tcp          ALLOW FWD   Anywhere                   # pensive_davinci:bb01e89284b6
172.17.0.3 83/tcp          ALLOW FWD   Anywhere                   # vigorous_wescoff:97403d2d7e08
172.17.0.3 82/tcp          ALLOW FWD   Anywhere                   # vigorous_wescoff:97403d2d7e08
Anywhere                   DENY FWD    172.17.0.3                 # vigorous_wescoff:97403d2d7e08
172.17.0.4 84/tcp          ALLOW FWD   192.168.3.0                # sweet_poitras:b7f4cbdd363b
172.17.0.4 85/tcp          ALLOW FWD   192.168.3.0                # sweet_poitras:b7f4cbdd363b
172.17.0.5 87/tcp          ALLOW FWD   192.168.3.0/24             # objective_moore:473a2fd127c4
172.17.0.5 87/tcp          ALLOW FWD   10.10.0.50                 # objective_moore:473a2fd127c4
172.17.0.5 86/tcp          ALLOW FWD   192.168.3.0/24             # objective_moore:473a2fd127c4
172.17.0.5 86/tcp          ALLOW FWD   10.10.0.50                 # objective_moore:473a2fd127c4
172.17.0.6 89/tcp          ALLOW FWD   172.10.5.0                 # goofy_dijkstra:3c4d49d8e118
172.17.0.6 89/tcp          ALLOW FWD   192.168.3.0/24             # goofy_dijkstra:3c4d49d8e118 LAN
172.17.0.6 89/tcp          ALLOW FWD   10.10.0.50                 # goofy_dijkstra:3c4d49d8e118 DNS
172.17.0.6 88/tcp          ALLOW FWD   172.10.5.0                 # goofy_dijkstra:3c4d49d8e118
172.17.0.6 88/tcp          ALLOW FWD   192.168.3.0/24             # goofy_dijkstra:3c4d49d8e118 LAN
172.17.0.6 88/tcp          ALLOW FWD   10.10.0.50                 # goofy_dijkstra:3c4d49d8e118 DNS
172.17.0.7 90/tcp          ALLOW FWD   172.10.5.0                 # wonderful_wilson:447017665de8
172.17.0.7 90/tcp          ALLOW FWD   192.168.3.0/24             # wonderful_wilson:447017665de8 LAN
172.17.0.7 90/tcp          ALLOW FWD   10.10.0.50                 # wonderful_wilson:447017665de8 DNS
172.17.0.7 91/tcp          ALLOW FWD   172.10.5.0                 # wonderful_wilson:447017665de8
172.17.0.7 91/tcp          ALLOW FWD   192.168.3.0/24             # wonderful_wilson:447017665de8 LAN
172.17.0.7 91/tcp          ALLOW FWD   10.10.0.50                 # wonderful_wilson:447017665de8 DNS
8.8.8.8 53                 ALLOW FWD   172.17.0.7                 # wonderful_wilson:447017665de8 GoogleDNS
1.1.1.0/24 53              ALLOW FWD   172.17.0.7                 # wonderful_wilson:447017665de8 CloudflareDNS
192.168.10.0/24            ALLOW FWD   172.17.0.7                 # wonderful_wilson:447017665de8 LAN
Anywhere                   DENY FWD    172.17.0.7                 # wonderful_wilson:447017665de8
172.17.0.8 88/tcp          ALLOW FWD   Anywhere                   # stoic_roentgen:e34a3201c01b Internet
172.17.0.8 89/tcp          ALLOW FWD   192.168.3.0/24             # stoic_roentgen:e34a3201c01b LAN
172.17.0.8 90/tcp          ALLOW FWD   10.10.0.50                 # stoic_roentgen:e34a3201c01b

Once containers are stopped their ufw entries will be deleted.

Installation

Step 1. Install ufw-docker's firewall rules on your ufw configuration file.

Open up /etc/ufw/after.rules file and add following code to the bottom of the file.

# BEGIN UFW AND DOCKER
*filter
:ufw-user-forward - [0:0]
:ufw-docker-logging-deny - [0:0]
:DOCKER-USER - [0:0]
-A DOCKER-USER -j ufw-user-forward

-A DOCKER-USER -j RETURN -s 10.0.0.0/8
-A DOCKER-USER -j RETURN -s 172.16.0.0/12
-A DOCKER-USER -j RETURN -s 192.168.0.0/16

-A DOCKER-USER -p udp -m udp --sport 53 --dport 1024:65535 -j RETURN

-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16
-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8
-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12
-A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 192.168.0.0/16
-A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 10.0.0.0/8
-A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 172.16.0.0/12

-A DOCKER-USER -j RETURN

-A ufw-docker-logging-deny -m limit --limit 3/min --limit-burst 10 -j LOG --log-prefix "[UFW DOCKER BLOCK] "
-A ufw-docker-logging-deny -j DROP

COMMIT
# END UFW AND DOCKER

Step 2. Reload your ufw service to take effect of new configuration.

sudo ufw reload

# or

sudo service ufw restart

# or

sudo systemctl restart ufw

Step 3. Download ufw-docker-automated binary

Download the latest release of the project.

Step 4. Run the app

To manage ufw rules, binary has to run as a root privileged user.

chmod +x ./ufw-docker-automated
./ufw-docker-automated

You'll most likely want to run this app in a background and at the startup of the system. If you use systemd service manager (Default since Ubuntu 16.04, Debian 8), here is an example.

Create and open new file on the following path /lib/systemd/system/ufw-docker-automated.service and copy the following content, don't forget to update the binary path.

[Unit]
Description=Ufw docker automated
Documentation=https://github.com/shinebayar-g/ufw-docker-automated
After=network-online.target ufw.service containerd.service
Wants=network-online.target
Requires=ufw.service

[Service]
# To manage ufw rules, binary has to run as a root or sudo privileged user.
User=ubuntu
# Provide /path/to/ufw-docker-automated
ExecStart=/usr/local/bin/ufw-docker-automated
Restart=always

[Install]
WantedBy=multi-user.target

Then reload the systemd.

sudo systemctl daemon-reload
sudo systemctl enable ufw-docker-automated
sudo systemctl start ufw-docker-automated

Feedback

If you encounter any issues please feel free to open an issue.

Build

Requirements:

  • go 1.19 >=
git clone https://github.com/shinebayar-g/ufw-docker-automated.git
go build -o ufw-docker-automated github.com/shinebayar-g/ufw-docker-automated

ufw-docker-automated's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

ufw-docker-automated's Issues

When container has multiple networks, it only creates one network rules

Hi.
First, I must say I don't understand iptables, so maybe this is correct.
I have a reverse proxy which has 2 networks (one has more priority over the other)
When I launch your program, only one of these networks is created, and the other is deleted if already exist.
Is correct this behavior?

 networks:
            proxy:                
                priority: 1000
            crowdsec:
ufw status numbered
Status: active

     To                         Action      From
     --                         ------      ----
[ 1] 22/tcp                     ALLOW IN    Anywhere
[ 2] 80/tcp                     ALLOW IN    Anywhere
[ 3] 443                        ALLOW IN    Anywhere
[ 4] 172.18.0.5 443/tcp         ALLOW FWD   Anywhere                   # traefik-traefik-1:0baf661347fb
[ 5] 172.18.0.5 80/tcp          ALLOW FWD   Anywhere                   # traefik-traefik-1:0baf661347fb
[ 6] 22/tcp (v6)                ALLOW IN    Anywhere (v6)
[ 7] 80/tcp (v6)                ALLOW IN    Anywhere (v6)
[ 8] 443 (v6)                   ALLOW IN    Anywhere (v6)

As you can see I should have 2 more rules like 4 and 5 but with IP 172.22.0.2 for example

Potential race condition on host startup

There is a potential race condition on host startup. ufw-docker-automated needs to connect to docker socket to stream event data, thus it'll always start behind docker service. There could be a little window ufw-docker-automated might miss some containers on startup because of this.
Currently on startup, ufw-docker-automated will only look through ghost rules but doesn't perform any catch-up action to fix such issues. To fix this issue, program could get the running container list on startup then check if they needed follow up ufw-docker rules.

allow-to rules needed

hello,

Thanks for nice project.
please also add UFW_ALLOW_TO IP or CIDR range. so from container only specific IP(s) can be connected. thanks

Ufw rules are not cleaned when multiple containers are killed

  • docker-compose
version: '2.4'
services:
  nginx1:
    image: nginx:alpine
    container_name: nginx1
    restart: unless-stopped
    labels:
      - UFW_MANAGED=true
      - UFW_ALLOW_FROM=192.168.0.0/24
      - UFW_DENY_OUTGOING=true
      - UFW_ALLOW_TO=any:53;dl-cdn.alpinelinux.org:80/tcp
    ports:
      - 8180:80

  nginx2:
    image: nginx:alpine
    container_name: nginx2
    restart: unless-stopped
    labels:
      - UFW_MANAGED=true
      - UFW_ALLOW_FROM=192.168.0.0/24
      - UFW_DENY_OUTGOING=true
      - UFW_ALLOW_TO=any:53;dl-cdn.alpinelinux.org:80/tcp
    ports:
      - 8280:80

  nginx3:
    image: nginx:alpine
    container_name: nginx3
    restart: unless-stopped
    labels:
      - UFW_MANAGED=true
      - UFW_ALLOW_FROM=192.168.0.0/24
      - UFW_DENY_OUTGOING=true
      - UFW_ALLOW_TO=any:53;dl-cdn.alpinelinux.org:80/tcp
    ports:
      - 8380:80
  • commands :
docker-compose up -d
docker-compose down
  • syslogs :
ufw-docker-automated: Adding UFW rule: allow from 192.168.0.0/24 to container nginx1 on port 80/tcp
ufw-docker-automated: Adding UFW rule: allow reply from container nginx1 on port 80/tcp to 192.168.0.0/24
ufw-docker-automated: Adding UFW rule: allow outgoing from container nginx1 to any on port 53
ufw-docker-automated: Adding UFW rule: allow outgoing from container nginx1 to 151.101.122.133/32 on port 80/tcp
ufw-docker-automated: Adding UFW rule: deny outgoing from container nginx1 to any
ufw-docker-automated: Adding UFW rule: allow from 192.168.0.0/24 to container nginx2 on port 80/tcp
ufw-docker-automated: Adding UFW rule: allow reply from container nginx2 on port 80/tcp to 192.168.0.0/24
ufw-docker-automated: Adding UFW rule: allow outgoing from container nginx2 to any on port 53
ufw-docker-automated: Adding UFW rule: allow outgoing from container nginx2 to 151.101.122.133/32 on port 80/tcp
ufw-docker-automated: Adding UFW rule: deny outgoing from container nginx2 to any
ufw-docker-automated: Adding UFW rule: allow from 192.168.0.0/24 to container nginx3 on port 80/tcp
ufw-docker-automated: Adding UFW rule: allow reply from container nginx3 on port 80/tcp to 192.168.0.0/24
ufw-docker-automated: Adding UFW rule: allow outgoing from container nginx3 to any on port 53
ufw-docker-automated: Adding UFW rule: allow outgoing from container nginx3 to 151.101.122.133/32 on port 80/tcp
ufw-docker-automated: Adding UFW rule: deny outgoing from container nginx3 to any
ufw-docker-automated: Cleaning UFW rule: container nginx3 deleted rule 'route allow from 192.168.0.0/24 to 172.17.0.4 port 80 proto tcp'
ufw-docker-automated: Cleaning UFW rule: container nginx3 deleted rule 'route allow from 172.17.0.4 port 80 to 192.168.0.0/24 proto tcp'
ufw-docker-automated: Cleaning UFW rule: container nginx3 deleted rule 'route allow from 172.17.0.4 to any port 53'
ufw-docker-automated: Cleaning UFW rule: container nginx3 deleted rule 'route allow from 172.17.0.4 to 151.101.122.133 port 80 proto tcp'
ufw-docker-automated: Cleaning UFW rule: container nginx3 deleted rule 'route deny from 172.17.0.4'

I think the script can handle one event at a time, when it needs to continue to listen to other events. Maybe with subprocess the script could open a dedicated child process for cleaning rules for a container and continue to listen on the main process ?

Problems accessing port

    ports:
      - ip:21:21
      - ip:21000-21010:21000-21010
    labels:
      UFW_MANAGED: 'TRUE'
      UFW_ALLOW_FROM: '0.0.0.0-21;0.0.0.0-21000;0.0.0.0-21001;0.0.0.0-21002;0.0.0.0-21003;0.0.0.0-21004;0.0.0.0-21005;0.0.0.0-21006;0.0.0.0-21007;0.0.0.0-21008;0.0.0.0-21009;0.0.0.0-21010'
172.25.0.2 21/tcp          ALLOW FWD   0.0.0.0                    # ftp-ftp-1:b4f6104135df
172.25.0.2 21000/tcp       ALLOW FWD   0.0.0.0                    # ftp-ftp-1:b4f6104135df
172.25.0.2 21001/tcp       ALLOW FWD   0.0.0.0                    # ftp-ftp-1:b4f6104135df
172.25.0.2 21002/tcp       ALLOW FWD   0.0.0.0                    # ftp-ftp-1:b4f6104135df
172.25.0.2 21003/tcp       ALLOW FWD   0.0.0.0                    # ftp-ftp-1:b4f6104135df
172.25.0.2 21004/tcp       ALLOW FWD   0.0.0.0                    # ftp-ftp-1:b4f6104135df
172.25.0.2 21005/tcp       ALLOW FWD   0.0.0.0                    # ftp-ftp-1:b4f6104135df
172.25.0.2 21006/tcp       ALLOW FWD   0.0.0.0                    # ftp-ftp-1:b4f6104135df
172.25.0.2 21007/tcp       ALLOW FWD   0.0.0.0                    # ftp-ftp-1:b4f6104135df
172.25.0.2 21008/tcp       ALLOW FWD   0.0.0.0                    # ftp-ftp-1:b4f6104135df
172.25.0.2 21009/tcp       ALLOW FWD   0.0.0.0                    # ftp-ftp-1:b4f6104135df
172.25.0.2 21010/tcp       ALLOW FWD   0.0.0.0                    # ftp-ftp-1:b4f6104135df
May 21 00:38:53 server kernel: [6740192.662607] [UFW DOCKER BLOCK] IN=ens18 OUT=br-a4b2272b5f4e MAC=36:24:05:bc:0f:f4:d6:42:5c:89:88:91:08:00 SRC=109.248.251.200 DST=172.25.0.2 LEN=60 TOS=0x10 PREC=0x00 TTL=63 ID=57620 DF PROTO=TCP SPT=59112 DPT=21 WINDOW=64240 RES=0x00 SYN URGP=0 

I cannot connect from outside the server (can connet from the server):

telnet ip 21

Cannot detect some container IP addresses when stopping multiple containers

Follow up #32, in bulk container stop scenario, program cannot detect some container's ip addresses. Because of this, program cannot delete some ufw rules. Inspecting the container state isn't reliable when container is shutting down. There will always be some race conditions. We should probably store the inspected data into memory when container starts. Then we could use state data to grab necessary information when container is shutting down.

Does not run on a Raspberry Pi @ Debian

I ran this on a linux machine for several month without problems. Now I tried it on 2 Debian RPIs but without success:

sudo ./ufw-docker-automated

./ufw-docker-automated: 1: ELF: not found
./ufw-docker-automated: 2: @$: not found
./ufw-docker-automated: 2: @?: not found
./ufw-docker-automated: 2: ?: not found
./ufw-docker-automated: 2: ?{?{??: not found
./ufw-docker-automated: 2: ?: not found
./ufw-docker-automated: 2: p?{?: not found
./ufw-docker-automated: 2: b?: not found
./ufw-docker-automated: 1: z?: not found
./ufw-docker-automated: 3:?zR?
                             v: not found
./ufw-docker-automated: 4: Syntax error: ")" unexpected

sudo journalctl -u ufw-docker-automated -f

-- Journal begins at Thu 2019-02-14 11:11:59 CET. --
Dec 26 21:03:12 pi-docker systemd[1]: Started Ufw docker automated.
Dec 26 21:03:12 pi-docker systemd[23123]: ufw-docker-automated.service: Failed to execute /usr/lib/ufw-docker/ufw-docker-automated: Exec format error
Dec 26 21:03:12 pi-docker systemd[23123]: ufw-docker-automated.service: Failed at step EXEC spawning /usr/lib/ufw-docker/ufw-docker-automated: Exec format error
Dec 26 21:03:12 pi-docker systemd[1]: ufw-docker-automated.service: Main process exited, code=exited, status=203/EXEC
Dec 26 21:03:12 pi-docker systemd[1]: ufw-docker-automated.service: Failed with result 'exit-code'.
Dec 26 21:03:12 pi-docker systemd[1]: ufw-docker-automated.service: Scheduled restart job, restart counter is at 5.
Dec 26 21:03:12 pi-docker systemd[1]: Stopped Ufw docker automated.
Dec 26 21:03:12 pi-docker systemd[1]: ufw-docker-automated.service: Start request repeated too quickly.
Dec 26 21:03:12 pi-docker systemd[1]: ufw-docker-automated.service: Failed with result 'exit-code'.
Dec 26 21:03:12 pi-docker systemd[1]: Failed to start Ufw docker automated.

Any hint on this?

Enhancement to support ufw-to (whitelist outgoing traffic)

Here we can discuss about a feature from mlollo:ufw-to branch to filter outgoing traffic only for containers. The idea is to deny by default outgoing traffic and allow a set of IPs.

As you know many docker are exposed on the internet and are subject to botnet attacks such as crypto bots.
It would be a nice to have feature to be able to filter outgoing traffic from the docker container with two more labels : UFW_DENY_OUTGOING=true and UFW_TO=any:53;mydomain:80/tcp;192.168.0.0/24:8080/udp;192.168.2.0/24:443;192.168.3.32

Here we can keep the label UFW_FROM=192.168.5.0/24 with those ufw rules :

ufw route allow proto tcp from 192.168.5.0/24 to 172.16.0.2 port 80
ufw route allow proto tcp from 172.16.0.2 port 80 to 192.168.5.0/24

As you can see we need to allow container to reply back to the client.
And now you can allow UFW_TO IPs :

ufw route allow from 172.16.0.2 to any port 53
ufw route allow from 172.16.0.2 to ip1_of_mydomain port 80 proto tcp
ufw route allow from 172.16.0.2 to ip2_of_mydomain port 80 proto tcp
ufw route allow from 172.16.0.2 to 192.168.0.0/24 port 8080 proto udp
ufw route allow from 172.16.0.2 to 192.168.2.0/24 port 443
ufw route allow from 172.16.0.2 to 192.168.3.32

And then after specifying all allow rules you can block outgoing traffic with :

ufw route deny from 172.16.0.2 to any

Notes :

  • I never recommend to expose directly docker or any application directly on the internet, I advise to add reverse proxy + firewall in front of those services. This is one of the reason this feature can be interesting.
  • I only tested one scenario for now, I'm not sure every scenario will work.
  • I added a feature to whitelist a fully qualified domain name using the result of the command host -t a fqdn at a given time (not working with dynamic dns).

Run ufw commands with no shell to improve speed

I was wondering if I could improve speed using shell=False in subprocess.run and I stumbled in this thread :
piping in shell via Python subprocess module.
And now I understand why all the parsing is important.
Because someone could try to inject commands in those docker labels and try to run something with higher privilege.
If somehow those input validation are broken in the future, could it be a good idea to use subprocess.run with shell=False ?
Because without shell piping is not working. This could prevent a scenario like this and probably improve speed.

Docker swarm mode support

Follow up #35 Original ufw-docker tool supports docker swarm mode. So it should be able to handle docker swarm mode as well.

Support host network mode

It's not directly related to ufw and iptables issue. But since we supported managing ufw firewall rules with docker labels, we could go further and support non bridged network (host).

For example one could run docker containers with:

docker run -d --net=host nginx:alpine 

In this case docker doesn't create conflicting IPtables rules, hence no destructive behavior. But ufw still has to managed manually and

docker run -d --net=host -l UFW_MANAGED=TRUE -l "UFW_FROM=192.168.0.2;192.168.1.0/24" nginx:alpine

will do nothing. It would be nice to have if the script actually supports this use case too.

Dockerize the service

It would be great improvement if the service itself could be dockerized. But I'm not sure how it would be possible to run ufw from container. Is this doable?

Double rules in ufw after server restart

When the server is rebooted, all container rules are automatically re-added after restart even if they already were there.
I think you have to delete all rules by matched labels.

Couldn't detect the container IP address.

Hi @shinebayar-g ,

I am on Ubuntu 23.10 and I changed from the built-in version of docker-compose (which was 1.29.1) to the latest version 2.22.0

With that version of docker-compose I had to change some of my compose files regarding external networks:

old content:

networks:
    traefik_proxy:
      external:
        name: traefik_proxy

new content:

networks:
    traefik_proxy
      external: true

I do not know if this is the "problem", but now ufw-docker-automated does not create the rules but throws this error:

ERR create.go:36 > ufw-docker-automated: Couldn't detect the container IP address.

Anything I could do? Could this be the problem, that ufw-docker-automated can not read the container IP?

automated rules removed and not properly added back on docker service restart

Running into an issue on an Ubuntu 22.04 x64 host (using the latest ufw-docker-automated, built from source on master) where the ufw container rules established is deleted and not properly recreated on a service docker restart / systemctl restart docker command.

E.g. - prior to docker service restart:

root@services:/# ufw status
Status: active

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW       Anywhere
[...] more static rules
8443/tcp (v6)              ALLOW       Anywhere (v6)

172.17.4.4 5044/udp        ALLOW FWD   10.0.0.0/16                # graylog-graylog-1:66528c03bad1 Beats
172.17.4.4 5140/udp        ALLOW FWD   10.0.0.0/16                # graylog-graylog-1:66528c03bad1 Syslog
172.17.4.4 5555/udp        ALLOW FWD   10.0.0.0/16                # graylog-graylog-1:66528c03bad1 Custom
172.17.4.4 12201/udp       ALLOW FWD   10.0.0.0/16                # graylog-graylog-1:66528c03bad1 GELF
172.17.4.4 5044/tcp        ALLOW FWD   10.0.0.0/16                # graylog-graylog-1:66528c03bad1 Beats
172.17.4.4 5140/tcp        ALLOW FWD   10.0.0.0/16                # graylog-graylog-1:66528c03bad1 Syslog
172.17.4.4 5555/tcp        ALLOW FWD   10.0.0.0/16                # graylog-graylog-1:66528c03bad1 Custom
172.17.4.4 12201/tcp       ALLOW FWD   10.0.0.0/16                # graylog-graylog-1:66528c03bad1 GELF
172.17.5.2 25/tcp          ALLOW FWD   10.0.0.0/16                # postfix-postfix-1:d5bf6f38bad2 SMTP
172.17.5.2 587/tcp         ALLOW FWD   10.0.0.0/16                # postfix-postfix-1:d5bf6f38bad2 SMTPS
172.17.5.2 25/tcp          ALLOW FWD   192.168.0.0/24             # postfix-postfix-1:d5bf6f38bad2 SMTP
172.17.5.2 587/tcp         ALLOW FWD   192.168.0.0/24             # postfix-postfix-1:d5bf6f38bad2 SMTPS
172.17.7.2 8443/tcp        ALLOW FWD   10.0.0.0/16                # step-ca-step-ca-1:10a514908c50
172.17.7.2 8443/tcp        ALLOW FWD   192.168.0.0/24             # step-ca-step-ca-1:10a514908c50

After sudo service docker restart:

root@services:/# ufw status
Status: active

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW       Anywhere
[...] more static rules
8443/tcp (v6)              ALLOW       Anywhere (v6)

Running service ufw-docker-automated restart will successfully re-create the custom rules.

It seems that ufw-docker-automated has code to detect a disconnect from tcp. Here's what I see in /var/log/syslog after the docker service restarts:

Jan 11 20:24:02 services ufw-docker-automated[995]: 2023/01/11 20:24:02 ufw-docker-automated: Event error: unexpected EOF
Jan 11 20:24:07 services ufw-docker-automated[995]: 2023/01/11 20:24:07 ufw-docker-automated: Trying to reconnect..
Jan 11 20:24:07 services ufw-docker-automated[995]: 2023/01/11 20:24:07 ufw-docker-automated: Reconnected to the Docker Engine.

However, inbound rules are not correctly readded post-service restart. Once I manually restart the ufw-docker-automated service /var/log/syslog shows:

Jan 11 20:24:11 services systemd[1]: Stopping Ufw docker automated...
Jan 11 20:24:11 services systemd[1]: ufw-docker-automated.service: Deactivated successfully.
Jan 11 20:24:11 services systemd[1]: Stopped Ufw docker automated.
Jan 11 20:24:11 services systemd[1]: ufw-docker-automated.service: Consumed 55.967s CPU time.
Jan 11 20:24:11 services systemd[1]: Started Ufw docker automated.
Jan 11 20:24:11 services ufw-docker-automated[675485]: 2023/01/11 20:24:11 ufw-docker-automated: Connected to the Docker Engine.
Jan 11 20:24:11 services ufw-docker-automated[675485]: 2023/01/11 20:24:11 ufw-docker-automated: Adding inbound rule: /usr/bin/sudo ufw route allow proto tcp from 10.0.0.0/16 to 172.17.7.2 port 8443 comment step-ca-step-ca-1:10a514908c50
Jan 11 20:24:11 services ufw-docker-automated[675485]: 2023/01/11 20:24:11 ufw-docker-automated: Adding inbound rule: /usr/bin/sudo ufw route allow proto tcp from 192.168.0.0/24 to 172.17.7.2 port 8443 comment step-ca-step-ca-1:10a514908c50
[...] and so on [...]

Not familiar with Go code, but it seems like the service tries to reconnect to the Docker UNIX domain socket (e.g. /var/run/docker.sock) but perhaps binds to an old or inactive version of it?

Anyhow, I "fixed" this issue by adding PartOf=docker.service to my systemd ufw-docker-automated.service file, as so:

[Unit]
Description=Ufw docker automated
Documentation=https://github.com/shinebayar-g/ufw-docker-automated
After=network-online.target ufw.service containerd.service
Wants=network-online.target
Requires=ufw.service
PartOf=docker.service

[Service]
# To manage ufw rules, binary has to run as a root or sudo privileged user.
User=root
# Provide /path/to/ufw-docker-automated
ExecStart=/usr/local/bin/ufw-docker-automated
Restart=always

[Install]
WantedBy=multi-user.target

A better fix might be more robust reconnection detection in the code, perhaps.

Not able to connect to container through WAN

I have installed this great overthought service but I don't seem to be able to connect to my container.

The rule is added automaticly on container create (port 9999 mapped):

10.0.1.2 80/tcp ALLOW FWD Anywhere # whoami:3f4ca202aaffe2ec4e8c151a4085346a9515e4f808921141f53de17e00d0136a

The rule seems to be fine, is this a ufw-docker issue or something else ?

Refering to: chaifeng/ufw-docker#50

Feature Request: integrate ports in ruleset

Hi all,

adding the possibility to define which ports should be opened / closed would be great (not only source). I have containers with ports for admin access (different ports) and I do not want to open these ports (only the "consumer ports").

Thanks and kind regards
Itchy2

support Debian 11 / Ubuntu 22

As others have reported in #45 Ubuntu 22 doesn't seem to work.

On the fresh setup, I'm seeing following output.

ubuntu@ufw-test-f3c5604:~$ ./ufw-docker-automated
2022/11/14 01:06:13 ufw-docker-automated: Connecting to the Docker API. Listening for events..
2022/11/14 01:06:13 ufw-docker-automated: Couldn't inspect container: Error: No such container: ufw Cleaning up ufw rule
2022/11/14 01:06:13 ufw-docker-automated: Deleting rule: ufw allow 22
2022/11/14 01:06:13 ufw error: exit status 1 ERROR: 'route delete NUM' unsupported. Use 'delete NUM' instead.

Fortunately, it's not actually deleting the allow 22 rule. 😓

How to update rule without recreate container?

I'm using docker-compose with few firewall rules. It work OK if the rules are stable. But there will be the case that the rules need to be updated after container created. How we can achieve this without recreate container?
Thank!

Enhancement to support ufw allow from ip

Hello @shinebayar-g,

Thank you for sharing this script. Here an enhancement suggestion to support commands like this one :
ufw route allow proto tcp from 192.168.0.0/24 to 172.16.0.2 port 80.
As I mentioned in this issue on chaifeng/ufw-docker repo it requires docker version >= 19.03.4

Usage : docker run --name nginx -p 80:80 -d -l UFW_MANAGED=TRUE -l "UFW_FROM=192.168.0.2/32;192.168.1.0/24" nginx

Here the modified ufw-docker-automated.py script :

#!/usr/bin/env python
import subprocess
import docker
from ipaddress import ip_network

client = docker.from_env()


def manage_ufw():
    for event in client.events(decode=True):

        event_type = event.get('status')

        # container network is attached on start or stop event
        if event_type == 'start' or event_type == 'kill':
            container = None
            try:
                container = client.containers.get(event['id'])
            except docker.errors.NotFound as e:
                continue
            container_network = container.attrs['HostConfig']['NetworkMode']
            container_ip = None
            container_port_num = None
            container_port_protocol = None
            ufw_managed = None
            ufw_from = None

            container_port_dict = container.attrs['NetworkSettings']['Ports'].items()

            if container_network != 'default':
                # compose network
                container_ip = container.attrs['NetworkSettings']['Networks'][container_network]['IPAddress']
            else:
                # default network
                container_ip = container.attrs['NetworkSettings']['Networks']['bridge']['IPAddress']

            if 'UFW_MANAGED' in container.labels:
                ufw_managed = container.labels.get('UFW_MANAGED').capitalize()

            if 'UFW_FROM' in container.labels:
                try:
                    ufw_from = [ip_network(str(_sub)) for _sub in container.labels.get('UFW_FROM').split(';')]
                except ValueError as e:
                    print(f"Invalid UFW label: UFW_FROM={container.labels.get('UFW_FROM')} exception={e}")
                    ufw_from = -1
                    pass

            if ufw_managed == 'True':
                for key, value in container_port_dict:
                    if value:
                        container_port_num = list(key.split("/"))[0]
                        container_port_protocol = list(key.split("/"))[1]

            if event_type == 'start' and ufw_managed == 'True':
                for key, value in container_port_dict:
                    if value:
                        if not ufw_from:
                            container_port_num = list(key.split("/"))[0]
                            container_port_protocol = list(key.split("/"))[1]
                            print(f"Adding UFW rule: {container_port_num}/{container_port_protocol} of container {container.name}")
                            subprocess.run([f"sudo ufw route allow proto {container_port_protocol} \
                                                from any to {container_ip} \
                                                port {container_port_num}"],
                                           stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True,
                                           shell=True)
                        elif isinstance(ufw_from, list):
                            for subnet in ufw_from:
                                print(f"Adding UFW rule: {container_port_num}/{container_port_protocol} of container {container.name} from {subnet}")
                                subprocess.run([f"sudo ufw route allow proto {container_port_protocol} \
                                                    from {subnet} to {container_ip} \
                                                    port {container_port_num}"],
                                            stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True,
                                            shell=True)

            if event_type == 'kill' and ufw_managed == 'True':
                ufw_length = subprocess.run(
                    [f"sudo ufw status numbered | grep {container_ip} | wc -l"],
                    stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True,
                    shell=True)

                for i in range(int(ufw_length.stdout.strip().split("\n")[0])):
                    awk = "'{print $2}'"
                    ufw_status = subprocess.run(
                        [f"sudo ufw status numbered | grep {container_ip} | awk -F \"[][]\" {awk} "],
                        stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True,
                        shell=True)

                    ufw_num = ufw_status.stdout.strip().split("\n")[0]
                    print(f"Cleaning UFW rule: {container_port_num}/{container_port_protocol} of container {container.name}")
                    ufw_delete = subprocess.run([f"yes y | sudo ufw delete {ufw_num}"],
                                            stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True,
                                            shell=True)


if __name__ == '__main__':
    manage_ufw()

Depending on the behavior you want when UFW_FROM contains invalid IPs, you can change ufw_from from -1 to None. But it's safer by default not to add any ufw rules in this case.

If someone is wondering how to catch those error logs in /var/log/syslog.
You can modify ufw-docker-automated.service file under the [Service] section :

Environment=PYTHONUNBUFFERED=1
ExecStart=/usr/bin/python3 -u /usr/lib/mylib/ufw-docker-automated.py

(Note: sudo is not required)

persistent storage

Right now program is storing container information in memory.
If ufw-docker-automated is restarted while containers are still running it'll lose its tracked containers information.

UFW init error bad argument filter

Hello, I keep getting this error. Any idea why please?
Thanks

ufw version 0.36 on Ubuntu 20.04.3 LTS (Focal Fossa) a.k.a. Ubuntu 20.04.3 LTS

Error

$ sudo ufw reload
ERROR: problem running ufw-init
Bad argument `*filter'
Error occurred at line: 33
Try `iptables-restore -h' or 'iptables-restore --help' for more information.

Problem running '/etc/ufw/after.rules'

My rules

#
# rules.input-after
#
# Rules that should be run after the ufw command line added rules. Custom
# rules should be added to one of these chains:
#   ufw-after-input
#   ufw-after-output
#   ufw-after-forward
#

# Don't delete these required lines, otherwise there will be errors
*filter
:ufw-after-input - [0:0]
:ufw-after-output - [0:0]
:ufw-after-forward - [0:0]
# End required lines

# don't log noisy services by default
-A ufw-after-input -p udp --dport 137 -j ufw-skip-to-policy-input
-A ufw-after-input -p udp --dport 138 -j ufw-skip-to-policy-input
-A ufw-after-input -p tcp --dport 139 -j ufw-skip-to-policy-input
-A ufw-after-input -p tcp --dport 445 -j ufw-skip-to-policy-input
-A ufw-after-input -p udp --dport 67 -j ufw-skip-to-policy-input
-A ufw-after-input -p udp --dport 68 -j ufw-skip-to-policy-input

# don't log noisy broadcast
-A ufw-after-input -m addrtype --dst-type BROADCAST -j ufw-skip-to-policy-input

# don't delete the 'COMMIT' line or these rules won't be processed
# COMMIT

# BEGIN UFW AND DOCKER
*filter
:ufw-user-forward - [0:0]
:ufw-docker-logging-deny - [0:0]
:DOCKER-USER - [0:0]
-A DOCKER-USER -j ufw-user-forward

-A DOCKER-USER -j RETURN -s 10.0.0.0/8
-A DOCKER-USER -j RETURN -s 172.16.0.0/12
-A DOCKER-USER -j RETURN -s 192.168.0.0/16

-A DOCKER-USER -p udp -m udp --sport 53 --dport 1024:65535 -j RETURN

-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16
-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8
-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12
-A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 192.168.0.0/16
-A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 10.0.0.0/8
-A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 172.16.0.0/12

-A DOCKER-USER -j RETURN

-A ufw-docker-logging-deny -m limit --limit 3/min --limit-burst 10 -j LOG --log-prefix "[UFW DOCKER BLOCK] "
-A ufw-docker-logging-deny -j DROP

COMMIT
# END UFW AND DOCKER

Couldn't inspect container: Error: No such container: 7a17d97ad...

I'm getting this error whenever I try to remove 3+ containers at the same time using docker rm -f container_1 container_2 container_3 syntax. Somehow only 2 of the container's firewall rule is deleted and 3rd container errors with no such container error...

Right now it looks like it's consistent behavior, easily reproducible. I cannot find the cause at the moment..
So until this issue is fixed, please don't remove 3+ containers at the same time 🤦‍♂️

Implement log level

Gotta implement log level. Console outputs are getting little bit chatty.

Service listening, no rules added

Hi,

I encountered a problem that my rules are not added on a latest and updated Ubuntu 21.04 install.

The service is listening but and waiting but nothing added.

Any idea ?

Thanks!

Ubuntu 22.04 with crowdsec firewall bouncer does not add any docker rules.

Hi @shinebayar-g

I do not know if it is related to the currently installed crowds-firewall-bouncer, but even with v0.11.0 the log does not say anything :(

./ufw-docker-automated

only shows

2023/01/20 20:32:08 ufw-docker-automated: Connected to the Docker Engine.

and

sudo journalctl -u ufw-docker-automated -f

shows only this, even on a container restart

Jan 20 05:52:45 nas sudo[635511]: pam_unix(sudo:session): session opened for user root(uid=0) by (uid=0)
Jan 20 05:52:46 nas sudo[635511]: pam_unix(sudo:session): session closed for user root
Jan 20 20:27:40 nas systemd[1]: Stopping Ufw docker automated...
Jan 20 20:27:40 nas systemd[1]: ufw-docker-automated.service: Deactivated successfully.
Jan 20 20:27:40 nas systemd[1]: Stopped Ufw docker automated.
Jan 20 20:27:40 nas systemd[1]: Started Ufw docker automated.
Jan 20 20:28:45 nas ufw-docker-automated[2957078]: 2023/01/20 20:28:45 ufw-docker-automated: Connected to the Docker Engine.
Jan 20 20:28:45 nas sudo[2966573]:     root : PWD=/ ; USER=root ; COMMAND=/usr/sbin/ufw show added
Jan 20 20:28:45 nas sudo[2966573]: pam_unix(sudo:session): session opened for user root(uid=0) by (uid=0)
Jan 20 20:28:45 nas sudo[2966573]: pam_unix(sudo:session): session closed for user root

Originally posted by @florie1706 in #47 (comment)

Multiple container shutdown isn't handled correctly

Docker stop command accepts multiple container name|id as an parameter. In the event of docker stop container1 container2 app tries to inspect the container after it's gone, resulting error

ufw-docker-automated: Couldn't inspect container: Error: No such container: ddbdb8b5427142a421a398ba1beff8332cfe0588842a2d27e8add5b343ba16f9

Previously this issue was tracked & fixed in #11. Python implementation used to find ufw status numbered, grep, awk combination to identify which rules to delete. In Go implementation I got rid of this technique and using ufw route delete command by passing exact ufw rules.

Unfortunately this approach recreated the #11

Issue root authorization during usage

Hi all,

first of all I must say this is a great project. So many thanks for all your time invested in here.

I have an issue during runtime (docker-compose up). The firewall rules are not activated, so I checked the logs:
Sep 20 21:28:54 holger-ab350mds3h ufw-docker-automated[12848]: ufw-docker-automated: Adding rule: /usr/sbin/ufw route allow proto tcp from any to 192.168.32.2 port 80 comment npm-app:d9f340c4f214

Sep 20 21:28:54 holger-ab350mds3h ufw-docker-automated[12848]: ufw: exit status 1 ERROR: Es werden Root-Rechte benötigt, um dieses Skript auszuführen to translate it: ufw requires root access.

As my ubuntu server is not equiped with user root I have modified my sudoers file:

myuser ALL = NOPASSWD: /usr/local/bin/ufw-docker-automated, /usr/sbin/ufw

also tried the "long version"

myuser ALL = NOPASSWD: /usr/local/bin/ufw-docker-automated
myuser ALL = NOPASSWD: /usr/sbin/ufw

Does anybody has an Idea about the issue?

Thanks and kind regards
Itchy2

No rules are added on version 0.6.0

Hi, I copied the new file to the old destination and restarted my server. But no rules are added now on startup or restart of the docker container. Can I debug anything?

I used User=root in my ufw-docker-automated.service until now.

I am on Ubuntu Server 21.10

Kind regards

Systemd ufw-docker-automated.service exit 0

● ufw-docker-automated.service - Ufw docker automated
     Loaded: loaded (/lib/systemd/system/ufw-docker-automated.service; enabled; vendor preset: enabled)
     Active: failed (Result: exit-code) since Thu 2023-06-08 10:39:44 MSK; 7s ago
       Docs: https://github.com/shinebayar-g/ufw-docker-automated
   Main PID: 16061 (code=exited, status=217/USER)
        CPU: 3ms

Jun 08 10:39:44 srv2-test systemd[1]: Stopped Ufw docker automated.
Jun 08 10:39:44 srv2-test systemd[1]: Started Ufw docker automated.
Jun 08 10:39:44 srv2-test systemd[1]: ufw-docker-automated.service: Main process exited, code=exited, status=217/USER
Jun 08 10:39:44 srv2-test systemd[1]: ufw-docker-automated.service: Failed with result 'exit-code'.
Jun 08 10:39:44 srv2-test systemd[1]: ufw-docker-automated.service: Scheduled restart job, restart counter is at 5.
Jun 08 10:39:44 srv2-test systemd[1]: Stopped Ufw docker automated.
Jun 08 10:39:44 srv2-test systemd[1]: ufw-docker-automated.service: Start request repeated too quickly.
Jun 08 10:39:44 srv2-test systemd[1]: ufw-docker-automated.service: Failed with result 'exit-code'.
Jun 08 10:39:44 srv2-test systemd[1]: Failed to start Ufw docker automated.

/usr/local/bin/ufw-docker-automated
2023-06-08T10:43:12+03:00 INF main.go:18 > ufw-docker-automated: Connected to the Docker Engine.
2023-06-08T10:43:12+03:00 INF create.go:91 > ufw-docker-automated: Adding inbound rule: /usr/bin/sudo ufw route allow proto tcp from 172.25.66.128/25 to 10.66.30.2 port 5001 comment apr_ss:728f6f947227 TEST
2023-06-08T10:43:12+03:00 INF create.go:101 > ufw: Skipping adding existing rule

2023-06-08T10:43:12+03:00 INF create.go:91 > ufw-docker-automated: Adding inbound rule: /usr/bin/sudo ufw route allow proto tcp from 172.25.66.0/24 to 10.66.30.2 port 5001 comment apr_ss:728f6f947227 PROD
2023-06-08T10:43:12+03:00 INF create.go:101 > ufw: Skipping adding existing rule

ERROR: 'route delete NUM' unsupported. Use 'delete NUM' instead.

ufw on debian 11 with ufw-docker-automated latest, couple of docker containers with UFW_MANAGED=true labels

Before starting ufw-docker-automated, I have these rules:

ufw status numbered
Status: active

     To                         Action      From
     --                         ------      ----
[ 1] 22                         ALLOW IN    xx.xx.xx.xx
[ 2] 443                        ALLOW IN    Anywhere                  
[ 3] 443 (v6)                   ALLOW IN    Anywhere (v6)   

running ufw-docker-automated results in this:

2022/10/26 16:52:33 ufw-docker-automated: Connecting to the Docker API. Listening for events..
2022/10/26 16:52:33 ufw-docker-automated: Adding rule: /usr/bin/sudo ufw route allow proto tcp from any to 172.19.0.2 port 443 comment caddy:55633a03aee9
2022/10/26 16:52:33 ufw-docker-automated: Couldn't inspect container: Error: No such container: ufw Cleaning up ufw rule

I take that as a warning, to be ignored...

2022/10/26 16:52:33 ufw-docker-automated: Deleting rule: ufw allow from xx.xx.xx.xx to any port 22
2022/10/26 16:52:33 ufw error: exit status 1 ERROR: Invalid syntax

why does it try to delete my existing port 22 rule? good thing it fails, otherwise I'd be ssh locked out...

2022/10/26 16:52:33 ufw-docker-automated: Deleting rule: ufw allow 443
2022/10/26 16:52:33 ufw: Rule added
2022/10/26 16:52:33 ufw-docker-automated: Adding rule: /usr/bin/sudo ufw route allow proto tcp from any to 172.19.0.2 port 80 comment caddy:55633a03aee9
2022/10/26 16:52:33 ufw error: exit status 1 ERROR: 'route delete NUM' unsupported. Use 'delete NUM' instead.

different error now, again not sure why it tries to delete the existing general 443 rule?

2022/10/26 16:52:33 ufw-docker-automated: Deleting rule: ufw allow 80
2022/10/26 16:52:33 ufw error: exit status 1 ERROR: 'route delete NUM' unsupported. Use 'delete NUM' instead.
2022/10/26 16:52:33 ufw: Rule added

After that, ufw shows this which is ok I guess - but the above errors are kind of irritating and the attempt to delete 22 potentially dangerous...

[ 1] 22                         ALLOW IN    xx.xx.xx.xx
[ 2] 443                        ALLOW IN    Anywhere                  
[ 3] 80                         ALLOW IN    Anywhere                  
[ 4] 172.19.0.2 443/tcp         ALLOW FWD   Anywhere                   # caddy:55633a03aee9
[ 5] 172.19.0.2 80/tcp          ALLOW FWD   Anywhere                   # caddy:55633a03aee9
[ 6] 443 (v6)                   ALLOW IN    Anywhere (v6)             
[ 7] 80 (v6)                    ALLOW IN    Anywhere (v6)             

Comments to UFW_ALLOW_FROM

Hi,

I just found this and it works great. Thank you indeed, that's what I was looking for a long time.
I have a very restricted iptables setting, so my server is just accessible from a bunch of ip ranges out of the internet.
To remember which range belong to which provider I added a individual comment to my iptables.
Would it be possible to have this in your solution too?

As an example I have this for you:
-A DOCKER-USER -s 87.140.192.0/21 -p tcp -m multiport --dports 80,443 -m comment --comment "Telekom Wifi" -j RETURN

So, for me it would be great to have something like this:

      - UFW_MANAGED=true
      - UFW_ALLOW_FROM=192.168.178.0/24;87.140.192.0/16
      - UFW_ALLOW_FROM_COMMENT=LAN;Telekom Wifi

or as a one-liner:

      - UFW_MANAGED=true
      - UFW_ALLOW_FROM=192.168.178.0/24-LAN;87.140.192.0/16-Telekom Wifi

Do you think this is possible?

docker-compose.yml for mempool

I'm asking for help rather than raising an issue.

I'm running my own mempool instance with docker-compose, as shown on github.com/mempool/mempool and github.com/mempool/mempool/tree/master/docker. If UFW is disabled everything works as expected, but with UFW enabled the known issues occur. I installed and prepared everything along your instructions, but the problem is I don't know which edits I have to make in "docker-compose.yml", because I know way to little to do this on my own even with the examples you showed.
This is the file:

version: "3.7"

services:
  web:
    environment:
      FRONTEND_HTTP_PORT: "8080"
      BACKEND_MAINNET_HTTP_HOST: "api"
    image: mempool/frontend:latest
    user: "1000:1000"
    restart: always
    stop_grace_period: 1m
    command: "./wait-for db:3306 --timeout=720 -- nginx -g 'daemon off;'"
    ports:
      - 4080:8080

  api:
    environment:
      MEMPOOL_BACKEND: "electrum"
      ELECTRUM_HOST: "10.0.0.9"
      ELECTRUM_PORT: "50002"
      ELECTRUM_TLS_ENABLED: "true"
      CORE_RPC_HOST: "10.0.0.9"
      CORE_RPC_PORT: "8332"
      CORE_RPC_USERNAME: "myusername"
      CORE_RPC_PASSWORD: "mypassword"
      DATABASE_ENABLED: "true"
      DATABASE_HOST: "db"
      DATABASE_DATABASE: "mempool"
      DATABASE_USERNAME: "mempool"
      DATABASE_PASSWORD: "mempool"
      STATISTICS_ENABLED: "true"
    image: mempool/backend:latest
    user: "1000:1000"
    restart: always
    stop_grace_period: 1m
    command: "./wait-for-it.sh db:3306 --timeout=720 --strict -- ./start.sh"
    volumes:
      - ./data:/backend/cache
  db:
    environment:
      MYSQL_DATABASE: "mempool"
      MYSQL_USER: "mempool"
      MYSQL_PASSWORD: "mempool"
      MYSQL_ROOT_PASSWORD: "admin"
    image: mariadb:10.5.8
    user: "1000:1000"
    restart: always
    stop_grace_period: 1m
    volumes:
      - ./mysql/data:/var/lib/mysql

I understand that I have to add something like this:

    labels:
      UFW_MANAGED: 'TRUE'
      UFW_ALLOW_FROM: '172.10.50.32;192.168.3.0/24;10.10.0.50/32-8080-LAN'
      UFW_DENY_OUT: 'TRUE'
      UFW_ALLOW_TO: '8.8.8.8-53-GoogleDNS;1.1.1.0/24-53-CloudflareDNS;192.168.10.24-8080-LAN'
    networks:
      - my-network

But I don't know in which way I have to edit the values from the example to fit to my "docker-compose.yml"-File.

Segmentation fault

OS debian 11

PRETTY_NAME="Debian GNU/Linux 11 (bullseye)"
NAME="Debian GNU/Linux"
VERSION_ID="11"
VERSION="11 (bullseye)"

Kernel
5.10.0-22-amd64 #1 SMP Debian 5.10.178-3 (2023-04-22) x86_64 GNU/Linux

/usr/local/bin/ufw-docker-automated Segmentation fault

Avoid duplicate rules

Right now program is relying on ufw for duplicate entries handling. Duplicate rules are produced on some scenario like defining allowed ports specifically.

Ufw rules are not cleaned when a container dies

When a container dies and the user remove it. UFW rules are not cleaned.
Example :

version: '2.4'
services:
  debian:
    image: debian
    container_name: debian
    labels:
      - UFW_MANAGED=true
      - UFW_DENY_OUTGOING=true
      - UFW_TO=192.168.1.0/24
    command: sleep 1

Commands :

docker-compose up -d
docker-compose down

If we check ufw rules we can see that they are remaining.
If the container dies, in this case we can catch the container id in it. Here the event that we could handle :

 {'status': 'die', 'id': '284b554c5c2e8a411e27fd80be330576b496c9b2db1d86844ae79ed140c6b3a4', 'from': 'debian', 'Type': 'container', 'Action': 'die', 'Actor': {'ID': '284b554c5c2e8a411e27fd80be330576b496c9b2db1d86844ae79ed140c6b3a4', 'Attributes': {'UFW_DENY_OUTGOING': 'true', 'UFW_MANAGED': 'true', 'UFW_TO': '192.168.1.0/24', 'com.docker.compose.config-hash': 'eee765fc5954e91126235b19bd1fa7ab32c7671abe99923eef218fee254b0b0c', 'com.docker.compose.container-number': '1', 'com.docker.compose.oneoff': 'False', 'com.docker.compose.project': 'test', 'com.docker.compose.project.config_files': 'docker-compose.yml', 'com.docker.compose.project.working_dir': '/home/test', 'com.docker.compose.service': 'debian', 'com.docker.compose.version': '1.27.4', 'exitCode': '0', 'image': 'debian', 'name': 'debian'}}, 'scope': 'local', 'time': 1610910393, 'timeNano': 1610910393567662105}

Maybe we should watch only die events. Because after a kill event there is a die event.

UFW Rule for network interface name

Feature request:

Add support for network interface name:
Example ufw rule:
ufw route allow in on eth0 proto tcp to 192.168.151.3 port 80

We can reuse the environment variable UFW_ALLOW_FROM value to detect if an IP address is specified (using regex) or a network interface name (string).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.