Skip to content

Commit 3f5acc2

Browse files
author
angelnu
committed
first release
1 parent f8c5178 commit 3f5acc2

13 files changed

+205
-78
lines changed

Dockerfile

+11-22
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,16 @@
1-
FROM golang:1.16 AS build
2-
3-
WORKDIR /workspace
4-
ENV GO111MODULE=on
5-
6-
COPY *.go go.mod *.sum ./
7-
8-
# Build
9-
RUN go mod download
10-
11-
RUN CGO_ENABLED=0 go build -o app -ldflags '-w -extldflags "-static"' .
12-
13-
#Test
14-
RUN CCGO_ENABLED=0 go test -v .
15-
16-
# Use distroless as minimal base image to package the manager binary
17-
# Refer to https://github.com/GoogleContainerTools/distroless for more details
18-
# debug tag adds a shell (not recommended for prod)
19-
FROM gcr.io/distroless/static:nonroot
1+
FROM alpine:3.13.5
202
WORKDIR /
21-
COPY --from=build /workspace/app /app/app
22-
USER nonroot:nonroot
233

24-
ENTRYPOINT ["/app/app"]
4+
# iproute2 -> bridge
5+
# bind-tools -> bind
6+
# dhclient -> get dynamic IP
7+
# dnsmasq -> DNS & DHCP server
8+
# coreutils -> need REAL chown and chmod for dhclient (it uses reference option not supported in busybox)
9+
RUN apk add --no-cache coreutils dnsmasq iproute2 bind-tools dhclient
10+
11+
COPY config /config
12+
COPY bin /bin
13+
CMD [ "/bin/entry.sh" ]
2514

2615
ARG IMAGE_SOURCE
2716
#https://github.com/k8s-at-home/template-container-image

Makefile

+1-25
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,6 @@
11

22
# Image URL to use all building/pushing image targets
3-
IMG ?= template-container-image:latest
4-
5-
# Run tests
6-
test: build
7-
go test -v .
8-
9-
# Build manager binary
10-
build: fmt vet
11-
go build -o app main.go
12-
13-
# Download dependencies
14-
download:
15-
go mod download
16-
17-
# Download dependencies
18-
tidy: download
19-
go mod tidy
20-
21-
# Run go fmt against code
22-
fmt: tidy
23-
go fmt ./...
24-
25-
# Run go vet against code
26-
vet: tidy
27-
go vet ./...
3+
IMG ?= pod-gateway:latest
284

295
# Build the docker image
306
docker-build:

README.md

+16-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1-
# template-container-image
1+
# pod-gateway
22

3-
Template for k8s-at-home containers. You can use it to as base to create your container.
3+
This container includes scripts used to route traafic from pods through another gateway pod. Typically
4+
the gateway pod then runs a openvpn client to forward the traffic.
5+
6+
The connection between the pods is done via a vxlan. The gatway provides a DHCP server to let client
7+
pods to get automatically an IP.
8+
9+
Ougoing traffic is masqueraded (SNAT). It is also possible to define port forwardind so ports of client
10+
pods can be reached from the outside.
411

512
The [.github](.github) folder will get PRs from this template so you can apply the latest workflows.
613

