GithubHelp home page GithubHelp logo

chaifeng / ufw-docker Goto Github PK

View Code? Open in Web Editor NEW
3.9K 50.0 337.0 168 KB

To fix the Docker and UFW security flaw without disabling iptables

License: GNU General Public License v3.0

Shell 97.49% Dockerfile 2.51%
docker ufw ubuntu debian linux firewall security docker-swarm

ufw-docker's Introduction

To Fix The Docker and UFW Security Flaw Without Disabling Iptables

Build Status chaifeng/ufw-docker-agent

TL;DR

Please take a look at Solving UFW and Docker issues.

Problem

UFW is a popular iptables front end on Ubuntu that makes it easy to manage firewall rules. But when Docker is installed, Docker bypass the UFW rules and the published ports can be accessed from outside.

The issue is:

  1. UFW is enabled on a server that provides external services, and all incoming connections that are not allowed are blocked by default.
  2. Run a Docker container on the server and use the -p option to publish ports for that container on all IP addresses. For example: docker run -d --name httpd -p 0.0.0.0:8080:80 httpd:alpine, this command will run an httpd service and publish port 80 of the container to port 8080 of the server.
  3. UFW will not block all external requests to visit port 8080. Even the command ufw deny 8080 will not prevent external access to this port.
  4. This problem is actually quite serious, which means that a port that was originally intended to provide services internally is exposed to the public network.

Searching for "ufw docker" on the web can find a lot of discussion:

Almost all of these solutions are similar. It requires to disable docker's iptables function first, but this also means that we give up docker's network management function. This causes containers will not be able to access the external network. It is also mentioned in some articles that you can manually add some rules in the UFW configuration file, such as -A POSTROUTING ! -o docker0 -s 172.17.0.0/16 -j MASQUERADE. But this only allows containers that belong to network 172.17.0.0/16 can access outside. If we create a new docker network, we must manually add such similar iptables rules for the new network.

Expected goal

The solutions that we can find on internet are very similar and not elegant, I hope a new solution can:

  • Don't need to disable Docker's iptables and let Docker to manage it's network. We don't need to manually maintain iptables rules for any new Docker networks, and avoid potential side effects after disabling iptables in Docker.
  • The public network cannot access ports that published by Docker. Even if the port is published on all IP addresses using an option like -p 8080:80. Containers and internal networks can visit each other normally. Although it is possible to have Docker publish a container's port to the server's private IP address, the port will not be accessed on the public network. But, this server may have multiple private IP addresses, and these private IP addresses may also change.
  • In a very convenient way to allow/deny public networks to access container ports without additional software and extra configurations. Just like using command ufw allow 8080 to allow external access port 8080, then using command ufw delete allow 8080 to deny public networks visit port 8080.

How to do?

Revoke the original modification

If you have modified your server according to the current solution that we find on the internet, please rollback these changes first, including:

  • Enable Docker's iptables feature. Remove all changes like --iptables=false , including configuration file /etc/docker/daemon.json.
  • UFW's default FORWARD rule changes back to the default DROP instead of ACCEPT.
  • Remove the rules related to the Docker network in the UFW configuration file /etc/ufw/after.rules.
  • If you have modified Docker configuration files, restart Docker first. We will modify the UFW configuration later and we can restart it then.

Solving UFW and Docker issues

This solution needs to modify only one UFW configuration file, all Docker configurations and options remain the default.

Modify the UFW configuration file /etc/ufw/after.rules and add the following rules at the end 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

Using command sudo systemctl restart ufw or sudo ufw reload to restart UFW after changing the file. Now the public network can't access any published docker ports, the container and the private network can visit each other normally, and the containers can also access the external network from inside. There may be some unknown reasons cause the UFW rules will not take effect after restart UFW, please reboot servers.

If you want to allow public networks to access the services provided by the Docker container, for example, the service port of a container is 80. Run the following command to allow the public networks to access this service:

ufw route allow proto tcp from any to any port 80

This allows the public network to access all published ports whose container port is 80.

Note: If we publish a port by using option -p 8080:80, we should use the container port 80, not the host port 8080.

If there are multiple containers with a service port of 80, but we only want the external network to access a certain container. For example, if the private address of the container is 172.17.0.2, use the following command:

ufw route allow proto tcp from any to 172.17.0.2 port 80

If the network protocol of a service is UDP, for example a DNS service, you can use the following command to allow the external network to access all published DNS services:

ufw route allow proto udp from any to any port 53

Similarly, if only for a specific container, such as IP address 172.17.0.2:

ufw route allow proto udp from any to 172.17.0.2 port 53

How it works?

The following rules allow the private networks to be able to visit each other. Normally, private networks are more trusted than public networks.

-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

The following rules allow UFW to manage whether the public networks are allowed to visit the services provided by the Docker container. So that we can manage all firewall rules in one place.

-A DOCKER-USER -j ufw-user-forward

For example, we want to block all outgoing connections from inside a container whose IP address is 172.17.0.9 which means to block this container to access internet or external networks. Using the following command:

ufw route deny from 172.17.0.9 to any

The following rules block connection requests initiated by all public networks, but allow internal networks to access external networks. For TCP protocol, it prevents from actively establishing a TCP connection from public networks. For UDP protocol, all accesses to ports which is less then 32767 are blocked. Why is this port? Since the UDP protocol is stateless, it is not possible to block the handshake signal that initiates the connection request as TCP does. For GNU/Linux we can find the local port range in the file /proc/sys/net/ipv4/ip_local_port_range. The default range is 32768 60999. When accessing a UDP protocol service from a running container, the local port will be randomly selected one from the port range, and the server will return the data to this random port. Therefore, we can assume that the listening port of the UDP protocol inside all containers are less then 32768. This is the reason that we don't want public networks to access the UDP ports that less then 32768.

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

-A DOCKER-USER -j RETURN

If a docker container doesn't follow the OS's settings when receiving data, that is to say, the minimal port number less than 32768. For example, we have a Dnsmasq container. The minimal port number that Dnsmasq uses for receiving data is 1024. We can use the following command to allow a bigger port range used for receiving DNS packages.

ufw route allow proto udp from any port 53 to any port 1024:65535

Because DNS is a very common service, so there is already a firewall rule to allow a bigger port range to receive DNS packages.

The reason for choosing ufw-user-forward, not ufw-user-input

using ufw-user-input

Pro:

Easy to use and understand, supports older versions of Ubuntu.

For example, to allow the public to visit a published port whose container port is 8080, use the command:

ufw allow 8080

Con:

It not only exposes ports of containers but also exposes ports of the host.

For example, if a service is running on the host, and the port is 8080. The command ufw allow 8080 allows the public network to visit the service and all published ports whose containers' port is 8080. But we just want to expose the service running on the host, or just the service running inside containers, not the both.

To avoid this problem, we may need to use a command similar to the following for all containers:

ufw allow proto tcp from any to 172.16.0.3 port 8080

using ufw-user-forward

Pro:

Cannot expose services running on hosts and containers at the same time by the same command.

For example, if we want to publish the port 8080 of containers, use the following command:

ufw route allow 8080

The public network can access all published ports whose container ports are 8080.

But the port 8080 of the host is still not be accessed by the public network. If we want to do so, execute the following command to allow the public access the port on the host separately:

ufw allow 8080

Con:

Doesn't support older versions of Ubuntu, and the command is a bit more complicated. But you can use my script.

Conclusion

If we are using an older version of Ubuntu, we can use ufw-user-input chain. But be careful to avoid exposing services that should not be exposed

