diff options
-rw-r--r-- | content/blog/kubernetes/wireguard-endpoint-on-kubernetes-part-1.md | 53 | ||||
-rw-r--r-- | static/static/wireguard-endpoint-on-kubernetes.drawio.svg | 4 |
2 files changed, 57 insertions, 0 deletions
diff --git a/content/blog/kubernetes/wireguard-endpoint-on-kubernetes-part-1.md b/content/blog/kubernetes/wireguard-endpoint-on-kubernetes-part-1.md new file mode 100644 index 0000000..8b177a7 --- /dev/null +++ b/content/blog/kubernetes/wireguard-endpoint-on-kubernetes-part-1.md @@ -0,0 +1,53 @@ +--- +title: Wireguard endpoint on kubernetes part 1 +description: How to expose kubernetes services over wireguard +date: 2023-04-13 +tags: +- kubernetes +- wireguard +--- + +## Introduction + +This article explains how I expose kubernetes services over wireguard. There are several way to achieve this, I choose to run a wireguard pod with a nginx proxy. + +There are multiple reasons in favor of this design, let's break these down. + +## Routing the return traffic + +When connecting to a service on your kubernetes cluster through wireguard, the return traffic needs to come back through your vpn. There are multiple ways to achieve this: +- have wireguard run on a fixed host and deploy routes to your wireguard clients' subnet via this host +- nat your traffic +- proxy your traffic + +I do not want to tie my vpn to a single host so this rules out solution 1. If this was a big enterprise setup, this could work with a dedicated compute for the vpn (or a pair for redundancy) and it would be a great solution! But it would not be tied to kubernetes which is the point of this article. + +Nat or proxy are both good because as far as the pods I connect to are concerned the traffic will originate from another pod on the cluster. + +## Overlapping networks for pods and services + +Often you inherit your infrastructure and do not have the luxury of building or reinstalling everything from scratch. Sometimes you just did not factor it, or you just applied a default configuration. Sometimes it is just not practical to avoid network overlaps between multiple providers. + +There are too many reasons (good or bad) for this to happen, I just take it into account when working on linking networks together with a vpn. Nat is one of the possible solutions, a proxy is another. + +## DNS resolution for services on kubernetes + +DNS is massively used for the discovery of everything running on kubernetes and is unavoidable. This makes it hard to run a nat setup, hence the proxy solution I chose. + +The proxy can perform a DNS lookup each time you connect to a service (or with a very short caching window) and send your traffic to the correct pods even when they move around or restart, changing their IP addresses. + +It would be possible to perform the DNS resolution from a resolver running on your vpn client (with unbound for example), but it would only work if you do not have overlapping networks. + +## Bonus feature: access managed cloud services + +A bonus feature that you might enjoy thanks to wireguard with a proxy is the ability to connect to cloud services outside your cluster, for example managed databases. My use case for this is the provisioning of managed databases using terraform. With this facility you can deploy and manage your terraform resources in the same state quite elegantly. + +## Conclusion + +Here is a simple schematic of what it looks like: + +![Architecture](/static/wireguard-endpoint-on-kubernetes.drawio.svg) + +Wireguard's pod will just be running nginx as a reverse proxy. Thanks to wireguard itself being integrated with the linux kernel and able to be namespaced, its setup can be isolated in a privileged init container. + +There is a network policy aspect to consider as well as nginx and wireguard's configurations to write, all this will be done in the next article.
\ No newline at end of file diff --git a/static/static/wireguard-endpoint-on-kubernetes.drawio.svg b/static/static/wireguard-endpoint-on-kubernetes.drawio.svg new file mode 100644 index 0000000..917af88 --- /dev/null +++ b/static/static/wireguard-endpoint-on-kubernetes.drawio.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Do not edit this file with editors other than diagrams.net --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="341px" height="142px" viewBox="-0.5 -0.5 341 142" content="<mxfile host="app.diagrams.net" modified="2023-04-13T21:41:53.979Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36" etag="KFpNmgPEaGdaKwkcgjHh" version="21.1.4" type="device"> <diagram id="-8aDvL2Yv33GjBWb1LGq" name="Page-1"> <mxGraphModel dx="715" dy="453" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" background="#181818" math="0" shadow="0"> <root> <mxCell id="0" /> <mxCell id="1" parent="0" /> <mxCell id="CjkN9uOaFDgBuOWTdM4j-2" value="kubernetes cluster" style="rounded=0;whiteSpace=wrap;html=1;verticalAlign=bottom;labelPosition=center;verticalLabelPosition=middle;align=right;fillColor=none;strokeColor=#b9b9b9;fontColor=#B9B9B9;" parent="1" vertex="1"> <mxGeometry x="160" y="240" width="220" height="140" as="geometry" /> </mxCell> <mxCell id="jydjK_vjZ9dkjedRBGX7-3" value="namespace" style="rounded=0;whiteSpace=wrap;html=1;verticalAlign=bottom;labelPosition=center;verticalLabelPosition=middle;align=right;fillColor=none;strokeColor=#4F9CFE;fontColor=#4F9CFE;" vertex="1" parent="1"> <mxGeometry x="170" y="250" width="190" height="50" as="geometry" /> </mxCell> <mxCell id="jydjK_vjZ9dkjedRBGX7-2" value="service you want to reach" style="rounded=0;whiteSpace=wrap;html=1;fillColor=none;strokeColor=#70B433;fontColor=#70B433;labelBackgroundColor=#181818;" vertex="1" parent="1"> <mxGeometry x="180" y="260" width="170" height="20" as="geometry" /> </mxCell> <mxCell id="jydjK_vjZ9dkjedRBGX7-4" value="wireguard&#39;s namespace" style="rounded=0;whiteSpace=wrap;html=1;verticalAlign=bottom;labelPosition=center;verticalLabelPosition=middle;align=right;fillColor=none;strokeColor=#4F9CFE;fontColor=#4F9CFE;" vertex="1" parent="1"> <mxGeometry x="170" y="310" width="190" height="50" as="geometry" /> </mxCell> <mxCell id="jydjK_vjZ9dkjedRBGX7-5" value="wireguard &amp;amp; nginx" style="rounded=0;whiteSpace=wrap;html=1;fillColor=none;strokeColor=#70B433;fontColor=#70B433;labelBackgroundColor=#181818;align=center;verticalAlign=middle;" vertex="1" parent="1"> <mxGeometry x="180" y="320" width="170" height="20" as="geometry" /> </mxCell> <mxCell id="jydjK_vjZ9dkjedRBGX7-12" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;strokeColor=#E67F43;strokeWidth=2;" edge="1" parent="1" source="jydjK_vjZ9dkjedRBGX7-5" target="jydjK_vjZ9dkjedRBGX7-2"> <mxGeometry relative="1" as="geometry"> <mxPoint x="320" y="375" as="sourcePoint" /> </mxGeometry> </mxCell> <mxCell id="jydjK_vjZ9dkjedRBGX7-10" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fillColor=#f8cecc;strokeColor=#E67F43;strokeWidth=2;" edge="1" parent="1" source="jydjK_vjZ9dkjedRBGX7-9" target="jydjK_vjZ9dkjedRBGX7-5"> <mxGeometry relative="1" as="geometry"> <mxPoint x="190" y="340" as="targetPoint" /> </mxGeometry> </mxCell> <mxCell id="jydjK_vjZ9dkjedRBGX7-9" value="Actor" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;strokeColor=#B9B9B9;fillColor=#181818;" vertex="1" parent="1"> <mxGeometry x="40" y="300" width="30" height="60" as="geometry" /> </mxCell> </root> </mxGraphModel> </diagram> </mxfile> " style="background-color: rgb(24, 24, 24);"><defs/><g><rect x="120" y="0" width="220" height="140" fill="none" stroke="#b9b9b9" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-end; justify-content: unsafe flex-end; width: 218px; height: 1px; padding-top: 137px; margin-left: 120px;"><div data-drawio-colors="color: #B9B9B9; " style="box-sizing: border-box; font-size: 0px; text-align: right;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(185, 185, 185); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">kubernetes cluster</div></div></div></foreignObject><text x="338" y="137" fill="#B9B9B9" font-family="Helvetica" font-size="12px" text-anchor="end">kubernetes cluster</text></switch></g><rect x="130" y="10" width="190" height="50" fill="none" stroke="#4f9cfe" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-end; justify-content: unsafe flex-end; width: 188px; height: 1px; padding-top: 57px; margin-left: 130px;"><div data-drawio-colors="color: #4F9CFE; " style="box-sizing: border-box; font-size: 0px; text-align: right;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(79, 156, 254); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">namespace</div></div></div></foreignObject><text x="318" y="57" fill="#4F9CFE" font-family="Helvetica" font-size="12px" text-anchor="end">namespace</text></switch></g><rect x="140" y="20" width="170" height="20" fill="none" stroke="#70b433" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 168px; height: 1px; padding-top: 30px; margin-left: 141px;"><div data-drawio-colors="color: #70B433; background-color: #181818; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(112, 180, 51); line-height: 1.2; pointer-events: all; background-color: rgb(24, 24, 24); white-space: normal; overflow-wrap: normal;">service you want to reach</div></div></div></foreignObject><text x="225" y="34" fill="#70B433" font-family="Helvetica" font-size="12px" text-anchor="middle">service you want to reach</text></switch></g><rect x="130" y="70" width="190" height="50" fill="none" stroke="#4f9cfe" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-end; justify-content: unsafe flex-end; width: 188px; height: 1px; padding-top: 117px; margin-left: 130px;"><div data-drawio-colors="color: #4F9CFE; " style="box-sizing: border-box; font-size: 0px; text-align: right;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(79, 156, 254); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">wireguard's namespace</div></div></div></foreignObject><text x="318" y="117" fill="#4F9CFE" font-family="Helvetica" font-size="12px" text-anchor="end">wireguard's namespace</text></switch></g><rect x="140" y="80" width="170" height="20" fill="none" stroke="#70b433" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 168px; height: 1px; padding-top: 90px; margin-left: 141px;"><div data-drawio-colors="color: #70B433; background-color: #181818; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(112, 180, 51); line-height: 1.2; pointer-events: all; background-color: rgb(24, 24, 24); white-space: normal; overflow-wrap: normal;">wireguard & nginx</div></div></div></foreignObject><text x="225" y="94" fill="#70B433" font-family="Helvetica" font-size="12px" text-anchor="middle">wireguard & nginx</text></switch></g><path d="M 310 90 L 330 90 L 330 30 L 318.24 30" fill="none" stroke="#e67f43" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 312.24 30 L 320.24 26 L 318.24 30 L 320.24 34 Z" fill="#e67f43" stroke="#e67f43" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/><path d="M 30 90 L 131.76 90" fill="none" stroke="#e67f43" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 137.76 90 L 129.76 94 L 131.76 90 L 129.76 86 Z" fill="#e67f43" stroke="#e67f43" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/><ellipse cx="15" cy="67.5" rx="7.5" ry="7.5" fill="#181818" stroke="#b9b9b9" pointer-events="all"/><path d="M 15 75 L 15 100 M 15 80 L 0 80 M 15 80 L 30 80 M 15 100 L 0 120 M 15 100 L 30 120" fill="none" stroke="#b9b9b9" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 127px; margin-left: 15px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;">Actor</div></div></div></foreignObject><text x="15" y="139" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Actor</text></switch></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg>
\ No newline at end of file |