Skip to content

Commit

Permalink
feat: implement port specific rules, fix #29
Browse files Browse the repository at this point in the history
  • Loading branch information
shinebayar-g committed Nov 3, 2021
1 parent 10247c0 commit ec45d84
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 9 deletions.
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ This project solves that problem by listening to the Docker API events.

## Supported labels

| Label key | Value | Example |
| -------------- | -------------------------------------------------- | -------------------------------------------------------- |
| UFW_MANAGED\* | TRUE | `-l UFW_MANAGED=TRUE` |
| UFW_ALLOW_FROM | CIDR/IP-Comment , Semicolon separated, default=any | `-l UFW_ALLOW_FROM=192.168.3.0/24-LAN;10.10.0.50/32-DNS` |
| Label key | Value / Syntax | Example |
| -------------- | --------------------------------------------------------------- | ----------------------------------------------------------- |
| UFW_MANAGED\* | TRUE | `-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` |

## Example

Expand All @@ -38,7 +38,7 @@ services:
- '8081:81'
labels:
UFW_MANAGED: 'TRUE'
UFW_ALLOW_FROM: '172.10.50.32;192.168.3.0/24;10.10.0.50/32-LAN'
UFW_ALLOW_FROM: '172.10.50.32;192.168.3.0/24;10.10.0.50/32-8080-LAN'
networks:
- my-network

Expand All @@ -60,6 +60,9 @@ networks:
# Allow from certain IP address, CIDR ranges + comments
➜ docker run -d -p 8086:86 -p 8087:87 -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 to different Port + comments
➜ docker run -d -p 8088:88 -p 8089:89 -p 8090:90 -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
Expand All @@ -82,6 +85,9 @@ To Action From
172.17.0.5 87/tcp ALLOW FWD 172.10.5.0 # funny_aryabhata:9eb642f07bde
172.17.0.5 87/tcp ALLOW FWD 192.168.3.0/24 # funny_aryabhata:9eb642f07bde LAN
172.17.0.5 87/tcp ALLOW FWD 10.10.0.50 # funny_aryabhata:9eb642f07bde DNS
172.17.0.6 88/tcp ALLOW FWD Anywhere # awesome_leavitt:6ebdb0c87a56 Internet
172.17.0.6 89/tcp ALLOW FWD 192.168.3.0/24 # awesome_leavitt:6ebdb0c87a56 LAN
172.17.0.6 90/tcp ALLOW FWD 10.10.0.50 # awesome_leavitt:6ebdb0c87a56
```

Once containers are stopped their ufw entries will be deleted.
Expand Down
33 changes: 29 additions & 4 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"net"
"os/exec"
"strconv"
"strings"

"github.com/docker/docker/api/types"
Expand All @@ -16,6 +17,7 @@ import (

type ufwSource struct {
CIDR string
port string
comment string
}

Expand Down Expand Up @@ -56,8 +58,19 @@ func handleUfwRule(ch <-chan ufwEvent) {
}
}

if len(ip) > 1 {
ufwSourceList = append(ufwSourceList, ufwSource{CIDR: ip[0], comment: fmt.Sprintf(" %s", ip[1])})
// Example: 172.10.5.0-LAN or 172.10.5.0-80
if len(ip) == 2 {
if _, err := strconv.Atoi(ip[1]); err == nil {
// case: 172.10.5.0-80
ufwSourceList = append(ufwSourceList, ufwSource{CIDR: ip[0], port: ip[1]})
} else {
// case: 172.10.5.0-LAN
ufwSourceList = append(ufwSourceList, ufwSource{CIDR: ip[0], comment: fmt.Sprintf(" %s", ip[1])})
}
// Example: 172.10.5.0-80-LAN
} else if len(ip) == 3 {
ufwSourceList = append(ufwSourceList, ufwSource{CIDR: ip[0], port: ip[1], comment: fmt.Sprintf(" %s", ip[2])})
// Should be just IP address without comment or port specified.
} else {
ufwSourceList = append(ufwSourceList, ufwSource{CIDR: ip[0]})
}
Expand All @@ -67,20 +80,32 @@ func handleUfwRule(ch <-chan ufwEvent) {
}

containerIP := event.container.NetworkSettings.IPAddress
// If docker-compose, container IP is defined here
if containerIP == "" {
networkMode := event.container.HostConfig.NetworkMode.NetworkName()
containerIP = event.container.NetworkSettings.Networks[networkMode].IPAddress
}

for _, source := range ufwSourceList {
var cmd *exec.Cmd
var containerPort string

if source.port == "" {
containerPort = port.Port()
} else {
// Because we're overriding port.Proto() loop element with something static,
// it'll create duplicate ufw rules. But ufw service handles that correctly.
containerPort = source.port
}

if event.msg.Action == "start" {
cmd = exec.Command("sudo", "ufw", "route", "allow", "proto", port.Proto(), "from", source.CIDR, "to", containerIP, "port", port.Port(), "comment", event.msg.Actor.Attributes["name"]+":"+event.msg.ID[:12]+source.comment)
cmd = exec.Command("sudo", "ufw", "route", "allow", "proto", port.Proto(), "from", source.CIDR, "to", containerIP, "port", containerPort, "comment", event.msg.Actor.Attributes["name"]+":"+event.msg.ID[:12]+source.comment)
fmt.Println("ufw-docker-automated: Adding rule:", cmd)
} else {
cmd = exec.Command("sudo", "ufw", "route", "delete", "allow", "proto", port.Proto(), "from", source.CIDR, "to", containerIP, "port", port.Port(), "comment", event.msg.Actor.Attributes["name"]+":"+event.msg.ID[:12]+source.comment)
cmd = exec.Command("sudo", "ufw", "route", "delete", "allow", "proto", port.Proto(), "from", source.CIDR, "to", containerIP, "port", containerPort, "comment", event.msg.Actor.Attributes["name"]+":"+event.msg.ID[:12]+source.comment)
fmt.Println("ufw-docker-automated: Deleting rule:", cmd)
}

var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
Expand Down

0 comments on commit ec45d84

Please sign in to comment.