If we are using a newer version of Ubuntu which is support ufw route sub-command, we'd better use ufw-user-forward chain, and use ufw route command to manage firewall rules for containers.

ufw-docker util

This script also supports Docker Swarm mode.

Install

Download ufw-docker script

sudo wget -O /usr/local/bin/ufw-docker \
  https://github.com/chaifeng/ufw-docker/raw/master/ufw-docker
sudo chmod +x /usr/local/bin/ufw-docker

Then using the following command to modify the after.rules file of ufw

ufw-docker install

This command does the following things:

  • Back up the file /etc/ufw/after.rules
  • Append the rules of UFW and Docker at the end of the file

Install for Docker Swarm mode

We can only use this script on manager nodes to manage firewall rules when using in Swarm mode.

  • Modifying all after.rules files on all nodes, including managers and workers
  • Deploying this script on manager nodes

Running in Docker Swarm mode, this script will add a global service ufw-docker-agent. The image chaifeng/ufw-docker-agent is also automatically built from this project.

Usage

Show help

ufw-docker help

Check the installation of firewall rules in UFW configurations

ufw-docker check

Update UFW configurations, add the necessary firewall rules

ufw-docker install

Show the current firewall allowed forward rules

ufw-docker status

List all firewall rules related to container httpd

ufw-docker list httpd

Expose the port 80 of the container httpd

ufw-docker allow httpd 80

Expose the 443 port of the container httpd and the protocol is tcp

ufw-docker allow httpd 443/tcp

Expose the 443 port of the container httpd and the protocol is tcp and the network is foobar-external-network when the container httpd is attached to multiple networks

ufw-docker allow httpd 443/tcp foobar-external-network

Expose all published ports of the container httpd

ufw-docker allow httpd

Remove all rules related to the container httpd

ufw-docker delete allow httpd

Remove the rule which port is 443 and protocol is tcp for the container httpd

ufw-docker delete allow httpd 443/tcp

Expose the port 80 of the service web

docker service create --name web --publish 8080:80 httpd:alpine

ufw-docker service allow web 80
# or
ufw-docker service allow web 80/tcp

Remove rules from all nodes related to the service web

ufw-docker service delete allow web

Try it out

We use Vagrant to set up a local testing environment.

Run the following command to create 1 master node and 2 worker nodes

vagrant up

Log into the master node

vagrant ssh master

After logging in, create a web service

docker service create --name web --publish 8080:80 httpd:alpine

We shouldn't visit this web service from our host

curl -v http://192.168.56.131:8080

On the master node, run the command to allow the public access port 80 of the web service.

sudo ufw-docker service allow web 80

We can access the web service from our host now

curl "http://192.168.56.13{0,1,2}:8080"

Discussions

太长不想读

请直接看解决 UFW 和 Docker 的问题

问题

UFW 是 Ubuntu 上很流行的一个 iptables 前端,可以非常方便的管理防火墙的规则。但是当安装了 Docker,UFW 无法管理 Docker 发布出来的端口了。

具体现象是:

  1. 在一个对外提供服务的服务器上启用了 UFW,并且默认阻止所有未被允许的传入连接。
  2. 运行了一个 Docker 容器,并且使用 -p 选项来把该容器的某个端口发布到服务器的所有 IP 地址上。比如:docker run -d --name httpd -p 0.0.0.0:8080:80 httpd:alpine 将会运行一个 httpd 服务,并且将容器的 80 端口发布到服务器的 8080 端口上。
  3. UFW 将不会阻止所有对 8080 端口访问的请求,用命令 ufw deny 8080 也无法阻止外部访问这个端口。

这个问题其实挺严重的,这意味着本来只是为了在内部提供服务的一个端口被暴露在公共网络上。

在网络上搜索 "ufw docker" 可以发现很多的讨论:

基本上可以找到的解决办法就是首先禁用 docker 的 iptables 功能,但这也意味着放弃了 docker 的网络管理功能,很典型的现象就是容器将无法访问外部网络。在有的文章中也提到了可以在 UFW 的配置文件中手工添加一条规则,比如 -A POSTROUTING ! -o docker0 -s 172.17.0.0/16 -j MASQUERADE。但这也只是允许了 172.17.0.0/16 这个网络。如果有了新增的网络,我们也必须手工再为新增的网络添加这样类似的 iptables 规则。

期望的目标

目前网络上的解决方案都非常类似,而且也不优雅,我希望一个新的解决方案可以:

  1. 不要禁用 Docker 的 iptables,像往常一样由 Docker 来管理自己的网络。这样有任何新增的 Docker 网络时都无需手工维护 iptables 规则,也避免了在 Docker 中禁用 iptables 之后可能带来的副作用。
  2. 公共网络不可以访问 Docker 发布出来的端口,即使是使用类似 -p 0.0.0.0:8080:80 的选项把端口发布在所有的 IP 地址上。容器之间、内部网络之间都可以正常互相访问,只有公共网络不可以访问。 虽然可以让 Docker 把容器的某一个端口映射到服务器的私有 IP 地址上,这样公共网络上将不会访问到这个端口。但是这个服务器可能有多个私有 IP 地址,这些私有 IP 地址可能也会发生变化。
  3. 可以很方便的允许公共网络直接访问某个容器的端口,而无需额外的软件和配置。就像是用 ufw allow 8080 这样允许外部访问 8080 端口,然后用 ufw delete allow 8080 就不再允许外部访问。

如何做?

撤销原先的修改

如果已经按照目前网络上搜索到解决方案修改过了,请先修改回来,包括:

  1. 启用 Docker 的 iptables 功能,删除所有类似 --iptables=false 的修改,包括 /etc/docker/daemon.json 配置文件。
  2. UFW 的默认 FORWARD 规则改回默认的 DROP,而非 ACCEPT
  3. 删除 UFW 配置文件 /etc/ufw/after.rules 中与 Docker 网络相关的规则。
  4. 如果修改了 Docker 相关的配置文件,重启 Docker。稍后还要修改 UFW 的配置,可以一并重启。

解决 UFW 和 Docker 的问题

目前新的解决方案只需要修改一个 UFW 配置文件即可,Docker 的所有配置和选项都保持默认。

修改 UFW 的配置文件 /etc/ufw/after.rules,在最后添加上如下规则:

# 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

然后重启 UFW,sudo systemctl restart ufw。现在外部就已经无法访问 Docker 发布出来的任何端口了,但是容器内部以及私有网络地址上可以正常互相访问,而且容器也可以正常访问外部的网络。可能由于某些未知原因,重启 UFW 之后规则也无法生效,请重启服务器。

如果希望允许外部网络访问 Docker 容器提供的服务,比如有一个容器的服务端口是 80。那就可以用以下命令来允许外部网络访问这个服务:

ufw route allow proto tcp from any to any port 80

这个命令会允许外部网络访问所有用 Docker 发布出来的并且内部服务端口为 80 的所有服务。

请注意,这个端口 80 是容器的端口,而非使用 -p 0.0.0.0:8080:80 选项发布在服务器上的 8080 端口。

如果有多个容器的服务端口为 80,但只希望外部网络访问某个特定的容器。比如该容器的私有地址为 172.17.0.2,就用类似下面的命令:

ufw route allow proto tcp from any to 172.17.0.2 port 80

如果一个容器的服务是 UDP 协议,假如是 DNS 服务,可以用下面的命令来允许外部网络访问所有发布出来的 DNS 服务:

ufw route allow proto udp from any to any port 53

同样的,如果只针对一个特定的容器,比如 IP 地址为 172.17.0.2

