125 lines
4.0 KiB
Markdown
125 lines
4.0 KiB
Markdown
# Kilo as VPN Server to connect into the cluster
|
|
|
|
Use Case: Connect into the Kubernetes Cluster via WireGuard VPN, so that a WireGuard client has direct
|
|
access to Pods and Services.
|
|
|
|
## Prerequisites
|
|
|
|
- Ensure Wireguard is installed on the host system
|
|
- UDP port 51820 must be externally reachable to the cluster
|
|
|
|
## Deployment
|
|
|
|
- For this case, it is enough to deploy a single instance of Kilo into the cluster. Kilo should be
|
|
**pinned** to a single Node, because the WireGuard private key is host-specific.
|
|
- CNI has to be disabled, because you are keeping the existing CNI plugin.
|
|
- You can use in-cluster Kubernetes configuration, and do not need to mount the host Kubernetes config.
|
|
(The latter is only needed to extract in the CNI case to detect the outside-visible Hostname for
|
|
each node).
|
|
- We only tested this with Flannel or Flannel+Calico (=Canal) so far.
|
|
|
|
You can still access all Kubernetes Services and Pods, no matter where they run, in this configuration.
|
|
|
|
The full configuration can be found at [manifests/kilo-vpn-only-example.yaml](../manifests/kilo-vpn-only-example.yaml).
|
|
|
|
**Make sure to adjust the `nodeSelector` in the `DaemonSet`**.
|
|
|
|
## Registering a new VPN client
|
|
|
|
1. Create a new WireGuard keypair on the VPN Client. Remember the public key.
|
|
|
|
2. For the client, create a Kubernetes `peer` resource:
|
|
|
|
- pick a new, unique, IP address for the client from the `10.5.0.*` IP range.
|
|
Based on this IP, we can lateron decide what the client can access.
|
|
|
|
- add the public key from the VPN client (see step 1) to the `peer` resource.
|
|
|
|
Example:
|
|
|
|
```
|
|
apiVersion: kilo.squat.ai/v1alpha1
|
|
kind: Peer
|
|
metadata:
|
|
name: squat
|
|
spec:
|
|
allowedIPs:
|
|
# desired IP address of the client's interface.
|
|
- 10.5.0.1/32
|
|
# Public Key of the client
|
|
publicKey: A......................................=
|
|
persistentKeepalive: 10
|
|
```
|
|
|
|
3. Configure your local VPN client in the following way:
|
|
|
|
```ini
|
|
[Interface]
|
|
PrivateKey = (already filled)
|
|
# IP address of VPN client; from the "peer" kubernetes resource as configured above
|
|
Address = 10.5.0.1/32
|
|
|
|
[Peer]
|
|
# from within the "kilo" Pod, run "wg" - that outputs the persistent, public key for
|
|
# the server
|
|
PublicKey = B......................................=
|
|
|
|
# Add the Pod and Service networks, e.g. if 10.42.* is the Pod Network; and 10.43.*
|
|
# is the Service network:
|
|
AllowedIPs = 10.42.0.0/16, 10.43.0.0/16
|
|
|
|
# public IP address of the Kilo node + Wireguard/Kilo UDP Port
|
|
Endpoint = 138.201.76.122:51820
|
|
|
|
# the server is always reachable, so we do not need PersistentKeepalive in
|
|
# this direction.
|
|
PersistentKeepalive = 0
|
|
```
|
|
|
|
## Optional: Using Calico / Canal to restrict the NetworkPolicy in the Cluster
|
|
|
|
If you are running Calico + Flannel (=Canal), you can use `HostEndpoint` combined
|
|
with a `GlobalNetworkPolicy` to restrict what each VPN client can access in the cluster:
|
|
|
|
```yaml
|
|
---
|
|
apiVersion: crd.projectcalico.org/v1
|
|
kind: HostEndpoint
|
|
metadata:
|
|
name: wireguard-kilo
|
|
labels:
|
|
interface: wireguard-kilo
|
|
spec:
|
|
node: THE_KILO_NODE_HERE
|
|
expectedIPs:
|
|
# in the "kilo" container, we run "ip address show kilo0",
|
|
# and this is the IP of the "inner" side of the wireguard interface.
|
|
# thus, we need to match on this IP here.
|
|
- 10.4.0.1
|
|
|
|
---
|
|
apiVersion: crd.projectcalico.org/v1
|
|
kind: GlobalNetworkPolicy
|
|
metadata:
|
|
name: wireguard-kilo
|
|
spec:
|
|
selector: interface == 'wireguard-kilo'
|
|
# we want to apply the policy as it enters our cluster (exits the wireguard
|
|
# interface). On the application pods, we could not apply it anymore, because
|
|
# the IP address gets rewritten to the Flannel interface IP.
|
|
applyOnForward: true
|
|
types:
|
|
- Ingress
|
|
ingress:
|
|
- action: Allow
|
|
source:
|
|
nets:
|
|
- 10.5.0.1/32 # a certain VPN client ...
|
|
destination:
|
|
# ... can access a certain app
|
|
namespaceSelector: network-policy-namespace == "cattle-prometheus"
|
|
selector: app == "grafana"
|
|
|
|
# anything which is not whitelisted explicitly is forbidden
|
|
- action: Deny
|
|
``` |