linuxserver / docker-wireguard

GNU General Public License v3.0
2.95k stars 367 forks source link

Routing in container seems screwed up #78

Closed evanrich closed 3 years ago

evanrich commented 3 years ago

I'm running wireguard inside kubernetes, which shouldn't be a problem, since other containers are working fine. I have a feeling perhaps that IPTABLES rules might be screwed up, because when a client connects to the pod, it can't access the internet/internal network, but the pod can.

Here is tcpdump traffic from the pod (container) out to ping google.com:

root@wireguard-79b98c69cd-ppkzj:/# ping google.com
PING google.com (142.250.68.78) 56(84) bytes of data.
64 bytes from lax31s11-in-f14.1e100.net (142.250.68.78): icmp_seq=1 ttl=113 time=14.2 ms

Here is a tcpdump of the virtual adapter docker creates for the container, showing bidirectional traffic for the ping above:

 tcpdump -i califda3b2b6779
2:09:30.278759 IP 10.1.211.156.47912 > 10.96.0.10.domain: 6458+ A? google.com.default.svc.cluster.local. (54)
22:09:30.278870 IP 10.1.211.156.47912 > 10.96.0.10.domain: 35659+ AAAA? google.com.default.svc.cluster.local. (54)
22:09:30.279136 IP 10.96.0.10.domain > 10.1.211.156.47912: 6458 NXDomain*- 0/1/0 (147)
22:09:30.279194 IP 10.96.0.10.domain > 10.1.211.156.47912: 35659 NXDomain*- 0/1/0 (147)
22:09:30.279333 IP 10.1.211.156.36584 > 10.96.0.10.domain: 24749+ A? google.com.svc.cluster.local. (46)
22:09:30.279399 IP 10.1.211.156.36584 > 10.96.0.10.domain: 48823+ AAAA? google.com.svc.cluster.local. (46)
22:09:30.279608 IP 10.96.0.10.domain > 10.1.211.156.36584: 48823 NXDomain*- 0/1/0 (139)
22:09:30.279664 IP 10.96.0.10.domain > 10.1.211.156.36584: 24749 NXDomain*- 0/1/0 (139)
22:09:30.279739 IP 10.1.211.156.57965 > 10.96.0.10.domain: 59012+ A? google.com.cluster.local. (42)
22:09:30.279803 IP 10.1.211.156.57965 > 10.96.0.10.domain: 49550+ AAAA? google.com.cluster.local. (42)
22:09:30.280048 IP 10.96.0.10.domain > 10.1.211.156.57965: 59012 NXDomain*- 0/1/0 (135)
22:09:30.280142 IP 10.96.0.10.domain > 10.1.211.156.57965: 49550 NXDomain*- 0/1/0 (135)
22:09:30.280228 IP 10.1.211.156.55184 > 10.96.0.10.domain: 3671+ A? google.com. (28)
22:09:30.280336 IP 10.1.211.156.55184 > 10.96.0.10.domain: 49757+ AAAA? google.com. (28)
22:09:30.287537 IP 10.96.0.10.domain > 10.1.211.156.55184: 3671 1/0/0 A 142.250.68.78 (54)
22:09:30.287627 IP 10.96.0.10.domain > 10.1.211.156.55184: 49757 1/0/0 AAAA 2607:f8b0:4005:807::200e (66)
22:09:30.288048 IP 10.1.211.156 > lax31s11-in-f14.1e100.net: ICMP echo request, id 368, seq 1, length 64
22:09:30.302242 IP lax31s11-in-f14.1e100.net > 10.1.211.156: ICMP echo reply, id 368, seq 1, length 64
22:09:30.302461 IP 10.1.211.156.41163 > 10.96.0.10.domain: 36929+ PTR? 78.68.250.142.in-addr.arpa. (44)
22:09:30.309751 IP 10.96.0.10.domain > 10.1.211.156.41163: 36929 1/0/0 PTR lax31s11-in-f14.1e100.net. (109)

WG showing client connected:

root@wireguard-79b98c69cd-ppkzj:/# wg show
interface: wg0
  public key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxgY=
  private key: (hidden)
  listening port: 51820

peer:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxZVE=
  endpoint: 192.168.4.2:56563
  allowed ips: 10.13.13.2/32
  latest handshake: 6 seconds ago
  transfer: 5.50 KiB received, 92 B sent

Here is a tcpdump of the wg0 interface in the container, showing client connected, but only going in 1 direction (10.13.13.2 is the client wireguard ip):

root@wireguard-79b98c69cd-ppkzj:/# tcpdump -i wg0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on wg0, link-type RAW (Raw IP), capture size 262144 bytes
22:12:12.763174 IP 10.13.13.2.3293 > pihole-tcp.default.svc.cluster.local.53: 2911+ AAAA? www.googleapis.com. (36)
22:12:12.765305 IP 10.13.13.2.11266 > pihole-tcp.default.svc.cluster.local.53: 44210+ A? cspxqfawsimkgf. (32)
22:12:12.765325 IP 10.13.13.2.33324 > pihole-tcp.default.svc.cluster.local.53: 27700+ A? oldjdtntonma. (30)
22:12:12.765997 IP 10.13.13.2.65298 > pihole-tcp.default.svc.cluster.local.53: 25596+ A? azdjlxabzrayia. (32)
22:12:12.767725 IP 10.13.13.2.31076 > pihole-tcp.default.svc.cluster.local.53: 45820+ AAAA? android.googleapis.com. (40)
22:12:12.767745 IP 10.13.13.2.5717 > pihole-tcp.default.svc.cluster.local.53: 6698+ A? android.googleapis.com. (40)
22:12:12.768601 IP 10.13.13.2.9234 > pihole-tcp.default.svc.cluster.local.53: 13490+ A? play.googleapis.com. (37)
22:12:12.780782 IP 10.13.13.2.11266 > pihole-tcp.default.svc.cluster.local.53: 44210+ A? cspxqfawsimkgf. (32)
22:12:12.780838 IP 10.13.13.2.33324 > pihole-tcp.default.svc.cluster.local.53: 27700+ A? oldjdtntonma. (30)
22:12:12.780838 IP 10.13.13.2.65298 > pihole-tcp.default.svc.cluster.local.53: 25596+ A? azdjlxabzrayia. (32)
22:12:12.780838 IP 10.13.13.2.49742 > pihole-tcp.default.svc.cluster.local.53: 25398+ A? clients4.google.com. (37)
22:12:12.780838 IP 10.13.13.2.53269 > pihole-tcp.default.svc.cluster.local.53: 38009+ A? clients4.google.com. (37)
22:12:12.780859 IP 10.13.13.2.64320 > pihole-tcp.default.svc.cluster.local.53: 51078+ A? clients4.google.com. (37)
22:12:12.782281 IP 10.13.13.2.49742 > pihole-tcp.default.svc.cluster.local.53: 25398+ A? clients4.google.com. (37)
22:12:12.782282 IP 10.13.13.2.40083 > pihole-tcp.default.svc.cluster.local.53: 51550+ A? android.googleapis.com. (40)
22:12:12.782282 IP 10.13.13.2.4813 > pihole-tcp.default.svc.cluster.local.53: 47001+ AAAA? android.googleapis.com. (40)

and finally, the kubernetes host showing no traffic coming out when the client tries to connect (homelab a is k8s host, 10.1.211.156 is pod ip):