ufw route allow proto udp from any to 172.17.0.2 port 53

解释

在新增的这段规则中,下面这段规则是为了让私有网络地址可以互相访问。通常情况下,私有网络是比公共网络更信任的。

-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

下面的规则是为了可以用 UFW 来管理外部网络是否允许访问 Docker 容器提供的服务,这样我们就可以在一个地方来管理防火墙的规则了。

-A DOCKER-USER -j ufw-user-forward

例如,我们要阻止一个 IP 地址为 172.17.0.9 的容器内的所有对外连接,也就是阻止该容器访问外部网络,使用下列命令

ufw route deny from 172.17.0.9 to any

下面的规则阻止了所有外部网络发起的连接请求,但是允许内部网络访问外部网络。对于 TCP 协议,是阻止了从外部网络主动建立 TCP 连接。对于 UDP,是阻止了所有小余端口 32767 的访问。为什么是这个端口的?由于 UDP 协议是无状态的,无法像 TCP 那样阻止发起建立连接请求的握手信号。在 GNU/Linux 上查看文件 /proc/sys/net/ipv4/ip_local_port_range 可以看到发出 TCP/UDP 数据后,本地源端口的范围,默认为 32768 60999。当从一个运行的容器对外访问一个 UDP 协议的服务时,本地端口将会从这个端口范围里面随机选择一个,服务器将会把数据返回到这个随机端口上。所以,我们可以假定所有容器内部的 UDP 协议的监听端口都小余 32768,不允许外部网络主动连接小余 32768 的 UDP 端口。

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

-A DOCKER-USER -j RETURN

如果一个容器在接受数据的时候,端口号没有遵循操作系统的设定,也就是说最小端口号要小余 32768。比如运行了一个 Dnsmasq 的容器,Dnsmasq 用于接受数据的最小端口号默认是 1024。那可以用下面的命令来允许 Dnsmasq 这个容器使用一个更大的端口范围来接受数据。

ufw route allow proto udp from any port 53 to any port 1024:65535

因为 DNS 是一个非常常见的服务,所以已经有一条规则用于允许使用一个更大的端口范围来接受 DNS 数据包

选择 ufw-user-forward 而不是 ufw-user-input 的原因

使用 ufw-user-input

优点:

使用的 UFW 命令比较简单,也比较容易理解,而且也支持老版本的 Ubuntu

比如,允许公众网络访问一个已经发布出来的容器端口 8080,使用命令:

ufw allow 8080

缺点:

不仅仅是暴露了已经发布的容器端口,也暴露了主机上的端口。

比如,如果在主机上运行了一个端口为 8080 的服务。命令 ufw allow 8080 允许了公共网络访问这个服务,也允许了访问所有已经发布的容器端口为 8080 的服务。但是我们可能只是希望保留主机上的这个服务,或者是运行在容器里面的服务,而不是两个同时暴露。

为了避免这个问题,我们可能需要使用类似下面的命令来管理已经发布的容器端口:

ufw allow proto tcp from any to 172.16.0.3 port 8080

使用 ufw-user-forward

优点:

不会因为同一条命令而同时暴露主机和容器里面的服务。

比如,如果我们希望暴露所有容器端口为 8080 的服务,使用下面的命令:

ufw route allow 8080

现在公共网络可以访问所有容器端口为 8080 的已经发布的服务,但是运行在主机上的 8080 服务仍然不会被公开。如果我们希望公开主机上的 8080 端口,可以执行下面的命令:

ufw allow 8080

缺点:

不支持老版本的 Ubuntu,而且命令的使用上可能也会比较复杂。

结论

如果我们正在使用老版本的 Ubuntu,我们可以使用 ufw-user-input。但是要小心避免把不该暴露的服务暴露出去。

如果正在使用支持 ufw route 命令的新版本的 Ubuntu,我们最好使用 ufw-user-forward,并且使用 ufw route 来管理与容器相关的防火墙规则。

ufw-docker 工具

现在这个脚本也支持 Docker Swarm。

安装

下载 ufw-docker 脚本

sudo wget -O /usr/local/bin/ufw-docker \
  https://github.com/chaifeng/ufw-docker/raw/master/ufw-docker
chmod +x /usr/local/bin/ufw-docker

使用下列命令来修改 ufw 的 after.rules 文件

ufw-docker install

这个命令做了以下事情:

  • 备份文件 /etc/ufw/after.rules
  • 把 UFW 和 Docker 的相关规则添加到文件 after.rules 的末尾

为 Docker Swarm 环境安装

仅仅可以在管理节点上使用 ufw-docker 这个脚本来管理防火墙规则。

  • 在所有的节点上修改 after.rules 这个文件,包括管理节点和工作节点
  • 在管理节点上部署这个脚本

运行在 Docker Swarm 模式下,这个脚本将会创建一个全局服务 ufw-docker-agent。这个镜像 chaifeng/ufw-docker-agent 是由本项目自动构建的。

使用方法

显示帮助

ufw-docker help

检查 UFW 配置文件中防火墙规则的安装

ufw-docker check

更新 UFW 的配置文件,添加必要的防火墙规则

ufw-docker install

显示当前防火墙允许的转发规则

ufw-docker status

列出所有和容器 httpd 相关的防火墙规则

ufw-docker list httpd

暴露容器 httpd80 端口

ufw-docker allow httpd 80

暴露容器 httpd443 端口,且协议为 tcp

ufw-docker allow httpd 443/tcp

如果容器 httpd 绑定到多个网络上,暴露其 443 端口,协议为 tcp,网络为 foobar-external-network

ufw-docker allow httpd 443/tcp foobar-external-network

把容器 httpd 的所有映射端口都暴露出来

ufw-docker allow httpd

删除所有和容器 httpd 相关的防火墙规则

ufw-docker delete allow httpd

删除容器 httpdtcp 端口 443 的规则

ufw-docker delete allow httpd 443/tcp

暴露服务 web80 端口

docker service create --name web --publish 8080:80 httpd:alpine

ufw-docker service allow web 80
# 或者
ufw-docker service allow web 80/tcp

删除与服务 web 相关的规则

ufw-docker service delete allow web

试试

我们使用 Vagrant 来创建一个本地的测试环境。

运行下面的命令来创建 1 个 master 节点和 2 个 workder 节点

vagrant up

登录到 master 节点

vagrant ssh master

登录后,创建 web 服务

docker service create --name web --publish 8080:80 httpd:alpine

我们应该无法从我们的主机上访问这个 web 服务

curl -v http://192.168.56.131:8080

在 master 节点上,运行下面的命令来允许公共访问 web 服务端 80 端口。

sudo ufw-docker service allow web 80

现在我们可以在我们的主机上访问这个 web 服务了

curl "http://192.168.56.13{0,1,2}:8080"

讨论

ufw-docker's People

Contributors

anuragpeshne avatar chaifeng avatar drallgood avatar erakli avatar ifurther avatar kronthto avatar rklos avatar

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  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

ufw-docker's Issues

Add another solution to the Readme.md

I have an additional solution that would easily solve the problem without workarounds.
In Docker and docker-compose you are able to map ports the follwing way:
127.0.0.1:80 : 80
That would open the port only for the local Machine. It enables reverse proxy to the Service without opening the Port to everyone.

Maybe you can add this to the Readme.

Containers cannot reach the external IP of their own server

I have manually added the after.rules settings that are listed here and all containers that have not been exposed via ufw route allow are no longer reachable from external networks. The only container that is routed and reachable from outside is the web proxy, which is what I have expected so far.

