17. September 2021 4 min read
Kubernetes and Traefik v2 forward traffic to external IP
In my internal network I have couple of devices that I would love to expose to internet. However as we all know those devices are not the most secure, so providing added layer of security via Kubernetes and Traefik v2 seemed like easiest and best idea. Traefik already obtains Letsencrypt certificates for the domains and is also able to forward traffic to addresses external to your Kubernetes cluster.
Prepare Traefik and Letsencrypt
Although I have written about this section in past posts, for completeness here is the creation of the certificate which uses letsencrypt-prod as issuer (read the official certmanager docs how to setup Issuer).
apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
name: example-cert
namespace: example
spec:
commonName: example.the-mori.com
secretName: example-the-mori-cert
dnsNames:
- example.the-mori.com
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
After you applied above certificate it is time to create a service, which is going to connect your outside-cluster server to the Kubernetes and Traefik. Important change is to adjust the ExternalName IP and ports.targetPort value to match the IP and port on which your outside-cluster server is on and listening. There are quite few ways to find the IP of the server in an internal network, but in most cases, it is in 192.168.X.X ranges (depending on your subnet mask).
kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: outside-server-example
name: outside-server-example
namespace: example
spec:
type: ExternalName
ports:
- name: outside-server-example
port: 80
targetPort: 80
externalName: 192.168.0.196
selector:
app.kubernetes.io/instance: traefik
app.kubernetes.io/name: traefik
Connect Traefik and Service with IngressRoute
Now everything is setup so that Traefik can connect the Service and external host, while also starting to obtain the certificate. This is done with IngressRoute object where match:Host is simply hostname/domain that you want Traefik to forward messages from and services is the name of service. tls.secretName is the connection to certificate, so that connection can be secured via https. Keep in mind that Host here, has to match proper fields in the Certificate object above.
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: outside-server-ingress
namespace: example
spec:
entryPoints:
- websecure
routes:
- match: Host(`example.the-mori.com`)
kind: Rule
services:
- name: outside-server-example
kind: Service
port: 80
tls:
secretName: example-the-mori-cert
It is this easy to use Traefik to forward traffic to a server external to your Kubernetes cluster. A fair warning is that this ideally should be within your local network as the main reason is to provide an additional layer of security and not expose vulnerable devices to the internet.
With Traefik 2.5.x the issue is that (via Helm Chart) you need to enable external services using this two arguments
additionalArguments:
- "--providers.kubernetesingress.allowexternalnameservices"
- "--providers.kubernetescrd.allowexternalnameservices"
These two arguments were not needed in previous versions of Traefik so make sure it is setup like this.