22:12:39.682287 IP homelab-a.56563 > 10.1.211.156.51820: UDP, length 128
22:12:39.693380 IP homelab-a.56563 > 10.1.211.156.51820: UDP, length 96
22:12:39.722214 IP homelab-a.56563 > 10.1.211.156.51820: UDP, length 96
22:12:39.728311 IP homelab-a.56563 > 10.1.211.156.51820: UDP, length 96
22:12:40.605581 IP homelab-a.56563 > 10.1.211.156.51820: UDP, length 96
22:12:41.437604 IP homelab-a.56563 > 10.1.211.156.51820: UDP, length 112
22:12:41.835339 IP homelab-a.56563 > 10.1.211.156.51820: UDP, length 96
22:12:42.298781 IP homelab-a.56563 > 10.1.211.156.51820: UDP, length 128
22:12:42.356183 IP homelab-a.56563 > 10.1.211.156.51820: UDP, length 96
22:12:42.448387 IP homelab-a.56563 > 10.1.211.156.51820: UDP, length 96
22:12:46.379399 IP homelab-a.56563 > 10.1.211.156.51820: UDP, length 112
22:12:46.403085 IP homelab-a.56563 > 10.1.211.156.51820: UDP, length 96
22:12:46.408106 IP homelab-a.56563 > 10.1.211.156.51820: UDP, length 96
22:12:46.439397 IP homelab-a.56563 > 10.1.211.156.51820: UDP, length 128
22:12:46.445315 IP homelab-a.56563 > 10.1.211.156.51820: UDP, length 96
22:12:46.456092 IP homelab-a.56563 > 10.1.211.156.51820: UDP, length 96
22:12:46.456106 IP homelab-a.56563 > 10.1.211.156.51820: UDP, length 96
22:12:46.459372 IP homelab-a.56563 > 10.1.211.156.51820: UDP, length 96
22:12:46.483333 IP homelab-a.56563 > 10.1.211.156.51820: UDP, length 80

I'm on the latest image you have (using flux to auto-deploy). Here is what I can surmise:

Mobile device can connect through router to wireguard pod without issue, meaning client can talk to wg0 in container Wireguard pod is able to talk out to world on eth0 It appears wg0 cannot pass traffic to eth0 inside container

I have looked at my firewall, and do not see traffic coming out to network from the wireguard session, nothing in/out of my network is reachable by the client either, and all tcpdump traffic shows only single direction from client into wg0 interface.

If it matters, here is deployment file in k8s:

---
apiVersion: v1
kind: Service
metadata:
  name: wireguard
  labels:
    app: wireguard
spec:
  selector:
    app: wireguard
  type: LoadBalancer
  loadBalancerIP: 192.168.50.26
  ports:
  - name: wireguard
    port: 51820
    protocol: UDP
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: wireguard
  annotations:
    fluxcd.io/automated: 'true'
    fluxcd.io/tag.wireguard: 'regex:^v1.0.+-ls[0-9]+$'
spec:
  replicas: 1
  selector:
    matchLabels:
      app: wireguard
  template:
    metadata:
      labels:
        app: wireguard
    spec:
      nodeSelector:
        kubernetes.io/hostname: "homelab-a"
      volumes:
      - name: dockerdata
        hostPath:
         # directory location on host
          path: /dockerdata
          type: Directory
      - name: host
        hostPath:
          path: /
          type: Directory
      containers:
      - name: wireguard
        image: linuxserver/wireguard:v1.0.20200827-ls1
        #imagePullPolicy: Always
        securityContext:
          capabilities:
            add:
            - NET_ADMIN
            - SYS_MODULE
        volumeMounts:
        - name: dockerdata
          subPath: wireguard
          mountPath: /config
        - name: host
          subPath: lib/modules
          mountPath: /lib/modules
        env:
        - name: PUID
          value: '1001'
        - name: PGID
          value: '1001'
        - name: TZ
          value: 'America/Los_Angeles'
        - name: SERVERURL
          value: 'wg.server.zzz'
        - name: PEERS
          value: '3'
        - name: PEERDNS
          value: '192.168.50.29'
        ports:
        - name: wireguard
          containerPort: 51820
          protocol: UDP

docker logs:

[s6-init] making user provided files available at /var/run/s6/etc...exited 0.
[s6-init] ensuring user provided files have correct perms...exited 0.
[fix-attrs.d] applying ownership & permissions fixes...
[fix-attrs.d] done.
[cont-init.d] executing container initialization scripts...
[cont-init.d] 01-envfile: executing...
[cont-init.d] 01-envfile: exited 0.
[cont-init.d] 10-adduser: executing...