One of the internal containers is providing an SSO API endpoint that is proxied and available on an external address https://openid.domain.com/auth/realms/domain.com/.well-known/openid-configuration. This endpoint must be called on the external address to return the proper results, which is also working with the above configuration.

But unfortunately, the other containers are not able to access the external API of the same server, while they can access e.g. google.com. Once they call the API on their own server and use its external address, the requests time out.

Do you have any idea about why this might not work?

Allow traffic on specific subnet/interface

Hello!

I'm a user of Tailscale, and I need to connect to my container only from within the Tailscale network. I usually achieve this by only allowing connections to the tailscale0 which is the interface it uses.

This is my goto command to achieve this
sudo ufw allow in on tailscale0 to any port 9003

I don't use it, but Tailscale works with IPs from 100.64.0.0/10 subnet[1], so this would also work
sudo ufw allow from 100.64.0.0/10 to any port 9003

How could I achieve this with ufw-docker?
Thank you.

[1] What are these 100.x.y.z addresses?

after.rules not reloaded unless reboot

Happy new year!

First, thanks for the information. It works great in a swarm cluster.

But I have one small issue, how to completely disable firewall after these changes?

I tried ufw disable still not able to access container from public network.

Removed the new stuff added in /etc/ufw/after.rules, followed by a ufw reload and ufw disable did not work.

The only thing worked is to remove the new stuff in after.rules, and ufw disable and ufw disable then reboot.

Any quick way to turn off these rules without a reboot?

thanks

Allow mapped port

Service has port 5566 mapped to 22. -p 22:5566 How do I go about allow 22 thru the firewall?

Docker default IP

Hello,

the Howto didn't work for me because adding 172.16.0.0/12 in /etc/ufw/after.rules didn't allow the containers to communicate with each other.

adding 172.17.0.0/12 into the after.rules instead of 172.16.0.0/12 worked for me.

Am i missing something or why is everyone using 172.16.0.0/12?

Best regards

Doesn't work for me on 18.04

Ubuntu 18.04 stock docker.io package, LXD and libvirt installed and working.

I tried adding the rules manually AND with the ufw-docker script.

Doing iptables -I FORWARD -i br0 -o br0 -j ACCEPT is enough to get things working properly

I rebooted and tried to clear all iptables rules prior doing it:

iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT
iptables -t nat -F
iptables -t mangle -F
iptables -F
iptables -X

/etc/netplan/01-netcfg.yaml

# This file describes the network interfaces available on your system
# For more information, see netplan(5).
network:
  version: 2
  renderer: networkd
  ethernets:
    eno1:
      dhcp4: yes
      dhcp6: no
  bridges:
    br0:
      dhcp4: no
      dhcp6: no
      addresses:
        - 10.0.14.2/24
      gateway4: 10.0.14.1
      nameservers:
        addresses: 
        - 10.0.14.6
      interfaces:
        - eno1

# LANG=C ufw-docker/ufw-docker check

########## iptables -n -L DOCKER-USER ##########
Chain DOCKER-USER (1 references)
target     prot opt source               destination         
RETURN     all  --  10.0.0.0/8           0.0.0.0/0           
RETURN     all  --  172.16.0.0/12        0.0.0.0/0           
RETURN     all  --  192.168.0.0/16       0.0.0.0/0           
RETURN     udp  --  0.0.0.0/0            0.0.0.0/0            udp spt:53 dpts:1024:65535
ufw-user-forward  all  --  0.0.0.0/0            0.0.0.0/0           
DROP       tcp  --  0.0.0.0/0            192.168.0.0/16       tcp flags:0x17/0x02
DROP       tcp  --  0.0.0.0/0            10.0.0.0/8           tcp flags:0x17/0x02
DROP       tcp  --  0.0.0.0/0            172.16.0.0/12        tcp flags:0x17/0x02
DROP       udp  --  0.0.0.0/0            192.168.0.0/16       udp dpts:0:32767
DROP       udp  --  0.0.0.0/0            10.0.0.0/8           udp dpts:0:32767
DROP       udp  --  0.0.0.0/0            172.16.0.0/12        udp dpts:0:32767
RETURN     all  --  0.0.0.0/0            0.0.0.0/0           


########## diff /etc/ufw/after.rules ##########

Check done.

# ip a

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: enp6s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 52:54:00:19:7e:6c brd ff:ff:ff:ff:ff:ff
    inet6 fe80::5054:ff:fe19:7e6c/64 scope link 
       valid_lft forever preferred_lft forever
3: eno1: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc mq master br0 state DOWN group default qlen 1000
    link/ether 04:92:26:b7:b2:ef brd ff:ff:ff:ff:ff:ff
4: enp8s0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 04:92:26:b7:b2:f0 brd ff:ff:ff:ff:ff:ff
5: enp9s0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 04:92:26:b7:b2:f1 brd ff:ff:ff:ff:ff:ff
6: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 7e:ce:8a:44:bf:9d brd ff:ff:ff:ff:ff:ff
    inet 10.0.14.2/24 brd 10.0.14.255 scope global br0
       valid_lft forever preferred_lft forever
    inet6 fe80::7cce:8aff:fe44:bf9d/64 scope link 
       valid_lft forever preferred_lft forever
7: lxdbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether fe:01:d8:d0:9a:3d brd ff:ff:ff:ff:ff:ff
    inet 10.158.192.1/24 scope global lxdbr0
       valid_lft forever preferred_lft forever
    inet6 fe80::7ce8:48ff:fe91:c23d/64 scope link 
       valid_lft forever preferred_lft forever
8: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
    link/ether 52:54:00:e9:3f:be brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
       valid_lft forever preferred_lft forever
9: virbr0-nic: <BROADCAST,MULTICAST> mtu 1500 qdisc fq_codel master virbr0 state DOWN group default qlen 1000
    link/ether 52:54:00:e9:3f:be brd ff:ff:ff:ff:ff:ff
11: vethXTE297@if10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master lxdbr0 state UP group default qlen 1000
    link/ether fe:01:d8:d0:9a:3d brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::fc01:d8ff:fed0:9a3d/64 scope link 
       valid_lft forever preferred_lft forever
13: vethSNA55U@if12: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master lxdbr0 state UP group default qlen 1000
    link/ether fe:23:4e:45:ee:31 brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet6 fe80::fc23:4eff:fe45:ee31/64 scope link 
       valid_lft forever preferred_lft forever
15: vethDL9SLE@if14: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master lxdbr0 state UP group default qlen 1000
    link/ether fe:7b:b8:c7:8e:5d brd ff:ff:ff:ff:ff:ff link-netnsid 2
    inet6 fe80::fc7b:b8ff:fec7:8e5d/64 scope link 
       valid_lft forever preferred_lft forever
17: vethXWYAMQ@if16: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br0 state UP group default qlen 1000
    link/ether fe:e8:ca:b2:be:0a brd ff:ff:ff:ff:ff:ff link-netnsid 2
    inet6 fe80::fce8:caff:feb2:be0a/64 scope link 
       valid_lft forever preferred_lft forever
18: vnet0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master br0 state UNKNOWN group default qlen 1000
    link/ether fe:54:00:a0:8d:c4 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::fc54:ff:fea0:8dc4/64 scope link 
       valid_lft forever preferred_lft forever
20: veth487J41@if19: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master lxdbr0 state UP group default qlen 1000
    link/ether fe:c0:f1:e1:dc:35 brd ff:ff:ff:ff:ff:ff link-netnsid 3
    inet6 fe80::fcc0:f1ff:fee1:dc35/64 scope link 
       valid_lft forever preferred_lft forever