@@ -13,15 +20,13 @@ You need to create the following secrets (not needed within the k8s-at-home org
1320

1421
## How to build
1522

16-
1. Build and test local
17-
```bash
18-
make
19-
```
20-
2. Build the container
21-
```bash
22-
make docker-build
23-
```
23+
1. Build the container
24+
```bash
25+
make
26+
```
2427

25-
Check the [Makefile] for other build targets
28+
Testing requires multiple containers - see
29+
[Helm chart](https://github.com/k8s-at-home/charts/tree/master/charts/stable/pod-gateway-setter)
30+
and check the [Makefile] for other build targets.
2631

2732

bin/dnsmasq.sh

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#!/bin/sh -ex
2+
3+
cat /config/settings.sh
4+
. /config/settings.sh
5+
6+
#Block default output traffic
7+
iptables --policy OUTPUT DROP
8+
9+
#create config
10+
echo "interface=vxlan0
11+
bind-interfaces
12+
dhcp-range=${VXLAN_IP_NETWORK}.20,${VXLAN_IP_NETWORK}.200,12h
13+
server=/local/${DNS_ORG}">>/etc/dnsmasq.conf
14+
15+
#Need to wait until new DNS server in /etc/resolv.conf is setup
16+
#TBD: find a better way
17+
sleep 10
18+
19+
exec dnsmasq -k

bin/entry.sh

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#!/bin/sh -ex
2+
3+
#Load main settings
4+
cat /config/settings.sh
5+
. /config/settings.sh
6+
7+
#in re-entry we need to remove the vxlan
8+
#on first entry set a routing rule to the k8s DNS server
9+
if ip addr|grep -q vxlan0; then
10+
ip link del vxlan0
11+
fi
12+
13+
14+
15+
K8S_GW_ROUTE=$(ip route get ${DNS_ORG}|head -1)
16+
K8S_GW_ROUTE=${K8S_GW_ROUTE%%uid*}
17+
ip route add $K8S_GW_ROUTE || /bin/true
18+
19+
#Delete default GW to prevent outgoing traffic to leave this docker
20+
echo "Deleting existing default GWs"
21+
ip route del 0/0 || /bin/true
22+
23+
24+
#After this point nothing should be reachable -> check
25+
if ping -c 1 -W 1000 8.8.8.8; then
26+
echo "WE SHOULD NOT BE ABLE TO PING -> EXIT"
27+
exit 255
28+
fi
29+
30+
#derived settings
31+
OPENVPN_ROUTER_IP="$(dig +short $OPENVPN_ROUTER_NAME @${DNS_ORG})"
32+
GW_ORG=$(route |awk '$1=="default"{print $2}')
33+
NAT_ENTRY="$(grep $(hostname) /config/nat.conf||true)"
34+
35+
#Create tunnel NIC
36+
ip link add vxlan0 type vxlan id $VXLAN_ID dev eth0 dstport 0 || true
37+
bridge fdb append to 00:00:00:00:00:00 dst $OPENVPN_ROUTER_IP dev vxlan0
38+
ip link set up dev vxlan0
39+
40+
#Configure IP and default GW though the VPN docker
41+
if [ -z "$NAT_ENTRY" ]; then
42+
echo "Get dynamic IP"
43+
dhclient -cf /config/dhclient.conf vxlan0
44+
else
45+
IP=$(echo $NAT_ENTRY|cut -d' ' -f2)
46+
VXLAN_IP="${VXLAN_IP_NETWORK}.${IP}"
47+
echo "Use fixed IP $VXLAN_IP"
48+
ip addr add $VXLAN_IP/24 dev vxlan0
49+
route add default gw $VXLAN_ROUTER_IP
50+
echo "nameserver $VXLAN_ROUTER_IP">/etc/resolv.conf.dhclient
51+
fi
52+
ping -c1 $VXLAN_ROUTER_IP
53+
54+
#Set DNS
55+
#route add $DNS_ORG gw $GW_ORG
56+
cp -av /etc/resolv.conf.dhclient* /etc_shared/resolv.conf
57+
58+
FIRST_BOOT_MARKER=/etc_shared/booted
59+
if [ ! -e "$FIRST_BOOT_MARKER" ] || [ -n "$FIRST_BOOT" ]; then
60+
touch $FIRST_BOOT_MARKER
61+
echo "First boot (init container): ending now."
62+
exit 0
63+
else
64+
echo "Not first boot: stay on monitoring connection to VPN"
65+
while true; do
66+
# Sleep while reacting to signals
67+
sleep 600 &
68+
wait $!
69+
#Ping router
70+
ping -c1 $VXLAN_ROUTER_IP
71+
done
72+
fi

bin/router.sh

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#!/bin/sh -ex
2+
3+
cat /config/settings.sh
4+
. /config/settings.sh
5+
6+
#Create tunnel NIC
7+
ip link add vxlan0 type vxlan id $VXLAN_ID dev eth0 dstport 0 || true
8+
ip addr add ${VXLAN_ROUTER_IP}/24 dev vxlan0 || true
9+
ip link set up dev vxlan0
10+
11+
#Enable outbound NAT
12+
iptables -t nat -A POSTROUTING -j MASQUERADE
13+
14+
#Open inbond NAT ports
15+
while read aLine; do
16+
case "$aLine" in
17+
\#*) continue;;
18+
*) echo Processing: $aLine ;;
19+
esac
20+
#Skip lines with comments
21+
[[ '$aLine' == \#* ]] && continue
22+
NAME=$(echo $aLine|cut -d' ' -f1)
23+
IP=$(echo $aLine|cut -d' ' -f2)
24+
PORTS=$(echo $aLine|cut -d' ' -f3)
25+
#Add NAT entries
26+
for portStr in $(echo $PORTS|sed 's/,/ /g'); do
27+
PORT_TYPE=$(echo $portStr|cut -d':' -f1)
28+
PORT_NUMBER=$(echo $portStr|cut -d':' -f2)
29+
echo "IP: $IP , NAME: $NAME , PORT: $PORT_NUMBER , TYPE: $PORT_TYPE"
30+
iptables -t nat -A PREROUTING -p ${PORT_TYPE} -i tun0 --dport ${PORT_NUMBER} -j DNAT --to-destination ${VXLAN_IP_NETWORK}.${IP}:${PORT_NUMBER}
31+
iptables -A FORWARD -p ${PORT_TYPE} -d ${VXLAN_IP_NETWORK}.${IP} --dport ${PORT_NUMBER} -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
32+
done
33+
done </config/nat.conf
34+
35+
#Firewall incomming traffic from VPN
36+
echo Accept traffic alredy ESTABLISHED
37+
iptables -A FORWARD -i tun0 -m state --state ESTABLISHED,RELATED -j ACCEPT
38+
echo "Reject other traffic"
39+
iptables -A FORWARD -i tun0 -j REJECT
40+
#iptables -A INPUT -i tun0 -j REJECT
41+
42+
#Do not forward any traffic that does not leave through tun0
43+
# The openvpn will also add drop rules but this is to ensure we block even if VPN is not connecting
44+
iptables --policy FORWARD DROP
45+
iptables -I FORWARD -o tun0 -j ACCEPT
46+
47+
#Do not allow outbound traffic on eth0 beyond VPN and local traffic
48+
iptables --policy OUTPUT DROP
49+
iptables -A OUTPUT -p udp --dport 443 -j ACCEPT #VPN traffic over UDP
50+
iptables -A OUTPUT -p tcp --dport 443 -j ACCEPT #VPN traffic over TCP
51+
iptables -A OUTPUT -d 10.0.0.0/8 -j ACCEPT
52+
iptables -A OUTPUT -d 192.168.0.0/16 -j ACCEPT
53+
iptables -A OUTPUT -o tun0 -j ACCEPT
54+
iptables -A OUTPUT -o vxlan0 -j ACCEPT
55+
56+
#Routes for local networks
57+
GW_IP=$(/sbin/ip route | awk '/default/ { print $3 }')
58+
ip route add 10.0.0.0/8 via ${GW_IP}
59+
ip route add 192.168.0.0/16 via ${GW_IP}

bin/webhook

-1.85 MB
Binary file not shown.

config/dhclient.conf

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
backoff-cutoff 2;
2+
initial-interval 1;
3+
link-timeout 10;
4+
reboot 0;
5+
retry 10;
6+
select-timeout 0;
7+
timeout 30;
8+
9+
interface "vxlan0"
10+
{
11+
apend domain-name-servers 10.96.0.1;
12+
request subnet-mask,
13+
broadcast-address,
14+
routers,
15+
domain-name-servers;
16+
require routers,
17+
subnet-mask,
18+
domain-name-servers;
19+
}

config/nat.conf

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#name IP ports(coma separated)
2+
#transmission 10 tcp:18289,udp:18289

config/settings.sh

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/bin/sh
2+
VXLAN_IP_NETWORK="172.16.0"
3+
DNS_ORG="10.96.0.10"
4+
VXLAN_ROUTER_IP="${VXLAN_IP_NETWORK}.1"
5+
VXLAN_ID="42"
6+
OPENVPN_ROUTER_NAME="openvpn.kube-system.svc.cluster.local"

go.mod

-3
This file was deleted.

main.go

-7
This file was deleted.

main_test.go

-10
This file was deleted.

0 commit comments

Comments
 (0)