Skip to content
Snippets Groups Projects
Dominik George's avatar
Nik | Klampfradler authored
82a35ed9
History

🖇️ k8s-linkup – Linkup Kubernetes pods to a remote site

k8s-linkup is a utility for linking up Kubernetes pods to remote sites by means of a Virtual Private Network connection (VPN).

It is intended to be used through its Helm chart, mostly as a subchart of an application. For example, if an external database is intended to be used for some applicaiton, k8s-linkup can be used to make it available to the pods running in Kubernetes.

Screenshot

This utility is developed alongside the AlekSIS® project, to be able to link up SaaS-hosted instances to databases hosted elsewhere.

💡 General idea

The general idea of how the container works is:

  • Choose a backend connection type (e.g. OpenVPN)
  • Create a configuration file for the connection (e.g. openvpn.conf)
    • Deploy this configuration file in a ConfigMap, or mount as volume manually
  • Deploy all secrets needed in a Secret, or mount as volume manually
  • Configure the backend connection in Helm values, or manually through the environment
  • Configure a set of port mappings in Helm values, or mount a HAProxy configuration manually
  • The container will start the backend connection, plus HAProxy to make configured services available to the outside

⚙️ How to deploy (using Helm)

Making the chart available

To make the chart available, add the chart repository and update the Helm cache:

helm repo add k8s-linkup https://edugit.org/api/v4/projects/882/packages/helm/stable
helm update

If using k8s-linkup as a subchart, add the following to Chart.yaml:

- name: k8s-linkup
  version: "^2.0.0"
  repository: https://edugit.org/api/v4/projects/882/packages/helm/stable
  condition: k8s-linkup.enabled

Configuring linkups

Linkups, that is, one or several containers connecting to a backend, can be configured by filling the linkups array in your Helm values. When deploying as a stand-alone chart, the array is on the top level; when using k8s-linkup as a subchart, it is below the k8s-linkup namespace.

An example linkup might look like this:

linkups:
  - name: linkup1
    connection: openvpn
    serviceType: ClusterIP
    replicaCount: 1
    configMap:
      name: openvpn-config
      file: openvpn.conf
    secret:
      name: openvpn-secret
    healthCheckPort: 9000
    portMappings: []

This example will spawn a container connecting to a remote OpenVPN server, using openvpn.conf from the ConfigMap names openvpn-config, and secrets from openvpn-secret.

The Secret will be mounted under /etc/k8s-linkup/openvpn/secret/, while the ConfigMap will be mounted at /etc/k8s-linkup/openvpn. That means that all files in the Secret can be referenced relative to the configuration file.

Multiple linkups can be configured. Each will spawn a separate pod, and make a separate Service available.

Mapping remote ports

To map ports to services running on the remote side, the portMappings array of each linkup is filled:

    portMappings:
      - name: ldap
        local:
          port: 389
        remote:
          host: 172.17.0.5
          port: 389
        maxconn: 20
        type: TCP
        monitored: true

This example will add a matching frontend and backend in HAProxy mapping the container port 389 to the same port on a remote host 172.17.0.5. It will allow 20 connections at most.

The monitored flag defines whether this service should be monitored, meaning that it will be added as a rule to HAProxy's health check. The health check is queried in the pod's liveness probe, so the container will be restarted if a port mapping which is monitored becomes and remains unavailable. This behaviour is the default.

Using proxied services

Proxied services are made available as ports ona Kubernetes Service, named with the Helm release name and linkup name. For example, for a Helm release named foobar, and a linkup named linkup1, the Service will be called foobar-linkup1.

Mind that, when using the chart as a subchart, the subchart name is appended to the release name, so the full name becomes foobar-k8s-linkup-linkup1.

You can use this service name as a hostname in your other pods.

🤗 Supported backend connections

The following connection types are supported (see below sections for hints on k8s-linkup specific configuration):

OpenVPN

OpenVPN is an enterprise-grade and well-known VPN solution, based around a client-server architecture.

In k8s-linkup, the configuration is expected in a single file in a ConfigMap. The configuration file should reference all necessary certificates and keys, with private keys and shared keys residing in the Secret (they can be referenced with a relative path, like secret/client.key).

WireGuard

WireGuard is a, relatively new, offering much simpler configuration than OpenVPN and a mesh-like architecture. It is included in the Linux kernel.

WireGuard expects the configuration file name to match the interface name. In k8s-linkup, the interface name is thus derived from the config file name used in the ConfigMap. The private key needs to reside in a file named <interface>.key in the Secret, i.e. with the same base name as the config file. It is recommended to use wg0.conf and wg0.key.

The relevant excerpt for your values, with the Secret containing a file named wg0.key, might look like:

linkups:
  - name: linkup1
    connection: wireguard
    configMap:
      name: wg-config
      file: wg0.conf
    secret:
      name: wg-secret

😿 Limitations

k8s-linkup has a few (partially deliberate) limitations:

  • Each container can only handle one backend connection. This is deliberate – to connect to multiple VPNs, spawn multiple linkup containers.
  • Only one Service is created per linkup pod, which exposes all mapped ports. This will probably be improved in a future version.
  • No full container networking – this is deliberate; the concept of this utility is to expose selected services only by mapping them into the cluster. Alternatives with full container networking exist.

⚖️ Copyright and licence

   Copyright 2021 Dominik George <dominik.geoerge@teckids.org>

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.