22: vethXKT7BH@if21: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br0 state UP group default qlen 1000
    link/ether fe:d6:0c:c1:99:65 brd ff:ff:ff:ff:ff:ff link-netnsid 3
    inet6 fe80::fcd6:cff:fec1:9965/64 scope link 
       valid_lft forever preferred_lft forever
24: vethVUQQ2D@if23: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master lxdbr0 state UP group default qlen 1000
    link/ether fe:22:de:ca:42:39 brd ff:ff:ff:ff:ff:ff link-netnsid 4
    inet6 fe80::fc22:deff:feca:4239/64 scope link 
       valid_lft forever preferred_lft forever
25: macvtap0@enp6s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 500
    link/ether 52:54:00:19:7e:6c brd ff:ff:ff:ff:ff:ff
    inet6 fe80::5054:ff:fe19:7e6c/64 scope link 
       valid_lft forever preferred_lft forever
26: vnet1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master br0 state UNKNOWN group default qlen 1000
    link/ether fe:54:00:db:12:2d brd ff:ff:ff:ff:ff:ff
    inet6 fe80::fc54:ff:fedb:122d/64 scope link 
       valid_lft forever preferred_lft forever
27: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:40:61:be:de brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:40ff:fe61:bede/64 scope link 
       valid_lft forever preferred_lft forever
29: vethd6281d7@if28: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether 7e:ef:8b:f8:66:94 brd ff:ff:ff:ff:ff:ff link-netnsid 5
    inet6 fe80::7cef:8bff:fef8:6694/64 scope link 
       valid_lft forever preferred_lft forever

Does this work with Docker swarm mode?

If so, how? I have a service with multiple published ports and I have no idea how configure UFW at this point.

On a single Docker node this little helper works fine, btw. 🙂

Docker inside docker

Hello, I have installed docker inside docker.
Let's call the root docker a and the inner docker b.
docker b is open despite ufw and ufw-docker settings in a.
a docker connected ports 1031 and 1032 (docker creation command)
b docker connects 1032 (docker creation command), a docker installs ufw income deny and ufw-docker and can access 1031 despite not allowing 1031 port.

IP addresses in ufw after.rules

In ufw after.rules you use 3 specific IP addresses. Is this global for Docker or I need to change to fit my setup?
Atm, I'm on VPS that has direct public IP on eth0. Any modifications required if not on local network behind a router?

Thanks

[Question] Exposing host ports

First of all thank you for creating this guide. Running into this problem and trying to find a good solution is very challenging as many other sources say to disable Dockers IPTables support which doesn't seem like a good solution. Having a good explanation of what you're trying to achieve and how it works is very helpful.

I want to have my server setup so that when I run ufw allow 80 that opens the hosts port 80 not the containers. Reading the The reason for choosing ufw-user-forward, not ufw-user-input section it seems like I could use ufw-user-input instead to achieve this but I'm not sure if that is correct.

My Qeuestion: If I use ufw-user-input will that mean that when I run a command like ufw allow 80 that would allow external connections to the service running on port 80 and not the any containers running on 80?

Edit

For clarity, I have my container setup using -p 8080:80 and I have Nginx running on the host forwarding external requests on port 80 to port 8080. I don't want anyone externally to be able to access 8080 directly, only port 80.

Does not work after reboot ?

Hi @chaifeng and thank you for your work.
The trick seems to work until you reboot the server.