-------------------------------------
          _         ()
         | |  ___   _    __
         | | / __| | |  /  \
         | | \__ \ | | | () |
         |_| |___/ |_|  \__/

Brought to you by linuxserver.io
-------------------------------------

To support the app dev(s) visit:
WireGuard: https://www.wireguard.com/donations/

To support LSIO projects visit:
https://www.linuxserver.io/donate/
-------------------------------------
GID/UID
-------------------------------------

User uid:    1001
User gid:    1001
-------------------------------------

[cont-init.d] 10-adduser: exited 0.
[cont-init.d] 30-config: executing...
Uname info: Linux wireguard-79b98c69cd-ppkzj 5.4.0-54-generic #60-Ubuntu SMP Fri Nov 6 10:37:59 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
**** It seems the wireguard module is already active. Skipping kernel header install and module compilation. ****
**** Server mode is selected ****
**** External server address is set to wg.server.zzz ****
**** External server port is set to 51820. Make sure that port is properly forwarded to port 51820 inside this container ****
**** Internal subnet is set to 10.13.13.0 ****
**** AllowedIPs for peers 0.0.0.0/0, ::/0 ****
**** Peer DNS servers will be set to 192.168.50.29 ****
**** Server mode is selected ****
**** No changes to parameters. Existing configs are used. ****
[cont-init.d] 30-config: exited 0.
[cont-init.d] 99-custom-scripts: executing...
[custom-init] no custom files found exiting...
[cont-init.d] 99-custom-scripts: exited 0.
[cont-init.d] done.
[services.d] starting services
[services.d] done.
[#] ip link add wg0 type wireguard
.:53
CoreDNS-1.8.0
linux/amd64, go1.15.3, 054c9ae
[#] wg setconf wg0 /dev/fd/63
[#] ip -4 address add 10.13.13.1 dev wg0
[#] ip link set mtu 1420 up dev wg0
[#] ip -4 route add 10.13.13.4/32 dev wg0
[#] ip -4 route add 10.13.13.3/32 dev wg0
[#] ip -4 route add 10.13.13.2/32 dev wg0
[#] iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

FWIW, I have a openvpn container that works, and I have also installed wireguard in a freenas Jail as a backup, so wireguard works in my network, and openvpn works in k8s, but wireguard does NOT seem to work in k8s, while other containers work just fine. I'm not an IP Tables expert, so can't debug that.

Thanks!

github-actions[bot] commented 3 years ago

Thanks for opening your first issue here! Be sure to follow the issue template!

evanrich commented 3 years ago

fwiw, adding "prividliged: true" to the container, and then adding "sysctl net.ipv4.ip_forward=1" in the container seems to fix this, can this be added to the image?

Tokugero commented 3 years ago

Hey there, sorry for missing this issue earlier.

I can verify that k8s does seem to have this behavior and your proposed solutions do fix it, specifically because privileged lets you set the sysctl in the container; although testing this on just a vanilla docker instance with no orchestration the value is set to 1 as expected by default.

We'll go back with the team and see if there's a better way to explicitly set the sysctl so you don't have to do either of these things, but since LSIO only officially supports vanilla docker today, there's no turnaround time or guarantee this will get fixed.

For k8s you'll have 2 options, then:

You can add unsafe sysctls to your cluster so you can set net.ipv4.ip_forward=1 in the pod spec You can keep privileged mode and add sysctl net.ipv4.ip_forward=1 to your /config/wg0.conf postUp step (which is what I'm now using thanks to your feedback :) )

Whatever the results are, thank you for debugging this issue and coming back with the solution; I'm sure this time capsule will be very valuable to folks!

jvanbruegge commented 3 years ago

Thanks, this helped a lot. I also deployed this now in kubernetes, but it also works without priviledged: Add:

allowedUnsafeSysctls:
  - 'net.ipv4.ip_forward'

to /var/lib/kubelet/config.yaml

Then you can modify your manifest:

---
apiVersion: v1
kind: Service
metadata:
  name: wireguard
  labels:
    app: wireguard
spec:
  selector:
    app: wireguard
  type: LoadBalancer
  loadBalancerIP: 192.168.50.26
  ports:
  - name: wireguard
    port: 51820
    protocol: UDP
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: wireguard
  annotations:
    fluxcd.io/automated: 'true'
    fluxcd.io/tag.wireguard: 'regex:^v1.0.+-ls[0-9]+$'
spec:
  replicas: 1
  selector:
    matchLabels:
      app: wireguard
  template:
    metadata:
      labels:
        app: wireguard
    spec:
      nodeSelector:
        kubernetes.io/hostname: "homelab-a"
+     securityContext:
+       sysctls:
+         - name: net.ipv4.ip_forward
+           value: '1'
      volumes:
      - name: dockerdata
        hostPath:
         # directory location on host
          path: /dockerdata
          type: Directory
      - name: host
        hostPath:
          path: /
          type: Directory
      containers:
      - name: wireguard
        image: linuxserver/wireguard:v1.0.20200827-ls1
        #imagePullPolicy: Always
        securityContext:
          capabilities:
            add:
            - NET_ADMIN
            - SYS_MODULE
        volumeMounts:
        - name: dockerdata
          subPath: wireguard
          mountPath: /config
        - name: host
          subPath: lib/modules
          mountPath: /lib/modules
        env:
        - name: PUID
          value: '1001'
        - name: PGID
          value: '1001'
        - name: TZ
          value: 'America/Los_Angeles'
        - name: SERVERURL
          value: 'wg.server.zzz'
        - name: PEERS
          value: '3'
        - name: PEERDNS
          value: '192.168.50.29'
        ports:
        - name: wireguard
          containerPort: 51820
          protocol: UDP

With these changes, wireguard works like a charm in k8s.

Just-Insane commented 3 years ago

Happy to have found this issue as I'm having the same problem.

I tried adding

allowedUnsafeSysctls:
  - 'net.ipv4.ip_forward'

to the path specified and rebooting the node, however when deploying I get a sysctl forbidden error message.

I've also tried with a privileged container and running sysctl net.ipv4.ip_forward=1, however, this also does not seem to be working.

I am using a CentOS 8 based node and installed the wireguard components as described in the wireguard install docs using the epel release method, though since the server is starting I suspect that is not the issue.

Tokugero commented 3 years ago

https://kubernetes.io/docs/tasks/administer-cluster/sysctl-cluster/#enabling-unsafe-sysctls

jvanbruegge posted exactly what to add to the kubelet configs to enable these sysctls, the link here is the official documentation on that step. We do not take any responsibility for any changes you make as we dont' technically support Kubernetes.

"Does not seem to be working" isn't very clear though, can you elaborate?

Just-Insane commented 3 years ago

Perhaps the problem is that I can't run kubectl on my nodes because they are managed by Rancher/RKE.

I tried creating the config file in the default path of kubectl, but that did not work either. I doubt this is a problem with the project, though having the ability to edit the default config to add the required section to the wg0.conf file would be nice.

Tokugero commented 3 years ago

Rancher uses a kube-api like any other and kubectl just calls that API, you can try the steps here to have access back https://rancher.com/docs/rancher/v2.x/en/cluster-admin/cluster-access/kubectl/ ; that being said I'm pretty sure the rancher UI does a decent job exposing the necessary bits to do the same but I'm not as familiar.

I'm closing this issue as we don't support k8s and at least two suitable answers to the original issue now exist.

Modifying the kubelet https://github.com/linuxserver/docker-wireguard/issues/78#issuecomment-751286862 And adding priviliged to the pod https://github.com/linuxserver/docker-wireguard/issues/78#issuecomment-739151416

If any historians reach this place and are looking for more Kubernetes conversations for our containers, at least as of the date of this writing, please join our Discord where we have several members who are just as masochistic as we are :) https://discord.gg/YWrKVTn