I applied the modifications to after.rules, enabled the firewall and limited access to a httpd container (added ufw route allow 80 + ssh => no problems here
However once i reboot the server, despite ufw being still active (systemctl Active: active (exited) and ufw Status: active) the container is exposed to public traffic
Host ports are still protected

any ideas ?
docker@ 19.03.3
ufw @ 0.36

Container restart requires new rules

Restarting a container (system reboot, docker restart, etc) causes containers to start with different ips and so the rules stop working. This means that if a service fails and has to restart, unsupervised, this will cause downtime.

The point of containers is being ephemeral, so hopefully there's a workaround?

Docker can access internet after: ufw default deny outgoing

I am trying to create a jailed machine to prevent the docker containers run there from accessing internet other than whitelisted hosts.

To that end i tried to use
ufw default deny outgoing

I found this bug report #12 and have applied the first option described there but it still does not prevent outgoing commections.

I thested this by running (image downloaded earlier)
docker -it debian:buster bash
$ apt-get update

and the image still could access the apt servers.

Is there any solution to fix this using ufw-docker or do I have to bite the bullet and use raw iptables?

UFW is disabled or you are not root user

Hi, in a test server with Ubuntu 18.04 I've tried to use your tool and I've got this error:

root@stage:/opt/ufw-docker/ufw-docker# ufw-docker install
ERROR: UFW is disabled or you are not root user.

Ufw is enabled with these rules:
Anywhere ALLOW 79.8.127.0
Anywhere ALLOW 192.168.169.0/24

Could you help me?
Thnx

Not working from container to host

I'm trying to access a service running on the host from a container.
I'm testing with nc -l 9900 on the host, and nc 172.18.0.1 9900 in the container.
It works with ufw disabled.
It doesn't work with ufw enabled. Here is the DOCKER-USER chain:

$ sudo iptables -L DOCKER-USER
Chain DOCKER-USER (1 references)
target     prot opt source               destination
RETURN     all  --  10.0.0.0/8           anywhere
RETURN     all  --  172.16.0.0/12        anywhere
RETURN     all  --  192.168.0.0/16       anywhere
RETURN     udp  --  anywhere             anywhere             udp spt:domain dpts:1024:65535
ufw-user-forward  all  --  anywhere             anywhere
DROP       tcp  --  anywhere             192.168.0.0/16       tcp flags:FIN,SYN,RST,ACK/SYN
DROP       tcp  --  anywhere             10.0.0.0/8           tcp flags:FIN,SYN,RST,ACK/SYN
DROP       tcp  --  anywhere             172.16.0.0/12        tcp flags:FIN,SYN,RST,ACK/SYN
DROP       udp  --  anywhere             192.168.0.0/16       udp dpts:0:32767
DROP       udp  --  anywhere             10.0.0.0/8           udp dpts:0:32767
DROP       udp  --  anywhere             172.16.0.0/12        udp dpts:0:32767
RETURN     all  --  anywhere             anywhere

That looks to me like it should work. Which means the RETURN lines aren't matching for some reason? If I look through all of iptables -L, I don't see 172.16 mentioned anywhere else.

Ubuntu 18.04.3.
Docker 18.09.7

Any ideas?

Feature request: Automate ufw rules with docker engine?

Hi, I've been a huge fan of this script for a while now. One thing that boggles my mind is it's pretty manual and it could be improved.
For example this nginx-proxy software runs as regular docker image and updates nginx rules as needed based on other docker image's ENVs. It solves manual rule update issue and less error prone.
I think it maybe possible to follow similar approach. For example, ufw-docker-agent will run as regular docker container on the host and will be connected to docker socket. It'll update ufw rules based on new container's ENVs. Containers should run with special ENVs if we want to expose them to public internet. like: docker run -d -e UFW_ALLOW_PORT=80 nginx

Another example is Traefik. Traefik runs as regular container on the host and connected to docker socket. It scans new containers to see if it includes special "labels" and updates its rules based on container labels.

Does anyone think such implementation is possible?

EDIT: Okay, I hacked together some crap and got working code, here is the repo. All you have to do is run the container with special label UFW_MANAGED=TRUE. Please let me know your feedbacks. Of course code is crap, but hopefully it works.

Deny outgoing connections from containers

Thank you for this great repo. I want to prevent containers to connect to certain IP addresses, i.e. I want ufw deny out to <dest> to stop connections from containers to dest. I tried with ufw route deny out on docker0 to <dest>, but it does not work. I also tried to change the interface to eth0 and all other interfaces I have, but connections are still allowed. These are all the related rules I have currently:

<dest>                DENY OUT    Anywhere
<dest> on docker0     DENY FWD    Anywhere
<dest> on eth0        DENY FWD    Anywhere
<dest> on lo          DENY FWD    Anywhere
<dest> on veth4ca42e2 DENY FWD    Anywhere
<dest> on vethe1dfed2 DENY FWD    Anywhere

This blocks pings from the host, but not from docker containers.

Constant literal 172.16.0.x / docker0 network --> auto-detect

On my various Ubuntu 20.04 systems, the default docker0 network seems to be 172.17.0.1/16, while this script is hard-coded to 172.16.0.0/12

I've seen other sources suggest finding this via:

ip addr show docker0

Or grabbing the host address via:

HOST_IP=$(ip addr show docker0 | grep "inet " | awk '{print $2}' | awk -F/ '{print $1}')
# 172.17.0.1

ERROR: UFW is disabled or you are not root user

Even everything is running and enable I keep on receiving this error so the script is not usable
● ufw.service - Uncomplicated firewall
Loaded: loaded (/lib/systemd/system/ufw.service; enabled; vendor preset: enabled)
Active: active (exited) since Sun 2020-01-05 13:56:12 CET; 6min ago
Docs: man:ufw(8)
Process: 9017 ExecStart=/lib/ufw/ufw-init start quiet (code=exited, status=0/SUCCESS)
Main PID: 9017 (code=exited, status=0/SUCCESS)

gen 05 13:56:12 CORNERWS systemd[1]: Starting Uncomplicated firewall...
gen 05 13:56:12 CORNERWS ufw-init[9017]: Firewall already started, use 'force-reload'
gen 05 13:56:12 CORNERWS systemd[1]: Started Uncomplicated firewall.

Doesn't with other locale

The script won't work with e.g. german locale. This is due to ufw status printing e.g. Status: Aktiv instead of Status: active which is expected in the script. Not sure if this is the only instance where the locale matters right now.

rationale for choosing networks

Hi,

-A DOCKER-USER -j RETURN -s 10.0.0.0/8

what is the rationale behind the chosen networks?
This does work in most cases but might need adaption in certain cases?

For example I have changed the address-pool in my docker start file like so:

  --default-address-pool=base=10.120.0.0/16,size=24 

So its seems I was just lucky enough to see ufw-docker working due to picking a network that is part of the default setup.

Would be nice to mention this somewhere and have some way to change the networks so ufw-docker check and ufw-docker install would fit an adapted docker setup.

Not able to connect to container through WAN

I have installed this amazing project but I don't seem to be able to connect to my container.

The rule is added (port 9999 mapped):

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

How can I debug this ?

Changing subnet doesn't "take"

My Docker i/f sits at 172.18.0.1, not 172.16. But I didn't notice this until after running ufw-docker and seeing it not work. If I edit /etc/ufw/after.rules and run ufw reload, I still get this from iptables -L DOCKER-USER

Chain DOCKER-USER (1 references)
target     prot opt source               destination         
RETURN     all  --  10.0.0.0/8           anywhere            
RETURN     all  --  172.16.0.0/12        anywhere            
RETURN     all  --  192.168.0.0/16       anywhere            
RETURN     udp  --  anywhere             anywhere             udp spt:domain dpts:1024:65535
ufw-user-forward  all  --  anywhere             anywhere            
DROP       tcp  --  anywhere             192.168.0.0/16       tcp flags:FIN,SYN,RST,ACK/SYN
DROP       tcp  --  anywhere             10.0.0.0/8           tcp flags:FIN,SYN,RST,ACK/SYN
DROP       tcp  --  anywhere             172.16.0.0/12        tcp flags:FIN,SYN,RST,ACK/SYN
DROP       udp  --  anywhere             192.168.0.0/16       udp dpts:0:32767
DROP       udp  --  anywhere             10.0.0.0/8           udp dpts:0:32767
DROP       udp  --  anywhere             172.16.0.0/12        udp dpts:0:32767
RETURN     all  --  anywhere             anywhere            

I saw your note in README.md about this, and rebooted... same thing.

Any ideas why? I'm wondering if it has something to do with the netmask being 12 bits instead of 16 (so therefore not covering the .16. This probably is more a ufw/iptables issue, but I'd appreciate any insights.

Dns packets are dropped by 50%

By adding those rules I had 50% change to get dns answers from an upsteam dns server.

How to reproduce.

  • start a dnsmasq container that forwards all queries to 1.1.1.1 or 8.8.8.8
  • shell into dnsmasq container
  • dig www.google.com @127.0.0.1

You have 50% chance to get an answer and 50% chance to have a timeout

tcpdump from the host says that answer from upstream (1.1.1.1 or 8.8.8.8) is correctly received

By flushing the DOCKER-USER table the problem is gone

Cannot access service on host from container

Should the following setup work after installing ufw-docker?:

  1. a database service runs on the host
  2. a docker container on the same host needs access to the database (1)

The host is not on a private subnet, but on a public IP. That is why UFW is essential for this host.

After 'ufw disable', access from the container to the host is possible.

After 'ufw enable' I am getting the following lines in syslog when I try to connect from the container to the database on the host:

[UFW BLOCK] IN=docker0 OUT= PHYSIN=vethc149a32 MAC=xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx SRC=172.17.0.2 DST=yy.yy.yy.yy LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=58585 DF PROTO=TCP SPT=45360 DPT=5432 WINDOW=29200 RES=0x00 SYN URGP=0

yy.yy.yy.yy is the (public) IP of my host

I added the following ufw allow rules, but still cannot connect:

sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
Anywhere           ALLOW       172.16.0.0/16
yy.yy.yy.yy           ALLOW       172.16.0.0/16
5432                    ALLOW       172.16.0.0/16

5432                    ALLOW FWD   172.16.0.0/16
yy.yy.yy.yy           ALLOW FWD   172.16.0.0/16

Is it possible to somehow prevent the [UFW BLOCK] (see log) from happening?

Thanks,

How should nmap look?

If I default deny using ufw and then just allow port 443 & 80, for example, then shouldn't all other ports be closed if I nmap externally? I've used your exact configuration with docker & ufw - but I'm not sure how this is supposed to behave - or if my services are really being protected by ufw. I just used the typical "ufw default deny" - perhaps that must be changed in this configuration?
Thanks.

ufw/iptables and containers connected to multiple networks

This is more of a question rather than a specific bug or issue with the ufw-docker script, but I'm hoping this can be solved using ufw-docker.

When I want to expose a port from a container connected to multiple networks, the iptables rules created by docker don't seem to update correctly.

For example, here are the network settings for a test container connected to a default network created by compose (compose_default), and also manually connected to a network called frontend:

"NetworkSettings": {
            "Bridge": "",
            "SandboxID": "07088f91dd0c58e26a33389ca25903516e34552e1fb9f441ac3e89b342920d02",
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "Ports": {
                "5000/tcp": [
                    {
                        "HostIp": "0.0.0.0",
                        "HostPort": "5000"
                    },
                    {
                        "HostIp": "::",
                        "HostPort": "5000"
                    }
                ]
            },
            "SandboxKey": "/var/run/docker/netns/07088f91dd0c",
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "",
            "Gateway": "",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "",
            "IPPrefixLen": 0,
            "IPv6Gateway": "",
            "MacAddress": "",
            "Networks": {
                "compose_default": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": [
                        "test",
                        "eb2326805f45"
                    ],
                    "NetworkID": "21ecdc8b989d86537fd4b87e09b4ebab4041de60261d83b4f4c64541e0a6a919",
                    "EndpointID": "a19da7d18d5ed659b2df167245f324cbc333ebd92c132fc91a0e224914b44dc9",
                    "Gateway": "172.18.0.1",
                    "IPAddress": "172.18.0.47",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": ####,
                    "DriverOpts": null
                },
                "frontend": {
                    "IPAMConfig": {},
                    "Links": null,
                    "Aliases": [
                        "eb2326805f45"
                    ],
                    "NetworkID": "dda768c0a205587c3da94511181c5c106c8ce7f5c3b2ed5b27f8f493825c53ca",
                    "EndpointID": "4d114c0866ac97c0b034f9cfdaca9ea917cc2cd5ba20167dee93f2add14ef3d8",
                    "Gateway": "172.19.0.1",
                    "IPAddress": "172.19.0.2",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": ####,
                    "DriverOpts": {}
                }
            }
        }
    }

I have already modified the existing ufw-docker script to be able to specify which network to grab the ip address from. So I can add a rule with sudo ufw-docker allow test 5000/tcp frontend (note the network specification as the last argument), resulting in the following rule being added:

ufw route allow proto tcp from any to 172.19.0.2 port 5000 comment allow test 5000/tcp

However, while I initially assumed this would open up port 5000 for external connections (as it would normally), this is not the case:

Jul  9 11:22:19 #### kernel: [257879.761018] [UFW DOCKER BLOCK] IN=eno1 OUT=br-21ecdc8b989d MAC=##### SRC=##### DST=172.18.0.47 LEN=52 TOS=0x00 PREC=0x00 TTL=118 ID=26924 DF PROTO=TCP SPT=28173 DPT=5000 WINDOW=64240 RES=0x00 SYN URGP=0
Jul  9 11:22:20 #### kernel: [257880.756708] [UFW DOCKER BLOCK] IN=eno1 OUT=br-21ecdc8b989d MAC=##### SRC=##### DST=172.18.0.47 LEN=52 TOS=0x00 PREC=0x00 TTL=118 ID=26925 DF PROTO=TCP SPT=28173 DPT=5000 WINDOW=64240 RES=0x00 SYN URGP=0
Jul  9 11:22:22 #### kernel: [257882.755631] [UFW DOCKER BLOCK] IN=eno1 OUT=br-21ecdc8b989d MAC=##### SRC=##### DST=172.18.0.47 LEN=52 TOS=0x00 PREC=0x00 TTL=118 ID=26928 DF PROTO=TCP SPT=28173 DPT=5000 WINDOW=64240 RES=0x00 SYN URGP=0
Jul  9 11:22:26 #### kernel: [257886.761023] [UFW DOCKER BLOCK] IN=eno1 OUT=br-21ecdc8b989d MAC=##### SRC=##### DST=172.18.0.47 LEN=52 TOS=0x00 PREC=0x00 TTL=118 ID=26935 DF PROTO=TCP SPT=28173 DPT=5000 WINDOW=64240 RES=0x00 SYN URGP=0

This is because for whatever reason, the packets are being directed to the container's ip within the compose_default network, which are then obviously dropped because no rules were added for that IP. I believe the issue lies not necessarily within ufw-docker, but rather docker's iptables rules itself. Looking at the DOCKER chain, there are only ACCEPT rules for the compose_default network IP, not for the frontend network:

Chain DOCKER (9 references)
pkts bytes target     prot opt in     out     source               destination         
.....
0     0 ACCEPT     tcp  --  !br-21ecdc8b989d br-21ecdc8b989d  0.0.0.0/0            172.18.0.47          tcp dpt:5000
....

So what should be the way to go here? Should I add a rule ufw rule for each network the container is connected to? Or is there a way to tell docker which network it should create its iptables rules for? Or is there a way within ufw-docker to do this?

Logging of forwarded connections

Hi,

when adding the "workaround" for docker from your manual, I was unable to get any logging whats going wrong there.

I've replaced it like this:

# BEGIN UFW AND DOCKER
*filter
:ufw-user-forward - [0:0]
:ufw-logging-route-deny - [0:0]
:DOCKER-USER - [0:0]
:DOCKER-USER-DENY - [0:0]
-A DOCKER-USER -s 172.16.0.0/12 -j RETURN
...
-A DOCKER-USER -j ufw-user-forward

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

-A DOCKER-USER -j RETURN

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

COMMIT
# END UFW AND DOCKER

(and a similar one for ipv6)

like this I get

[UFW ROUTE BLOCK] IN=enp0s3 OUT=br-...

messages if someone tries to access a "dockererized" port and where I forgot to add a proper ufw route allow rule and not silently ignore it.

Perhaps this is helpful for someone or can even integrated into the Readme?

Container with multiple IPs override their own rules instead of adding them

I have a Traefik container that is connected to 3 networks.
ufw-docker correctly detects all 3 IPs associated with the container but when adding the ufw rules for the 2 ports the previous set rule gets immediately deleted.
Check image below (note: the command also starts with removing "old" routes, those are just 2 from a prior run of the same command)

image

Block specific ip from accessing port 443

I have a service on port 443,
How I can block specific IP from accessing port 443

I tried this:

ufw insert 1 deny from 89.179.6.129 to any port 443
iptables -A INPUT -s 89.179.6.129 -p tcp --destination-port 443 -j DROP

the user can still access the service exposed with:

ufw route allow proto tcp from any to any port 443

thanks for the help?

Is there an elegent way to use with docker-compose?

Hello and thank you for the good library,
I solved the problem of a docker container as a docker-compose service to access the local services exposed on the host server by using the following command
sudo ufw allow in on br-122345655 from {docker_sub_net_cidr} to {host_server_ip} port {service_port}
But I wonder if there is a more elegant way to achieve the same result.
The ufw was blocking the port before adding the command.

service allow from ip

Hi,

Thanks for this amazing project. It works real good in swarm mode !
I was wondering if it is possible to restrain opening a service port for only a custom IP ?

eg something like sudo ufw-docker service allow my-service from 123.45.67.89 1234/tcp ?

Moreover, is it possible to open multiple ports at the same for a service ?
Something like sudo ufw-docker service allow my-service 1234:1238/tcp ?

关于Clash容器的问题

这个解决方案很有用,但是同时我的ubuntu里跑了一个clash的容器做网络代理,然后代理就挂了,这个可能的原因和解决方案是啥。clash容器的网络是host模式,也设置了http_proxy.

How to block outgoing traffic from container

I have a container which is listening on port 80. But I don't want the container to be able to establish connections to this port. Or any other port for that matter. Is this the right place to ask this question? Sorry if it is not, I'm rather new to Docker, UFW and TCP security.

Examples and documentation is incomprehensive

Examples and documentation is incomprehensive and relies on analogies from the main ufw command.
Also, the documentation totally ignored mentioning docker-compose and how to work with it.

Can't connect from different docker network to published docker service

I have tested the following:
containera with networka has a webservice running at port 80, which is published to any with ufw-docker.
containerb with networkb should now be able to connect to http://containera:80, like it is without ufw, but unfortunately it doesn't work.
Connecting to the host with port 80 from outside works as expected.

Did I do something wrong or is there something missing?

iptables migration to nftables on debian

Recently debian has switched to nftables by defaut (buster/unstable)

Debian is using builtin alternatives system to provide iptables command by either iptables-nft or iptables-legacy.

Upstream docker/libnetwork has incorporated this by updating libnetwork to use 'iptables-legacy' if available moby/libnetwork#2285

I updated ufw-docker to use iptables-legacy and it seems to work. Otherwise it would not detect the DOCKER related chains as they'd be hidden in iptables-nft.

More on the docker story in regards to iptables/nftables can be found on this issue: moby/moby#26824 it seems distros are slowly picking up nftables causing docker some troubles ....

containers are still accessible publicly

I have run ufw-docker install but containers are still accessible publicly without opening any ports via ufw.
I guess the issue is that I have two nics. One public and one local. I added the public ip to the after.rules but that did not fix anything.
I tried resetting ufw and rebooting after adding the rules but still accessible.

Anyone got any idea on what the issue might be?

########## iptables -n -L DOCKER-USER ##########
Chain DOCKER-USER (0 references)
target     prot opt source               destination         
ufw-user-forward  all  --  0.0.0.0/0            0.0.0.0/0           
RETURN     all  --  10.0.0.0/8           0.0.0.0/0           
RETURN     all  --  172.16.0.0/12        0.0.0.0/0           
RETURN     all  --  192.168.0.0/16       0.0.0.0/0           
RETURN     udp  --  0.0.0.0/0            0.0.0.0/0            udp spt:53 dpts:1024:65535
ufw-docker-logging-deny  tcp  --  0.0.0.0/0            192.168.0.0/16       tcp flags:0x17/0x02
ufw-docker-logging-deny  tcp  --  0.0.0.0/0            10.0.0.0/8           tcp flags:0x17/0x02
ufw-docker-logging-deny  tcp  --  0.0.0.0/0            172.16.0.0/12        tcp flags:0x17/0x02
ufw-docker-logging-deny  tcp  --  0.0.0.0/0            XX.XXX.XXX.X         tcp flags:0x17/0x02
ufw-docker-logging-deny  udp  --  0.0.0.0/0            192.168.0.0/16       udp dpts:0:32767
ufw-docker-logging-deny  udp  --  0.0.0.0/0            10.0.0.0/8           udp dpts:0:32767
ufw-docker-logging-deny  udp  --  0.0.0.0/0            172.16.0.0/12        udp dpts:0:32767
ufw-docker-logging-deny  udp  --  0.0.0.0/0            XX.XXX.XXX.X         udp dpts:0:32767
RETURN     all  --  0.0.0.0/0            0.0.0.0/0           


########## diff /etc/ufw/after.rules ##########
--- /etc/ufw/after.rules	2021-01-22 22:03:42.366124108 +0100
+++ /tmp/tmp.VUESxreQu9	2021-01-23 23:44:16.423945619 +0100
@@ -44,11 +44,9 @@
 -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 tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d XX.XXX.XXX.X
 -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 ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d XX.XXX.XXX.X
 
 -A DOCKER-USER -j RETURN
Status: active

     To                         Action      From
     --                         ------      ----
[ 1] 1001                       ALLOW IN    Anywhere                   # ssh
[ 2] 192.168.0.3 4695 on enp3s0 ALLOW FWD   Anywhere                   (out) # vnc
[ 3] Samba on enp3s0            ALLOW IN    Anywhere                   # smb
[ 4] 172.20.0.3 443/tcp         ALLOW FWD   Anywhere                   # allow traefik 443/tcp
[ 5] 172.20.0.3 80/tcp          ALLOW FWD   Anywhere                   # allow traefik 80/tcp
[ 6] 172.20.0.16 49161/tcp      ALLOW FWD   Anywhere                   # allow rtorrent 49161/tcp
[ 7] 172.20.0.16 49161/udp      ALLOW FWD   Anywhere                   # allow rtorrent 49161/udp
[ 8] 172.20.0.6 32400/tcp       ALLOW FWD   Anywhere                   # allow plex 32400/tcp

Doesn't work with IPV6

So I took a shot at trying to get this to work with IP V6 addresses with no luck. If I disable the ufw service i'm able to access my site using the V6 address, but when I enable ufw the connection times out. I found /etc/ufw/after6.rules and tried to modify it to work, but I must be doing something wrong. My guess is it's something with the V6 subnet.

# BEGIN UFW AND DOCKER
*filter
:ufw6-user-forward - [0:0]
:DOCKER-USER - [0:0]
-A DOCKER-USER -j RETURN -s fe80::/10
-A DOCKER-USER -p udp -m udp --sport 53 --dport 1024:65535 -j RETURN

-A DOCKER-USER -j ufw6-user-forward

-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d fe80::/10
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d fe80::/10

-A DOCKER-USER -j RETURN
COMMIT
# END UFW AND DOCKER

Here is my ifconfig:

docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        inet6 fe80::1  prefixlen 64  scopeid 0x20<link>
        ether 02:42:0e:75:6d:9a  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

ufw status

Status: active
Logging: off
Default: deny (incoming), allow (outgoing), deny (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW IN    Anywhere
22/tcp (v6)                ALLOW IN    Anywhere (v6)

80/tcp                     ALLOW FWD   Anywhere
443/tcp                    ALLOW FWD   Anywhere
80/tcp (v6)                ALLOW FWD   Anywhere (v6)
443/tcp (v6)               ALLOW FWD   Anywhere (v6)

ufw-docker status error!

Hi friends:

I got an error as follows, after installed ufw-docker and run ufd-docker status...

/usr/local/bin/ufw-docker: line 276: files_to_be_deleted[@]: unbound variable

My linux version is: Ubuntu 14.04.4 LTS (GNU/Linux 3.13.0-100-generic x86_64)
And the bash version: GNU bash, version 4.3.11(1)-release (x86_64-pc-linux-gnu)

Any comment would be appreciated. Thanks!

Publish multiple docker with same port

Hi,
I've followed you rinstruction and I was able to block all the port except the ones I needed, but now...I need to expose a second webserver on a different port, how do I do this?

Teamspeak doesn't show correct client address.

Hello, I'm hosting a teamspeak server using this panel. When I connect to the teamspeak server my client ip is 172.18.0.1 instead of my public ip. Is there maybe a solution to this problem or could anyone point me in the right direction. I'm by no mean an expert but willing to learn all about new topics.

Output of ifconfig:

pterodactyl0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.18.0.1  netmask 255.255.0.0  broadcast 172.18.255.255
        inet6 fdba:17c8:6c94::1011  prefixlen 64  scopeid 0x0<global>
        inet6 fe80::42:32ff:fe43:8a1  prefixlen 64  scopeid 0x20<link>
        inet6 fe80::1  prefixlen 64  scopeid 0x20<link>
        ether 02:42:32:43:08:a1  txqueuelen 0  (Ethernet)
        RX packets 1653  bytes 167191 (163.2 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 1658  bytes 133446 (130.3 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

Added to after.rules

# BEGIN UFW AND DOCKER
*filter
:ufw-user-forward - [0:0]
:DOCKER-USER - [0:0]
-A DOCKER-USER -j RETURN -s 10.0.0.0/8
-A DOCKER-USER -j RETURN -s 172.18.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-user-forward

-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.18.0.0/12
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 192.168.0.0/16
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 10.0.0.0/8
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 172.18.0.0/12
-A DOCKER-USER -j RETURN
COMMIT
# END UFW AND DOCKER

Image of teamspeak

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.