<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title></title>
    <subtitle>Webpage of Henrik Gerdes</subtitle>
    <link rel="self" type="application/atom+xml" href="https://henrikgerdes.me/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://henrikgerdes.me"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-04-18T00:00:00+00:00</updated>
    <id>https://henrikgerdes.me/atom.xml</id>
    <entry xml:lang="en">
        <title>Native IPv6 Kubernetes for true edge routing</title>
        <published>2026-04-18T00:00:00+00:00</published>
        <updated>2026-04-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              hegerdes
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://henrikgerdes.me/blog/2026-04-k8s-native-ipv6-edge/"/>
        <id>https://henrikgerdes.me/blog/2026-04-k8s-native-ipv6-edge/</id>
        
        <content type="html" xml:base="https://henrikgerdes.me/blog/2026-04-k8s-native-ipv6-edge/">&lt;h1 id=&quot;kubernetes-ipv6&quot;&gt;Kubernetes &amp;amp; IPv6&lt;&#x2F;h1&gt;
&lt;p&gt;Let’s bring some technologies with very different adoption metrics closer together:&lt;br &#x2F;&gt;
Kubernetes is just over 11 years old, as of writing. IPv6 is from 1998, that’s more than twice the age of k8s with 27 years. Some early deployments are even older.&lt;&#x2F;p&gt;
&lt;p&gt;While Kubernetes is nothing but a success story, IPv6 has a &lt;em&gt;complicated&lt;&#x2F;em&gt; history. Based on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.google.com&#x2F;intl&#x2F;en&#x2F;ipv6&#x2F;statistics.html?yzh=28197&quot;&gt;Google data&lt;&#x2F;a&gt;, IPv6 just hit 50% of traffic - after almost 30 years. Let’s change that because it will make all our lives easier in the long run. Because IPv6 is the replacement of a legacy protocol - not an extension!&lt;&#x2F;p&gt;
&lt;p&gt;One of the major advantages of IPv6 is the much larger address space of 2^128 compared to 2^32. Instead of handing out individual IPs to each host or even sharing them behind (C)NAT, ISPs and cloud provider usually hand out entire ranges. Typically ranges between &lt;code&gt;&#x2F;56&lt;&#x2F;code&gt; and &lt;code&gt;&#x2F;64&lt;&#x2F;code&gt; are advertised. This means that every one of these prefixes has more IPs available then the entire IPv4 space.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s have some fun with that in Kubernetes!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;an-easy-ipv6-setup-in-kubernetes&quot;&gt;An easy IPv6 setup in Kubernetes&lt;&#x2F;h2&gt;
&lt;p&gt;Kubernetes has supported IPv6 since &lt;code&gt;v1.6&lt;&#x2F;code&gt;, but the usability heavily depends on the CNI. The easiest way to use IPv6 in Kubernetes is to set these two args on cluster initialization with:&lt;br &#x2F;&gt;
&lt;code&gt;kubeadm init --pod-network-cidr=fd00:10:32::&#x2F;56 --service-cidr=fd00:10:64::&#x2F;112&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This example uses unique local addresses (ULA) IPv6 and does not need any special network requirements. Functionally it is equivalent to IPv4 clusters. These settings and the configured CNI will create an overlay network where pods can reach each other directly via the ULA addresses, but IP packets from and to the Internet need to be rewritten to reach anything. Nothing is really simplified here since we still distinguish between “private” and “public” IPs. Nevertheless, this is a great approach for testing and dev environments with tools like minikube, kind and more.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;native-routing&quot;&gt;Native Routing&lt;&#x2F;h3&gt;
&lt;p&gt;Since IPv6 allows anyone to get large, unique global address spaces, we should use them:&lt;br &#x2F;&gt;
&lt;code&gt;kubeadm init --pod-network-cidr=2a01:10:32::&#x2F;56 --service-cidr=2a01:34:e393::&#x2F;112&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;It uses global unicast addresses (GUA) that were allocated to you by your ISP or cloud provider. This setup requires a little more planning. We need our own IPv6 prefix that is large enough and not used by other devices. By default, Kubernetes tries to allocate a &lt;code&gt;&#x2F;64&lt;&#x2F;code&gt; from the pod network IPv6 CIDR to each node. In my opinion that is a very large default and can be wasteful in certain environments, since we will never have 2^64 pods on one node. It can be changed by setting &lt;code&gt;--node-cidr-mask-size-ipv6&lt;&#x2F;code&gt; accordingly. Depending on your requirements, I would set a value between &lt;code&gt;&#x2F;64&lt;&#x2F;code&gt; and &lt;code&gt;&#x2F;112&lt;&#x2F;code&gt;. Even a &lt;code&gt;&#x2F;112&lt;&#x2F;code&gt; would allow 2^16=65536 IPs for each node to be consumed by pods.&lt;br &#x2F;&gt;
Exactly the same cidr-mask-arg can be used when you don’t have a &lt;code&gt;&#x2F;56&lt;&#x2F;code&gt; IPv6 prefix or do not want to allocate the entire range to a single cluster. Service CIDRs can also be adjusted according to ones need.&lt;&#x2F;p&gt;
&lt;p&gt;Due to this approach being tailored to the current environment it runs in, it is a little less flexible, BUT it allows much simpler routing. As long as you don’t have any firewalls configured and all addresses are correctly advertised, every pod can directly reach the internet and can be reached from the internet. No service, loadbalancer, proxy or NAT required. Flat, native and efficient networking.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;native-routing-on-the-edge&quot;&gt;Native Routing on the edge&lt;&#x2F;h3&gt;
&lt;p&gt;From the network perspective, the routing became simpler, but it needs proper planning and requires you to have one large CIDR allocated to you. Sometimes this is not the case. Kubernetes is designed for distributed workloads. Maybe you want a multi-region cluster, a cluster spanning between clouds and a cluster that includes edge devices. Now every location has their own distinct address prefixes.&lt;br &#x2F;&gt;
Here IPv6 really shines. Kubernetes at its core does not really care about IPs. We can have scattered CIDRs per node, since the routing is handled by the CNI anyway, not Kubernetes. The only thing that is preventing us from doing this by default is the &lt;code&gt;node-ipam-controller&lt;&#x2F;code&gt; in the &lt;code&gt;kube-controller-manager&lt;&#x2F;code&gt; - which can be turned off.&lt;br &#x2F;&gt;
Now the &lt;code&gt;pod-network-cidr&lt;&#x2F;code&gt; does not matter. The cluster initializes and CNI can handles the IP allocation, either via BGP or “manually” by patching each node’s &lt;code&gt;.spec.podCIDR&lt;&#x2F;code&gt; and &lt;code&gt;.spec.podCIDRs&lt;&#x2F;code&gt; fields. Now we can have a cluster with one node on AWS, one on GCP, Azure and one running at your home - with all pods communicating natively over IPv6.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-few-notes-about-kubernetes-ipv6&quot;&gt;A few notes about Kubernetes IPv6&lt;&#x2F;h2&gt;
&lt;p&gt;Within the Kubernetes network and the IPv6 Internet, all of the above approaches work without problems. Unfortunately, not everything is IPv6 and we still have to deal with legacy IPv4. The best and easiest way to deal with that is to use &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc6147&quot;&gt;DNS64&lt;&#x2F;a&gt; at the CoreDNS upstream level. DNS64 essentially provides AAAA records for domains that do not have any natively by appending the target’s IPv4 A address to a predefined IPv6 prefix. The resulting address will point to an &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc6146&quot;&gt;NAT64&lt;&#x2F;a&gt; implementation, which will handle IPv6 to IPv4 translation.&lt;br &#x2F;&gt;
While starting, there is no need to build this on your own, there are public and free DNS64&#x2F;NAT64 services available.&lt;&#x2F;p&gt;
&lt;p&gt;Since we are already building clusters how they will be run in the future, we needed to alter some Kubernetes default configurations. The same most likely applies to your CNI. I used Cilium for all my setups, some of the configuration changes includes turning off IPv4, setting the routing mode and using kube-proxy replacement.&lt;&#x2F;p&gt;
&lt;p&gt;Native IPv6 routing simplifies the networking drastically but also exposes your workloads directly to the Internet if all addresses are correctly advertised and there is no filtering; a firewall is essential. Cilium provides great tooling for protecting the node, cluster and individual pods.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;A word about DualStack:&lt;br &#x2F;&gt;
One may ask: Why just not use IPv4 and IPv6 in the cluster and workloads would use whatever works - no need for NAT64&#x2F;DNS64&lt;&#x2F;p&gt;
&lt;p&gt;DONT&lt;&#x2F;p&gt;
&lt;p&gt;You will have two network stacks, loose native routing, have services that by default are SingleStack and apps that bind to the wrong IPs. Trust me, I tried it. You will not have less problems but double - IPv4 is legacy. There is a reason AWS EKS does not offer this configuration.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;encouragement-try-it&quot;&gt;Encouragement - try it&lt;&#x2F;h2&gt;
&lt;p&gt;While this all can sound a little complex at the beginning, it has become quite simple. Resources on the web are getting more numerous, and ISPs and clouds improved their IPv6 adoption a lot (except GitHub). I used Hetzner a lot for testing, they give you a free &lt;code&gt;&#x2F;64&lt;&#x2F;code&gt; for each node. Scaleway is also a good option. If you’re curious, you can also try to reverse engineer EKS and reimplement it, like I did - they are not doing anything magical.  
If native IPv6 is, for whatever reason, not possible, please at least create a loadbalancer that has IPv4 and IPv6. Internally all traffic can still be IPv4, but everyone on the Internet can talk to you over a modern connection without the need for DNS64&#x2F;NAT64.&lt;&#x2F;p&gt;
&lt;p&gt;Regarding the different adoption rates, I have a thesis:
Kubernetes is something “new”, it solved a new and unsolved problem and had big names carrying it. IPv6 aims to fix issues from a previous solution that still &lt;em&gt;kind of works&lt;&#x2F;em&gt;. Unfortunately, it is often cheaper to find workarounds for old solutions instead of investing in new ones. But with the increasing price for IPv4 addresses, this finally seems to change.&lt;&#x2F;p&gt;
&lt;p&gt;I hope I was able to give you a high-level overview and some approaches on how to bring IPv6 to the 90% traffic mark. Feel free to write me via &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mastodon.social&#x2F;@hegerdes&quot;&gt;Mastodon&lt;&#x2F;a&gt; or the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;kubernetes.slack.com&#x2F;team&#x2F;U05C4U2T5AA&quot;&gt;Kubernetes Slack&lt;&#x2F;a&gt; if you have any questions. I implemented all of the above approaches and even automated most of them completely - it’s not that hard :)&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Gateway API doesn&#x27;t solve real problems - yet</title>
        <published>2026-01-31T00:00:00+00:00</published>
        <updated>2026-01-31T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              hegerdes
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://henrikgerdes.me/blog/2026-01-gateway-api-exp-1/"/>
        <id>https://henrikgerdes.me/blog/2026-01-gateway-api-exp-1/</id>
        
        <content type="html" xml:base="https://henrikgerdes.me/blog/2026-01-gateway-api-exp-1/">&lt;h1 id=&quot;gateway-api-doesn-t-solve-real-problems-yet&quot;&gt;Gateway API doesn’t solve real problems - yet&lt;&#x2F;h1&gt;
&lt;p&gt;🧾📖 &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;henrikgerdes.me&#x2F;docs&#x2F;gateway-api-exp-1.pdf&quot;&gt;PDF version&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;&#x2F;strong&gt; This tells my personal experiences with the Kubernetes Gateway-API and shows the value Ingress-Nginx provided.&lt;br &#x2F;&gt;
&lt;strong&gt;My takeaway&lt;&#x2F;strong&gt;: Gateway API makes hard things possible - but easy things hard.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;why-the-change&quot;&gt;Why the Change?&lt;&#x2F;h2&gt;
&lt;p&gt;The Kubernetes steering committee shocked a lot of people when they announced the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;kubernetes.io&#x2F;blog&#x2F;2025&#x2F;11&#x2F;11&#x2F;ingress-nginx-retirement&#x2F;&quot;&gt;retirement of the ingress-nginx-controller&lt;&#x2F;a&gt; at the 2025 Atlanta-Kubecon.&lt;br &#x2F;&gt;
After March 2026, the biggest ingress controller will not receive any more updates and patches. This change resulted in quite some angry comments towards the maintainers and the committee. But this change was foreseeable. The maintainers repeatedly reached out for more support or asked for corporate sponsors - which were unanswered.&lt;br &#x2F;&gt;
The decision is understandable, at least. A free, feature rich reverse proxy with good documentation that is used by thousands for free. Some corporations have generated billions in sales with requests that were served by &lt;code&gt;ingress-nginx&lt;&#x2F;code&gt;, but the only thing that was given back were support requests, bug reports or new feature requests.&lt;br &#x2F;&gt;
I will not go into the debate of corporations exploiting open-source projects - this has been talked about a lot recently. The decision has been made, and the direction given was clear. The future is the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;gateway-api.sigs.k8s.io&#x2F;&quot;&gt;Gateway-API&lt;&#x2F;a&gt;!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-a-new-api&quot;&gt;Why a new API?&lt;&#x2F;h2&gt;
&lt;p&gt;The &lt;code&gt;Ingress&lt;&#x2F;code&gt; API is a core component of the &lt;code&gt;networking.k8s.io&lt;&#x2F;code&gt; Kubernetes API-Group. It defines the routing path for HTTP-Traffic (L7-Layer) via a bunch of rules with &lt;code&gt;PATH&lt;&#x2F;code&gt; and &lt;code&gt;Host&lt;&#x2F;code&gt;. It can also do TLS for these rules but that’s pretty much it.&lt;br &#x2F;&gt;
It does not handle headers like &lt;code&gt;X-Forwarded&lt;&#x2F;code&gt;, cookies, authentication, payload size, compression, timeouts, redirects, traffic splitting and many more. All of these things &lt;strong&gt;can&lt;&#x2F;strong&gt; be done with ingress though, but not via its core API-Definition.&lt;br &#x2F;&gt;
Annotations are commonly used to enrich API-Objects with additional information. Ingress-Nginx had over 110 of them. A problem that comes with Annotations is that they are not validated, since they are not part of the API-Spec and that they are not vendor agnostic. So, you can’t use the same annotations from Ingress-Nginx for Kong, HAProxy, Traefik or the Apache-Webserver-Ingress. Each of these have their own feature- and annotation set, switching ingress-controller usually takes some time.&lt;&#x2F;p&gt;
&lt;p&gt;Another concern is that all these settings are applied at the ingress level. Should a developer with &lt;code&gt;Ingress&lt;&#x2F;code&gt; access really be able to alter the TLS config for a whole domain?&lt;&#x2F;p&gt;
&lt;p&gt;Gateway-API promises to fix this. A well-defined API that separates operational tasks like TLS and proxy settings from routing configuration.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;gateway-api.sigs.k8s.io&#x2F;images&#x2F;resource-model.png&quot; alt=&quot;Gateway-API Role Diagram&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Gateway-API introduces a stricter role-based approach. It has a mental model of &lt;em&gt;how does what&lt;&#x2F;em&gt; and which resources can be referenced from where. It’s &lt;code&gt;HTTPRoute&lt;&#x2F;code&gt; supports native routing via hostname, header, path or query parameters. All well defined in its core API but still extendable via filters.&lt;br &#x2F;&gt;
Apart from HTTP routing, Gateway-API also proposes &lt;code&gt;GRPCRoutes&lt;&#x2F;code&gt;, &lt;code&gt;TLSRoutes&lt;&#x2F;code&gt;, &lt;code&gt;TCPRoutes&lt;&#x2F;code&gt; and &lt;code&gt;UDPRoutes&lt;&#x2F;code&gt;. While some of these are still experimental, having a well-defined, vendor-agnostic spec for all these use-cases is a killer feature.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-does-this-affect-developers-and-admins&quot;&gt;How does this affect Developers and Admins?&lt;&#x2F;h2&gt;
&lt;p&gt;In theory this means less error-prone routing configuration (let’s see how this will work out) and developers not having to worry about TLS.&lt;br &#x2F;&gt;
In practice, developers will need to learn a new doc-spec or wait for admins to give them templates.&lt;&#x2F;p&gt;
&lt;p&gt;Admins on the other hand will have a lot more to do. Configure the Gateway, provide templates for developers and allow all necessary namespaces to reference the Gateway. They need to test and set up new integration, handle TLS and maintain a separate API that is maintained outside the Kubernetes core API.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;gateway-api-is-more-complex&quot;&gt;Gateway API is more complex&lt;&#x2F;h3&gt;
&lt;p&gt;With more features comes more complexity.&lt;br &#x2F;&gt;
The Ingress API has two resource types, &lt;code&gt;Ingress&lt;&#x2F;code&gt; and the hardly noticed &lt;code&gt;IngressClass&lt;&#x2F;code&gt; type. The Gateway-API has &lt;code&gt;ReferenceGrant&lt;&#x2F;code&gt;, &lt;code&gt;BackendTLSPolicy&lt;&#x2F;code&gt;, &lt;code&gt;GRPCRoute&lt;&#x2F;code&gt;, &lt;code&gt;Gateway&lt;&#x2F;code&gt;, &lt;code&gt;GatewayClass&lt;&#x2F;code&gt;, &lt;code&gt;HTTPRoute&lt;&#x2F;code&gt; and these are just the stable API-Objects, there are a lot more in experimental mode.&lt;&#x2F;p&gt;
&lt;p&gt;Ingress is a core component of Kubernetes, the Gateway-API is not shipped with Kubernetes and needs to be installed separately via &lt;code&gt;CRDs&lt;&#x2F;code&gt;. This might result in bootstrapping challenges since one cannot expect that the APIs are installed.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;To install them use &lt;code&gt;kubectl apply --server-side -f https:&#x2F;&#x2F;github.com&#x2F;kubernetes-sigs&#x2F;gateway-api&#x2F;releases&#x2F;download&#x2F;&amp;lt;LATEST_VERSION&amp;gt;&#x2F;standard-install.yaml&lt;&#x2F;code&gt;. The &lt;code&gt;--server-side&lt;&#x2F;code&gt; is required since the API is too big for client side apply.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;To setup a &lt;code&gt;Gateway&lt;&#x2F;code&gt; cluster admins need to install &lt;code&gt;CRDs&lt;&#x2F;code&gt;, choose an implementation, install an operator&#x2F;controller and then create the &lt;code&gt;Gateway&lt;&#x2F;code&gt;. Most Gateway-API implementations separate the controlplane from the dataplane. Most Ingress implementations used a shared approach where an agent ran as a sidecar process next to the dataplane to ensure the proper configuration.&lt;&#x2F;p&gt;
&lt;p&gt;Right now, the selecting a Gateway is actually the hardest part. While the main API-Objects specs have reached GA, their features are not yet supported by all implementations. While the Gateway-API SIG tries to help with this decision by providing &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;gateway-api.sigs.k8s.io&#x2F;implementations&#x2F;v1.4&#x2F;&quot;&gt;comparison tables&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;kubernetes-sigs&#x2F;gateway-api&#x2F;tree&#x2F;main&#x2F;conformance&#x2F;reports&#x2F;&quot;&gt;conformance reports&lt;&#x2F;a&gt; it is still a lot of work to go through.&lt;br &#x2F;&gt;
These on-paper comparisons don’t replace real-word tests to catch any edge cases and say nothing about performance between all these. If you look for some real-world comparisons, you may wanna check out &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;howardjohn&#x2F;gateway-api-bench&quot;&gt;this benchmark&lt;&#x2F;a&gt; from &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;howardjohn&quot;&gt;John Howard&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;gateway-api-is-not-vendor-agnostic&quot;&gt;Gateway API is not vendor agnostic&lt;&#x2F;h3&gt;
&lt;p&gt;Let’s remember the goals of Gateway API: Separate personas, strict validation and a vendor-agnostic config.&lt;&#x2F;p&gt;
&lt;p&gt;Right now, I see a trend that is moving against the last goal. Yes, TLS configuration and routing might be standardized, but the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nginx&#x2F;nginx-gateway-fabric&quot;&gt;nginx-gateway-fabric&lt;&#x2F;a&gt; for example already brings their own set of 10 &lt;code&gt;CRDs&lt;&#x2F;code&gt; for configuring the &lt;code&gt;Gateway&lt;&#x2F;code&gt; itself or for use cases that are not yet defined in the standard Gateway-API spec. And so does Kong and Envoy-Gateway with even more &lt;code&gt;CRDs&lt;&#x2F;code&gt;.&lt;br &#x2F;&gt;
There is no native way to do auth or mTLS enforcement (for clients) in the Gateway-API yet, so implementations bring their own filters and &lt;code&gt;CRDs&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Gateway API, by design, is extendable and vendors are using this extendibility to overcome the shortcomings of the core API. They are using these to separate themselves from each other and maybe - to create a vendor-lock-in. Never forget that there are companies behind these products that want and need to make money.&lt;&#x2F;p&gt;
&lt;p&gt;Maybe over time more features will be covered by the core Gateway-API, but most of us know even if the spec is well defined, implementations can behave differently. My &lt;code&gt;TLSRoute&lt;&#x2F;code&gt; worked perfectly with Cilium but was not working with nginx-gateway-fabric.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;gateway-api-is-not-widely-supported-yet&quot;&gt;Gateway API is not widely supported yet&lt;&#x2F;h3&gt;
&lt;p&gt;New technologies need time for adoption, it is totally normal that most helm charts do not yet ship with &lt;code&gt;HTTPRoutes&lt;&#x2F;code&gt; alongside &lt;code&gt;Ingress&lt;&#x2F;code&gt;. Unfortunately a lot of helm charts do not support a &lt;code&gt;extraObjects&lt;&#x2F;code&gt; either, so you need multiple commands to deploy your app or a multi source GitOps solution.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Creating a good general helm template for &lt;code&gt;HTTPRoutes&lt;&#x2F;code&gt; is quite hard. I know this because I crated the &lt;code&gt;HttpRoute&lt;&#x2F;code&gt; helm template that gets generated when you run &lt;code&gt;helm create &amp;lt;my-chart&amp;gt;&lt;&#x2F;code&gt; in recent versions of helm.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;I wanna give another example of a problem I encountered:&lt;br &#x2F;&gt;
A common scenario in highly automated clusters is having an Ingress-Controller, CertManager and ExternalDNS. These work perfectly together. The ingress is created and uses a fallback TLS certificate, ExternalDNS checks the domain records and adds a new record if not set yet and Certmanager creates a &lt;code&gt;http-01-challenge&lt;&#x2F;code&gt; to obtain a valid certificate. It may take some minutes, but &lt;em&gt;eventually&lt;&#x2F;em&gt; you have a valid, working &lt;code&gt;Ingress&lt;&#x2F;code&gt; with TLS.&lt;&#x2F;p&gt;
&lt;p&gt;Now try the same with Gateway-API. It will not work, even with experimental flags. Why does it not work?&lt;br &#x2F;&gt;
The Gateway handles the TLS, not the &lt;code&gt;HTTPRoute&lt;&#x2F;code&gt;. The default listener likely does not have a valid certificate for your new domain, so you add a new listener. The &lt;code&gt;HTTPRoute&lt;&#x2F;code&gt; references that listener but never becomes ready because the listener is not healthy yet due to the missing certificate. ExternalDNS watches &lt;code&gt;HTTPRoutes&lt;&#x2F;code&gt;, but only the ones that are ready and have an IP. Now the circle closes, without a valid DNS record, you can’t complete a &lt;code&gt;http-01-challenge&lt;&#x2F;code&gt;. It’s a deadlock.&lt;&#x2F;p&gt;
&lt;p&gt;The only way around this that I found was to switch to a &lt;code&gt;dns-01 challenge&lt;&#x2F;code&gt;. The ExternalDNS project is aware of this problem, but AFAIK the solution is still work-in-progress.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ingress-nginx-will-be-missed&quot;&gt;Ingress-Nginx will be missed&lt;&#x2F;h2&gt;
&lt;p&gt;I don’t want to make Gateway-API look bad; it is powerful - maybe not just ready yet.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;For those not ready to switch: Maybe look at Cainguards &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.chainguard.dev&#x2F;unchained&#x2F;introducing-chainguard-emeritoss&quot;&gt;EmeritOSS&lt;&#x2F;a&gt; program. They &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.chainguard.dev&#x2F;unchained&#x2F;keeping-ingress-nginx-alive&quot;&gt;announced&lt;&#x2F;a&gt; to provide basic security maintenance for &lt;code&gt;ingress-nginx&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;For these reason, Ingress-Nginx will be missed. It is a dead simple solution that just works. The battle-tested Nginx with a small agent that does config generation and reloads. Provided by a couple of individuals that did get nothing in return but provided the technology that served half of all Kubernetes-hosted HTTP traffic.&lt;br &#x2F;&gt;
Ingress-Nginx is a community project - no big company behind it. That’s something that will change with Gateway-API. Implementing all of Gateway-APIs features is a lot of work, no one can expect a couple of individuals to do that in their free time.&lt;br &#x2F;&gt;
Now it’s done by corporations that battle for the market share that Ingress-Nginx will leave behind. Once this battle is settled, I wouldn’t be surprised to see more Broadcom, HashiCorp and Docker like rug-pulls.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>AWS Web-Identity-Token - The free IDP for all your OnPrem solutions</title>
        <published>2025-12-08T00:00:00+00:00</published>
        <updated>2025-12-08T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              hegerdes
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://henrikgerdes.me/blog/2025-12-aws-web-identity-token/"/>
        <id>https://henrikgerdes.me/blog/2025-12-aws-web-identity-token/</id>
        
        <content type="html" xml:base="https://henrikgerdes.me/blog/2025-12-aws-web-identity-token/">&lt;h1 id=&quot;reduce-your-token-usage-for-all-non-aws-apps-with-aws-web-identity-token&quot;&gt;Reduce your Token-Usage for all non AWS-Apps with AWS Web-Identity-Token&lt;&#x2F;h1&gt;
&lt;hr &#x2F;&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TLDR:&lt;&#x2F;strong&gt; AWS new STS Web-Identity-Token function allows secure, low maintenance authentication via OIDC for all none AWS Services at no additional cost. Perfect for OnPrem system or CI.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;AWS enabled a new functionality within their secret-token-service (STS) which basically is a free and managed &lt;a href=&quot;https:&#x2F;&#x2F;henrikgerdes.me&#x2F;blog&#x2F;2025-12-aws-web-identity-token&#x2F;OpenID_Connect&quot;&gt;OpenID Connect&lt;&#x2F;a&gt; (OIDC) Identity-Provider (IDP).&lt;br &#x2F;&gt;
Users and IAM-Roles with the needed permissions can create shot lived &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;JSON_Web_Token&quot;&gt;JWTs&lt;&#x2F;a&gt; and can securely authenticate against any service that supports OIDC-Token authentication. Services can validate the token via the AWS managed IDP-Issuer. This essentially makes all long lived and manually managed credentials unneeded.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;use-cases&quot;&gt;Use cases&lt;&#x2F;h2&gt;
&lt;p&gt;I found this functionality via a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;dev.to&#x2F;aws-builders&#x2F;aws-iam-outbound-oidc-with-google-cloud-identity-pool-5ak7&quot;&gt;post from Piotr Pabis&lt;&#x2F;a&gt;. He implemented a (little over-engendered) demo to create a low maintenance authentication setup between AWS and GCP using AWS Web-Identity-Tokens, to show how to create multi-cloud secure auth setups with short lived tokens.&lt;br &#x2F;&gt;
This inspired me to test it out and try to access my private Kubernetes Cluster with AWS-Tokens, but the use cases are virtually endless! Just to give a few examples:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;kubernetes&quot;&gt;Kubernetes&lt;&#x2F;h3&gt;
&lt;p&gt;If you have a hybrid infrastructure with some systems on AWS and some OnPrem this can come very handy. Kubernetes natively supports OIDC and all you need to enable AWS Web-Identity-Token authentication is to add the AWS managed IdP to your Kubernetes &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;kubernetes.io&#x2F;docs&#x2F;reference&#x2F;access-authn-authz&#x2F;authentication&#x2F;#configuring-the-api-server&quot;&gt;structured-auth-config&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Docs: https:&#x2F;&#x2F;kubernetes.io&#x2F;docs&#x2F;reference&#x2F;access-authn-authz&#x2F;authentication&#x2F;#openid-connect-tokens&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;piVersion&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; a&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;piserver.config.k8s.io&#x2F;v1beta1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;k&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ind&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; A&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;uthenticationConfiguration&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;j&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;wt&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span&gt;  -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; i&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ssuer&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;      u&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;rl&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; h&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ttps:&#x2F;&#x2F;xxx.tokens.sts.global.api.aws&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;      a&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;udiences&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span&gt;        -&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; h&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ttps:&#x2F;&#x2F;k8s.my-org.com&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;    c&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;laimMappings&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;      u&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;sername&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;        c&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;laim&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; s&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ub&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;        p&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;refix&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;aws:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;&#x2F;strong&gt; You can add as many Issuers as you want, you can also configure and limit anonymous auth to &lt;a href=&quot;&#x2F;blog&#x2F;2025-05-k8s-annonymus-auth&#x2F;&quot;&gt;increase your Kubernetes security&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Now you can use normal Kubernetes RBAC to allow the &lt;code&gt;aws:&amp;lt;YOUR_ROLE_ARN&amp;gt;&lt;&#x2F;code&gt; user to access the needed resources.&lt;br &#x2F;&gt;
No need to ever share a &lt;code&gt;Kubeconf.yaml&lt;&#x2F;code&gt; ever again. Combine this approach with the &lt;a href=&quot;&#x2F;blog&#x2F;2024-03-aws-from-gh-actions&#x2F;&quot;&gt;credential less authentication between GitHub Actions or GitLab CI&lt;&#x2F;a&gt; and gone are the days of managing long lived credentials, rotating them and risking leakage just to deploy something to Kubernetes.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;workflow-automation&quot;&gt;Workflow Automation&lt;&#x2F;h3&gt;
&lt;p&gt;You use automated Workflow? Have any WebHooks or have Microsoft Power Automate setup? Now everything that is accessible can have low maintenance short lived token that can easily be verified via the aws managed IdP. Need some examples?&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Your AWS Lambda has an issue and you want it to automatically open a ticket in your support system? The lambda can use its own identity to create a token which the ticket system can validate.&lt;&#x2F;li&gt;
&lt;li&gt;Access an OnPrem file Share via HTTP. Just send the JWT as a Bearer, validate it and access internal documents to be processed in your AWS automation.&lt;&#x2F;li&gt;
&lt;li&gt;One AWS Lambda can authenticate to another without Cognito.&lt;&#x2F;li&gt;
&lt;li&gt;You CI assumes an AWS role and sends an authenticated request to your chat app to push notifications.&lt;&#x2F;li&gt;
&lt;li&gt;Update any OnPrem hosted document without pushing it to AWS.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;how-to-use&quot;&gt;How to use&lt;&#x2F;h2&gt;
&lt;p&gt;So how do I start using this?&lt;&#x2F;p&gt;
&lt;p&gt;Easy, just enable it and you can start requesting tokens. Everything else is managed by AWS. You can just the &lt;code&gt;aws cli&lt;&#x2F;code&gt; to request tokens, but also the SDK of &lt;em&gt;your favorite&lt;&#x2F;em&gt; language. Examples can be found at the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;boto3.amazonaws.com&#x2F;v1&#x2F;documentation&#x2F;api&#x2F;latest&#x2F;reference&#x2F;services&#x2F;sts&#x2F;client&#x2F;get_web_identity_token.html&quot;&gt;AWS Python boto3 docs&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Get your issuer config&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; iam&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; get-outbound-web-identity-federation-info&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-output&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; json&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; if not enabled, you can enable it with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;4&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; iam&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; enable-outbound-web-identity-federation&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-output&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; json&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If not already enabled, it creates a aws managed private key-pair (RSA and ECDSA) and publishes the IdP-Config under a globally accessible and unique endpoint. The command then gives you an URL in the format &lt;code&gt;https:&#x2F;&#x2F;xxx.tokens.sts.global.api.aws&lt;&#x2F;code&gt;.&lt;br &#x2F;&gt;
When you access &lt;code&gt;https:&#x2F;&#x2F;xxx.tokens.sts.global.api.aws&#x2F;.well-known&#x2F;openid-configuration&lt;&#x2F;code&gt; you can see all supported claims, supported signature algorithms and the path to your JWKs config, which contains all information to validate your JWTs with it’s associated public key.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;Version&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;2012-10-17&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;Statement&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span&gt;    {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;Effect&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Allow&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;Action&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;sts:TagGetWebIdentityToken&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;sts:GetWebIdentityToken&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;sts:SetContext&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;      ]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;Resource&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;&#x2F;span&gt;&lt;span&gt;  ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;14&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;&#x2F;strong&gt; You can also add &lt;code&gt;Condition&lt;&#x2F;code&gt; to the permissions to ensure a low TTL, the used signer algorithm or any validation on tags you can think of. You also need at least the AWS-CLI version &lt;code&gt;≥2.32.5&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Now every IAM-Role with these permissions can crate a JWT:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; sts&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; get-web-identity-token&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-audience&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; demo&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-signing-algorithm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ES384&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; You can also add up to 50 tags which will make extra information available in the JWT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; sts&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; get-web-identity-token&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-audience&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; demo&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-signing-algorithm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ES384&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-tags&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Key=account,Value=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;123456&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The decoded JWT will look like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;aud&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;demo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;sub&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;lt;MY_IAM_ROLE_ARN&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;https:&#x2F;&#x2F;sts.amazonaws.com&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;org_id&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;o-xxx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;aws_account&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;123456&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;ou_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;xxx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;request_tags&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;account&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;123456&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;original_session_exp&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;2025-12-07T22:17:32Z&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;source_region&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;eu-central-1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;principal_id&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;lt;MY_IAM_ROLE_ARN&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;14&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;identity_store_user_id&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;xxx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;15&lt;&#x2F;span&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;16&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;iss&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;https:&#x2F;&#x2F;xxx.tokens.sts.global.api.aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;17&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;exp&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 1765140780&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;18&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;iat&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 1765140480&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;19&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;jti&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;xxx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;20&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For testing purposes or if you have self developed applications to you want to use with AWS web-identity-tokens yo can use the example python script below to validate the token.&lt;&#x2F;p&gt;
&lt;details&gt;
  &lt;summary&gt;validate.py&lt;&#x2F;summary&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; requests&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; jwt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; verifyToken&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-function&quot;&gt;    token&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; str&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-function&quot;&gt;    jwks&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; dict&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-function&quot;&gt;    audience&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; str&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-function&quot;&gt;    issuer&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; str&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-function&quot;&gt;    algorithms&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;RS256&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ES384&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; dict&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;    try&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;        return&lt;&#x2F;span&gt;&lt;span&gt; jwt&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span&gt;decode&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;&#x2F;span&gt;&lt;span&gt;            token&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; jwks&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; algorithms&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;algorithms&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; audience&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;audience&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; issuer&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;issuer&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;14&lt;&#x2F;span&gt;&lt;span&gt;        )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;15&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;    except&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; Exception&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; as&lt;&#x2F;span&gt;&lt;span&gt; e&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;16&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;        print&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Token verification failed:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; e&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;17&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;        return&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; None&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;18&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;19&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;20&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; getJWKs&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-function&quot;&gt;jwks_uri&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; str&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; dict&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;21&lt;&#x2F;span&gt;&lt;span&gt;    resp&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; requests&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;jwks_uri&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;22&lt;&#x2F;span&gt;&lt;span&gt;    resp&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span&gt;raise_for_status&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;23&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span&gt; resp&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span&gt;json&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;24&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;25&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; getJWKsUri&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-function&quot;&gt;issuer&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; str&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; str&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;26&lt;&#x2F;span&gt;&lt;span&gt;    resp&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; requests&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;issuer&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;.well-known&#x2F;openid-configuration&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;27&lt;&#x2F;span&gt;&lt;span&gt;    resp&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span&gt;raise_for_status&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;28&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span&gt; resp&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span&gt;json&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;jwks_uri&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;29&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;30&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;31&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;if&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable&quot;&gt; __name__&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;__main__&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;32&lt;&#x2F;span&gt;&lt;span&gt;    iss&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;https:&#x2F;&#x2F;xxx.tokens.sts.global.api.aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;33&lt;&#x2F;span&gt;&lt;span&gt;    aud&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;demo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;34&lt;&#x2F;span&gt;&lt;span&gt;    token&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;xxx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;35&lt;&#x2F;span&gt;&lt;span&gt;    verifyToken&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;token&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; getJWKs&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;getJWKsUri&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;iss&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;keys&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; aud&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; iss&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;&#x2F;details&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>The Grafana trust problem</title>
        <published>2025-11-14T00:00:00+00:00</published>
        <updated>2025-11-14T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              hegerdes
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://henrikgerdes.me/blog/2025-11-grafana-mess/"/>
        <id>https://henrikgerdes.me/blog/2025-11-grafana-mess/</id>
        
        <content type="html" xml:base="https://henrikgerdes.me/blog/2025-11-grafana-mess/">&lt;h1 id=&quot;i-can-t-recommend-grafana-anymore&quot;&gt;I can’t recommend Grafana anymore&lt;&#x2F;h1&gt;
&lt;hr &#x2F;&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Disclaimer:&lt;&#x2F;em&gt;&lt;&#x2F;strong&gt; This tells my personal experiences with Grafana products. It also includes some facts but your experience may vary, and I would love to hear your take.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;I started my work life at a small software company near my university. They develop, run websites and operate web services for multiple clients. Everyone had multiple responsibilities, and they heavily relied on interns and freshmen—which can be both bad and good.&lt;br &#x2F;&gt;
For me it was good because I learned a lot.&lt;&#x2F;p&gt;
&lt;p&gt;At some point we needed a monitoring solution, and Zabbix didn’t fit well into the new and declarative world of containers and Docker. I was tasked to find a solution.
I looked at Loki&#x2F;Prometheus with Grafana and Elastic with Kibana.
Elastic was a beast! Heavy, hard to run, resource-hungry, and complex, Loki and Prometheus were the perfect fit back then.&lt;&#x2F;p&gt;
&lt;p&gt;So, I created a &lt;code&gt;docker-compose.yaml&lt;&#x2F;code&gt; with Loki, Prometheus and Grafana. Since they all were within a internal Docker network, we required no auth between them. Grafana was only exposed over an SSH tunnel. One static scrape config and the Docker Loki log plugin later, we had our observability stack. For non-Docker logs, we used Promtail.&lt;br &#x2F;&gt;
Loki and Prometheus stayed on the same machine and all we required was a local volume mount. Load was minimal.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ️ This is when I learned that you should not transform every log parameter to a label just to make it easier to select in the Grafana UI. Having a label for latency with basically limitless values will fill every disk inode’s, that’s just how Cortex bin-packs.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;I also found out Grafana Labs has a cloud offering with a nice free tier. I even used this for personal stuff. I had a good experience with them.&lt;&#x2F;p&gt;
&lt;p&gt;Time goes on, and I switched jobs. Now we have Kubernetes.&lt;br &#x2F;&gt;
The Prometheus container was now switching nodes. Roaming storage was a problem back then, and our workload increased by a lot. We also needed long-term storage (13 months). So I looked around and found Thanos and Mimir.&lt;br &#x2F;&gt;
Previous experiences with Grafana products were good, so I chose Mimir. Should be similar to Loki since both are based on Cortex. Now we didn’t really need Prometheus anymore. We were only using &lt;code&gt;remote_write&lt;&#x2F;code&gt; from Prometheus. Grafana had a solution for this. With the Grafana Agent, you can ship both logs and metrics to a remote location all in one binary. This seemed like a no-brainer.&lt;&#x2F;p&gt;
&lt;p&gt;Time goes on, and Grafana changed the Grafana Agent setup to Grafana Agent Flow Mode—some adjustments, but okay - software changes. And man, did Grafana like to change things.&lt;&#x2F;p&gt;
&lt;p&gt;They started to build their own observability platform to steal some of DataDog’s customers. They created Grafana OnCall their own notification system. Not only that, but they heavily invested in Helm charts and general starter templates. Basically, it took only two commands to install the metric&#x2F;log shippers and use Grafana Cloud. And even when you don’t want or can’t use Grafana Cloud, here are the Helm charts to install Mimir&#x2F;Loki&#x2F;Tempo. To make things even easier, let’s all put it in an umbrella chart (it renders to 6k lines in the default state). Or use their Grafana Operator to manage Grafana installs - or at least parts of it.&lt;&#x2F;p&gt;
&lt;p&gt;As many may have experienced, software maintenance shows with age.&lt;br &#x2F;&gt;
Grafana OnCall is deprecated, and Grafana Agent and Agent Flow were deprecated within 2-3 years of their creation. Some of the &lt;em&gt;easy to use&lt;&#x2F;em&gt; Helm charts are not maintained anymore. They also deprecated Angular within Grafana and switched to React for dashboards. This broke most existing dashboards.&lt;&#x2F;p&gt;
&lt;p&gt;On the same day they deprecated the Grafana Agent, they announced Grafana Alloy. The all in one replacement. It can do Logs, Metrics, Traces (zipkin &amp;amp; jaeger) and OTEL. The solution for everything!&lt;br &#x2F;&gt;
The solution kind of had a rough start and was a &lt;em&gt;little&lt;&#x2F;em&gt; buggy. But it got better over time. The Alloy Operator also entered the game because why not.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ️ They choose to use their own configuration language for alloy. Something that looks like HCL. I can understand why they didn’t want to use YAML but I’m still not a fan of this. Not everything needs their own DSL.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Happy End, right?  - Not quite&lt;br &#x2F;&gt;
The all-in-one solution does not support everything. While Grafana built their own monitoring empire, the kube-prometheus community consistently and naturally developed. The Prometheus Operator with &lt;code&gt;ServiceMonitor&lt;&#x2F;code&gt; and &lt;code&gt;PodMonitor&lt;&#x2F;code&gt; CRDs became the defacto standards in Kubernetes. So Alloy also supports the &lt;code&gt;monitoring.coreos.com&lt;&#x2F;code&gt; api-group CRDs, at least some parts of it. It natively works with &lt;code&gt;ServiceMonitor&lt;&#x2F;code&gt; and &lt;code&gt;PodMonitor&lt;&#x2F;code&gt;, but &lt;code&gt;PrometheusRules&lt;&#x2F;code&gt; needs extra configuration. The &lt;code&gt;AlertmanagerConfig&lt;&#x2F;code&gt; which would need to be implemented in Mimir is not supported. Because Mimir brings its own Alertmanager - at least sort of. There are version differences and small incompatibilities.  &lt;&#x2F;p&gt;
&lt;p&gt;But I got it all working; now I can finally stop explaining to my boss why we need to re-structure the monitoring stack every year.&lt;&#x2F;p&gt;
&lt;p&gt;Grafana just released Mimir 3.0. They re-architected the ingestion logic for scalability, and now they use a message broker. Yes, Mimir in version 3.0 needs Apache Kafka to work.&lt;br &#x2F;&gt;
None of the above things alone would be a reason to ditch Grafana products. Set aside the fact that they made it incredibly difficult now to find the ingestion endpoints for Grafana Cloud since they want to push users to use their new fleet-config management service. But all this together makes me uncomfortable recommending Grafana stuff.&lt;br &#x2F;&gt;
I just don’t know what will change next.&lt;&#x2F;p&gt;
&lt;p&gt;I want stability for my monitoring; I want it boring, and that’s something Grafana is not offering.  
It seems like the pace within Grafana is way too fast for many companies, and I know for a fact that that pace is partially driven by career-driven development. There are some smart people at Grafana but not every customer is smart nor has the capacity to make Grafana their priority number one. Complexity kills - we’ve seen this.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ️ Don’t get me wrong. Mimir, Loki and Grafana are technically really good software products and I (mostly) still like them but it’s the way these products are managed which makes me question them.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Sometimes I wonder how I would see this if I had chosen the ELK stack at my first job. I also wonder if the OpenShift approach (kube-prometheus-stack) with Thanos for long-term storage is the most time-stable solution.  
I just hope OTEL settles, gets stable and boring fast, and just lets me pick whatever I want for my backend. Because right now I’m done with monitoring. I just want to support our application and do not want to revisit the monitoring setup every x weeks, because monitoring is a necessity—not the product. At least for most companies.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Rootless GitLab Runners</title>
        <published>2025-10-05T00:00:00+00:00</published>
        <updated>2025-10-05T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              hegerdes
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://henrikgerdes.me/blog/2025-10-gitlab-rootles-runner/"/>
        <id>https://henrikgerdes.me/blog/2025-10-gitlab-rootles-runner/</id>
        
        <content type="html" xml:base="https://henrikgerdes.me/blog/2025-10-gitlab-rootles-runner/">&lt;h1 id=&quot;rootless-gitlab-runners&quot;&gt;Rootless GitLab Runners&lt;&#x2F;h1&gt;
&lt;hr &#x2F;&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;TL;DR:&lt;&#x2F;em&gt;&lt;&#x2F;strong&gt; Rootless Docker has become easy! You can also easily run the GitLab Runner binary with rootless Docker without impacting workloads with rootless-kit. Even run buildkit, dind and docker build! See the HOW-TO!&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;GitLab CI is the biggest CI&#x2F;CD system after GitHub Actions and is the preferred solution for self-hosted and enterprise SCM-Systems. While GitHub gives you a fresh, full-blown VM for each job, GitLab has the concept of different &lt;em&gt;Executors&lt;&#x2F;em&gt;. While the GitLab-Runner binary manages the communication and job setup, the executor does the actual work.&lt;&#x2F;p&gt;
&lt;p&gt;While there are &lt;code&gt;Shell&lt;&#x2F;code&gt; and &lt;code&gt;SSH&lt;&#x2F;code&gt; executors, container-based executors are often preferred for flexibility, security and reproducibility. While Docker &lt;em&gt;can&lt;&#x2F;em&gt; improve security, it is not know for it in its default configuration, since everything runs as root.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;attack-surface-docker&quot;&gt;Attack Surface Docker&lt;&#x2F;h2&gt;
&lt;p&gt;By default, Docker is started as root and everyone in the &lt;code&gt;docker&lt;&#x2F;code&gt; user group can communicate with the root-owned socket in &lt;code&gt;&#x2F;var&#x2F;run&#x2F;docker.sock&lt;&#x2F;code&gt;. Since the user-ids inside a container map 1:1 to the user-ids on the host, a simple &lt;code&gt;docker run --it --privileged -v &#x2F;:&#x2F;host debian&lt;&#x2F;code&gt; can overtake the whole system. Even if the user executing it is not root.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ️ Docker and other containers are &lt;strong&gt;NOT&lt;&#x2F;strong&gt; virtualization! All processes run on the same kernel as the host and are only isolated by process namespace and cgroup capabilities.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;This alone is kind of bad. It gets even worse if you run arbitrary, potentially malicious code from unknown systems. A complete host takeover is only one &lt;code&gt;services: [docker:dind]&lt;&#x2F;code&gt; or a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;java.testcontainers.org&#x2F;supported_docker_environment&#x2F;continuous_integration&#x2F;gitlab_ci&#x2F;#example-using-docker-socket&quot;&gt;stupid runner config&lt;&#x2F;a&gt; away.&lt;&#x2F;p&gt;
&lt;p&gt;But how can you run jobs rootless and what about &lt;code&gt;docker build&lt;&#x2F;code&gt; jobs that need dind?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;securing-docker-ci&quot;&gt;Securing Docker &amp;amp; CI&lt;&#x2F;h2&gt;
&lt;p&gt;This can be mitigated by not running Docker as root at all. Rootless Docker used to be a pain but has become surprisingly easy on modern systems.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;&#x2F;strong&gt; The instructions are based on a Debian system but can be adapted to others.&lt;&#x2F;p&gt;
&lt;p&gt;First install Docker according to the official docs:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Install pre-requirements and some extra packages&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; apt&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; update&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; apt&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; curl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ca-certificates&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; curl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; uidmap&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; apparmor&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; lsb-release&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;    slirp4netns&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; dbus-user-session&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; fuse-overlayfs&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; systemd-container&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; fuse-overlayfs&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cifs-utils&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Add the docker apt repo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;m&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 0755&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;d&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;etc&#x2F;apt&#x2F;keyrings&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; curl&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;fsSL&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; https:&#x2F;&#x2F;download.docker.com&#x2F;linux&#x2F;debian&#x2F;gpg&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;o&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;etc&#x2F;apt&#x2F;keyrings&#x2F;docker.asc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; chmod&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; a+r&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;etc&#x2F;apt&#x2F;keyrings&#x2F;docker.asc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;deb [arch=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;dpkg&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-print-architecture&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; signed-by=&#x2F;etc&#x2F;apt&#x2F;keyrings&#x2F;docker.asc] &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;\&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;    https:&#x2F;&#x2F;download.docker.com&#x2F;linux&#x2F;debian &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;\&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;    $(&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;etc&#x2F;os-release&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;VERSION_CODENAME&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; stable&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;    sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; tee&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;etc&#x2F;apt&#x2F;sources.list.d&#x2F;docker.list&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;dev&#x2F;null&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;14&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;15&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Finally install docker&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;16&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; apt&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; update&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;17&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; apt&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; docker-ce&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; docker-ce-cli&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; containerd.io&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;18&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;    docker-buildx-plugin&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; docker-compose-plugin&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; docker-ce-rootless-extras&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now Docker is running as root. Which we don’t want. Disable it via systemd and optionally allow normal users to open ports below 1024.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Disable the root docker service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; systemctl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; restart&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; apparmor.service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; systemctl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; disable&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-now&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; docker.service&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; docker.socket&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;4&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; rm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;var&#x2F;run&#x2F;docker.sock&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;5&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Allow privileged ports for normal users&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;6&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; sysctl&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;w&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; net.ipv4.ip_unprivileged_port_start=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now we need the gitlab-runner binary that communicates with GitLab and our executor. By default, the official install scripts also runs gitlab-runner as root. It should also run as a normal user:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Create gitlab-runner user and install the GitLab Runner&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; useradd&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-create-home&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-shell&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;usr&#x2F;bin&#x2F;bash&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-user-group&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; gitlab-runner&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;curl&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;JOL&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; https:&#x2F;&#x2F;packages.gitlab.com&#x2F;install&#x2F;repositories&#x2F;runner&#x2F;gitlab-runner&#x2F;script.deb.sh&lt;&#x2F;span&gt;&lt;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;4&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; bash&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; script.deb.sh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;5&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; apt&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; gitlab-runner&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;6&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; systemctl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; stop&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; gitlab-runner&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;7&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; systemctl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; disable&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-now&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; gitlab-runner&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We want to run docker rootless, but the users inside of containers are often root or require root. Since we want all our workloads to work with the new setup we use the &lt;em&gt;user-namespace&lt;&#x2F;em&gt; capability of the Linux kernel. This maps the root user form inside a container to an unprivileged user to the host. So even if an attacker manages to break out of a container, he will never have privileges higher than the newly created &lt;code&gt;gitlab-runner&lt;&#x2F;code&gt; user.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Set user-namespace mapping&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; echo&lt;&#x2F;span&gt;&lt;span&gt; $(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;id&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;u&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; gitlab-runner&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;:100000:65536&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; &amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;etc&#x2F;subuid&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; echo&lt;&#x2F;span&gt;&lt;span&gt; $(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;id&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;u&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; gitlab-runner&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;:100000:65536&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; &amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;etc&#x2F;subgid&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;5&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; If you run everything headless without a login shell you need to enable lingering&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;6&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; loginctl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; enable-linger&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can now switch to the new &lt;code&gt;gitlab-runner&lt;&#x2F;code&gt; user and set up docker and the required configs:&lt;&#x2F;p&gt;
&lt;details&gt;
  &lt;summary&gt;&lt;i&gt;gitlab-runner.service&lt;&#x2F;i&gt;&lt;&#x2F;summary&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;toml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; gitlab-runner.service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;Unit&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;Description&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;GitLab Runner&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;ConditionFileIsExecutable&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;usr&#x2F;bin&#x2F;gitlab-runner&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;After&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;network.target&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;Service&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;Restart&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;always&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;RestartSec&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;120&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;StartLimitInterval&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;StartLimitBurst&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;10&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;Environment&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;DOCKER_HOST=unix:&#x2F;&#x2F;&#x2F;run&#x2F;user&#x2F;&amp;lt;&amp;lt;YOUR_GITLAB_RUNNER_USERID&amp;gt;&amp;gt;&#x2F;docker.sock&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;ExecStart&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;usr&#x2F;bin&#x2F;gitlab-runner &lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;run &lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;\&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;14&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;--config &lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;&#x2F;home&#x2F;gitlab-runner&#x2F;gitlab-runner-config.toml &lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;\&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;15&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;--working-directory &lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;&#x2F;home&#x2F;gitlab-runner &lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;\&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;16&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;--service &lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;gitlab-runner &lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;--user &lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;gitlab-runner&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;17&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;18&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;Install&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;19&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;WantedBy&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;default.target&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;&#x2F;details&gt;
&lt;details&gt;
  &lt;summary&gt;&lt;i&gt;gitlab-runner-config.toml&lt;&#x2F;i&gt;&lt;&#x2F;summary&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;toml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; gitlab-runner-config.toml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;concurrent&lt;&#x2F;span&gt;&lt;span&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;check_interval&lt;&#x2F;span&gt;&lt;span&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;shutdown_timeout&lt;&#x2F;span&gt;&lt;span&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;session_server&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  session_timeout&lt;&#x2F;span&gt;&lt;span&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 1800&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span&gt;[[&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;runners&lt;&#x2F;span&gt;&lt;span&gt;]]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  name&lt;&#x2F;span&gt;&lt;span&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Rootless Docker&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  url&lt;&#x2F;span&gt;&lt;span&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;https:&#x2F;&#x2F;gitlab.com&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  id&lt;&#x2F;span&gt;&lt;span&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 1234&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  token&lt;&#x2F;span&gt;&lt;span&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;lt;MY_TOKEN&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  executor&lt;&#x2F;span&gt;&lt;span&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;docker&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;&#x2F;span&gt;&lt;span&gt;  [&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;runners&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;docker&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;14&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    image&lt;&#x2F;span&gt;&lt;span&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;debian&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;15&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    allowed_pull_policies&lt;&#x2F;span&gt;&lt;span&gt; =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;always&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;if-not-present&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;16&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    allowed_privileged_images&lt;&#x2F;span&gt;&lt;span&gt; =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;moby&#x2F;buildkit:*&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;docker:dind&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;17&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    disable_entrypoint_overwrite&lt;&#x2F;span&gt;&lt;span&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;18&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    privileged&lt;&#x2F;span&gt;&lt;span&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;19&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    oom_kill_disable&lt;&#x2F;span&gt;&lt;span&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;20&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    disable_cache&lt;&#x2F;span&gt;&lt;span&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;21&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    volumes&lt;&#x2F;span&gt;&lt;span&gt; =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;cache&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;certs&#x2F;client&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;22&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    shm_size&lt;&#x2F;span&gt;&lt;span&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;23&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    network_mtu&lt;&#x2F;span&gt;&lt;span&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;&#x2F;details&gt;
&lt;p&gt;We now can start rootless docker and configure gitlab-runner to use it:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;i&lt;&#x2F;span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; su&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; gitlab-runner&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;mkdir&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;p&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; .config&#x2F;systemd&#x2F;user&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;.config&#x2F;docker&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Run rootless docker&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;dockerd-rootless-setuptool.sh&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; You can now run docker commands&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage&quot;&gt;export&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; DOCKER_HOST&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;unix&lt;&#x2F;span&gt;&lt;span&gt;:&#x2F;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;run&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;user&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;id&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;u&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;docker&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;sock&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;docker&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; run&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-rm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; hello-world&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Setup GitLab Runner conf and systemd service with the conf above &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Remember to adjust your user-id and set your token&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;vim&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; .config&#x2F;systemd&#x2F;user&#x2F;gitlab-runner.service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;14&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;vim&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; gitlab-runner-config.toml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;15&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;16&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Activate the runner&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;17&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;systemctl&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-user&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; daemon-reload&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;18&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;systemctl&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-user&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; enable&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; gitlab-runner.service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;19&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;systemctl&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-user&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; start&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; gitlab-runner.service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;With the correct token and GitLab server configured you should now see the runner in the GitLab UI.&lt;br &#x2F;&gt;
You now can run any CI-Job with this runner - even dind works!&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;r&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ootless-job&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  t&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ags&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;m&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;y-rootless-runner&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  s&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ervices&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;d&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ocker:dind&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;4&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  s&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;tage&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; t&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;est&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;5&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  s&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;cripts&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;6&lt;&#x2F;span&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; e&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;cho &amp;quot;I am running as $(whoami)&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;what-about-kubernetes&quot;&gt;What about Kubernetes&lt;&#x2F;h2&gt;
&lt;p&gt;What if you use the Kubernetes GitLab-Executor and run buildkit in Kubernetes?&lt;br &#x2F;&gt;
When you run modern Kubernetes with &lt;code&gt;containerd&lt;&#x2F;code&gt; version &lt;code&gt;&amp;gt;=2.x1&lt;&#x2F;code&gt; and Kubernetes &lt;code&gt;&amp;gt;= 1.33.x&lt;&#x2F;code&gt; you can use &lt;code&gt;userNamespace&lt;&#x2F;code&gt; with your pods. It is just one parameter. Just set &lt;code&gt;spec.hostUsers&lt;&#x2F;code&gt; to &lt;code&gt;false&lt;&#x2F;code&gt; in your &lt;code&gt;Pods&lt;&#x2F;code&gt; any thats it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;and-now&quot;&gt;And now?&lt;&#x2F;h2&gt;
&lt;p&gt;This is one measurement to avoid security issues that may overtake your CI runners, but it is by far not the only attack that often used. Supply chain security is a wide and deep topic and the upcoming post will explain how to protect your environment from credential threats and other attacks.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Follow Up: Let&#x27;s talk about anonymous access to Kubernetes</title>
        <published>2025-05-22T00:00:00+00:00</published>
        <updated>2025-05-22T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              hegerdes
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://henrikgerdes.me/blog/2025-05-k8s-annonymus-auth/"/>
        <id>https://henrikgerdes.me/blog/2025-05-k8s-annonymus-auth/</id>
        
        <content type="html" xml:base="https://henrikgerdes.me/blog/2025-05-k8s-annonymus-auth/">&lt;h1 id=&quot;follow-up-let-s-talk-about-anonymous-access-to-kubernetes&quot;&gt;Follow Up: Let’s talk about anonymous access to Kubernetes&lt;&#x2F;h1&gt;
&lt;hr &#x2F;&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;TL;DR:&lt;&#x2F;em&gt;&lt;&#x2F;strong&gt; Kubernetes default anonymous-auth allows unended information exposure, but disabling it was hard. Now you can limit anonymous-auth to specific paths only.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;In 2023 Rory McCune (raesene) wrote a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;raesene.github.io&#x2F;blog&#x2F;2023&#x2F;03&#x2F;18&#x2F;lets-talk-about-anonymous-access-to-Kubernetes&#x2F;&quot;&gt;nice blog post&lt;&#x2F;a&gt; about Kubernetes &lt;code&gt;anonymous-auth&lt;&#x2F;code&gt; flag, which is enabled by default. While security mechanism like RBAC are still applied, certain endpoints in Kubernetes can be accessed without providing any form of authentication - therefore, it is called &lt;code&gt;anonymous-auth&lt;&#x2F;code&gt;.&lt;br &#x2F;&gt;
He raised awareness for this flag and also did a regular &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;raesene.github.io&#x2F;blog&#x2F;2024&#x2F;02&#x2F;17&#x2F;a-final-kubernetes-censys&#x2F;&quot;&gt;Kubernetes Census&lt;&#x2F;a&gt; listing how many Kubernetes API-Servers were publicly accessible and in which version. He was able to gather that data, because the &lt;code&gt;&#x2F;version&lt;&#x2F;code&gt; path in one of the paths that can be accessed without any form of authentication.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;raesene.github.io&#x2F;assets&#x2F;media&#x2F;kubernetes-versions-2024.png&quot; alt=&quot;Graph of public accessible Kubernetes Servers and their version&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Rory McCune suggests to outright disable the anonyms auth flag with &lt;code&gt;--anonymous-auth=false&lt;&#x2F;code&gt; to reduce the  exposed information and the potential attack vector. While it is definitely a smart idea, it is often unpractical since &lt;code&gt;kubeadm&lt;&#x2F;code&gt; needs certain anonymous-auth endpoints in order to join new nodes to a cluster.&lt;br &#x2F;&gt;
In long-lived static clusters where new nodes are rarely added, this would not be a large issue, but the kube-api-server itself uses &lt;code&gt;anonymous-auth&lt;&#x2F;code&gt; endpoints in order to perform health checks on itself. These endpoints may also be used by loadbalancer in order to check it’s targets status.&lt;br &#x2F;&gt;
If these checks failed, due to a &lt;code&gt;401 Unauthorized&lt;&#x2F;code&gt; HTTP Error, the api-server would mark itself (actually it is the kubelet doing the check) as unhealthy and restart itself - over and over again. Making the whole cluster unaccessible.&lt;&#x2F;p&gt;
&lt;p&gt;So setting &lt;code&gt;--anonymous-auth=false&lt;&#x2F;code&gt; often was impractical.&lt;br &#x2F;&gt;
But Kubernetes is a fast-moving platform and has heavily increased security in recent years with features like &lt;code&gt;usernamespaces&lt;&#x2F;code&gt;, &lt;code&gt;appamor&lt;&#x2F;code&gt;, &lt;code&gt;selinux&lt;&#x2F;code&gt; and bound-serviceaccount-tokens. They also introduced the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;kubernetes.io&#x2F;blog&#x2F;2024&#x2F;04&#x2F;25&#x2F;structured-authentication-moves-to-beta&#x2F;&quot;&gt;structured-authentication-config&lt;&#x2F;a&gt; in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;kubernetes&#x2F;enhancements&#x2F;blob&#x2F;master&#x2F;keps%2Fsig-auth%2F4633-anonymous-auth-configurable-endpoints%2FREADME.md&quot;&gt;KEP-4633&lt;&#x2F;a&gt;. A config file that allows users to declaratively configure OIDC-Auth (the only reasonable auth option for user access in larger clusters) &lt;strong&gt;AND&lt;&#x2F;strong&gt; a fine-grained anonymous auth configuration.&lt;&#x2F;p&gt;
&lt;p&gt;It took me a few tries but with the following authentication-config you can drastically reduce the information exposure of your cluster and still be able to join new nodes via &lt;code&gt;kubeadm&lt;&#x2F;code&gt; and check the cluster health.&lt;br &#x2F;&gt;
It also prevents misconfiguration with unintended RBAC bindings to the &lt;code&gt;unauthenticated&lt;&#x2F;code&gt; group.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;piVersion&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; a&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;piserver.config.k8s.io&#x2F;v1beta1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;k&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ind&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; A&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;uthenticationConfiguration&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;nonymous&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  e&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;nabled&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  c&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;onditions&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;    #&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; kubeadm needs to read the discovery info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; p&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ath&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;api&#x2F;v1&#x2F;namespaces&#x2F;kube-public&#x2F;configmaps&#x2F;cluster-info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;    #&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; for liveness and readiness checks:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; p&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ath&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;healthz&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; p&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ath&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;readyz&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; p&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ath&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;livez&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;j&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;wt&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;  #&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Optional OIDC config&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This only gives access to the health&#x2F;status endpoints and to one specific configmap. The cluster-version and other information are not accessible without authentication.&lt;br &#x2F;&gt;
The health endpoints only return &lt;code&gt;200 OK&lt;&#x2F;code&gt; and the configmap contains the IDs of bootstrap-token and the clusters CA certificate, which is accessible anyway.&lt;&#x2F;p&gt;
&lt;p&gt;Thats it! Easy way to protect your clusters a little more without sacrificing functionality.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;P.S. If someone knows how to write CEL expressions that can validate the extra claims of a user idtoken - write me!&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Level up your Ansible Code - Creating Golden Images</title>
        <published>2025-04-20T00:00:00+00:00</published>
        <updated>2025-04-20T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              hegerdes
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://henrikgerdes.me/blog/2025-04-ansible-packer/"/>
        <id>https://henrikgerdes.me/blog/2025-04-ansible-packer/</id>
        
        <content type="html" xml:base="https://henrikgerdes.me/blog/2025-04-ansible-packer/">&lt;h1 id=&quot;level-up-your-ansible-code-creating-golden-images&quot;&gt;Level up your Ansible Code - Creating Golden Images&lt;&#x2F;h1&gt;
&lt;hr &#x2F;&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;TL;DR:&lt;&#x2F;em&gt;&lt;&#x2F;strong&gt; The combination of Ansible and Packer can be a terrific solution to improve provisioning time, increase reliability and reduce stress on other infrastructure. Run Packer once with your existing Ansible-Config and reuse the resulting image a 1000 times.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;So the story usually looks like this: You became tired of doing the same web-server base configuration over and over again. Sometimes it didn’t work because you misspelled a parameter or copy-pasted the wrong command. But then someone mentioned Ansible. A tool that can run the same actions over and over again with the desired same output (when done right - which I have seen not that often). It can be lunched against 1000s of machines. It sounded great since you wanted to have more free time and are not afraid to automate yourself out of your job (don’t worry, will not happen - you will only level up).&lt;br &#x2F;&gt;
So you started to implement your tasks as Ansible roles and tasks. It took a while to get right but now you have made yourself a name by always delivering setups in such a quick time with rock solid and consistent quality. Great, enjoy your life, right?&lt;&#x2F;p&gt;
&lt;p&gt;Yeah, maybe. But you seek even better outputs, even more “free” time, got a new requirement, or just want a good reason for your next raise? I don’t really care, but this is where this canticle comes in handy!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;my-ansible-setup&quot;&gt;My Ansible setup&lt;&#x2F;h2&gt;
&lt;p&gt;My story actually looked quite similar. I use Ansible to set up vanilla k8s cluster on systems. I have a &lt;code&gt;common&lt;&#x2F;code&gt; role for all nodes and a &lt;code&gt;cp-bootstrap&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;worker-join&lt;&#x2F;code&gt; role. Setting up a Debian based cluster, with a lot of extra conf for extra container-runtimes and newer kernels it takes about 15min to fully bootstrap a cluster on the Hetzner cloud. That is &lt;em&gt;so slow&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-annoying-stuff-in-ansible&quot;&gt;The annoying stuff in Ansible&lt;&#x2F;h2&gt;
&lt;p&gt;Manly because Ansible is slow. Even with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.ansible.com&#x2F;ansible&#x2F;latest&#x2F;reference_appendices&#x2F;config.html#ansible-pipelining&quot;&gt;connection-pipelining&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.ansible.com&#x2F;ansible&#x2F;latest&#x2F;reference_appendices&#x2F;config.html#default-forks&quot;&gt;multiple forks&lt;&#x2F;a&gt; and other tweaks. It gets even worse if the connection goes over VPS,JumpHosts or some Proxies. But not only Ansible is slow. Installing packages is slow, setting kernel parameters and downloading stuff is slow. And sometimes, not often, your playbooks &lt;strong&gt;FAIL&lt;&#x2F;strong&gt;. Because a connection timed out, you got rate limited or a package version changed.&lt;&#x2F;p&gt;
&lt;p&gt;When this happens, your playbooks are not idempotent, let alone reproducible. It mostly works out, but you can not guarantee that the state will always be exactly the same when you run your playbook over and over again. I get it, reproducibility is hard, but we can make your life’s a little easier when we don’t have to run Ansible that often. And even save more time, because again, Ansible is &lt;em&gt;slow&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;introducing-packer-golden-images&quot;&gt;Introducing Packer &amp;amp; Golden Images&lt;&#x2F;h2&gt;
&lt;p&gt;Packer is a packaging software from HashiCorp. It uses plugins to integrate with various providers, such as AWS, Azure, GCE but also onPrem solutions like VMware, Proxmox and good old QEMU. It uses HashiCorp’s Configuration Language (HCL), just like Terraform.&lt;br &#x2F;&gt;
In Packer you usually have one or more &lt;code&gt;source&lt;&#x2F;code&gt; resources with one or more &lt;code&gt;build&lt;&#x2F;code&gt; steps. Packers plugin ecosystem makes it really versatile for your build configuration. You can create AMIs on AWS, but also Docker-Images, ISOs and RAW disk images. Reusability is provided by HCL by the usage of variables, inputs and basic logic functions (JSON-Encode, reverse, map, etc.) build into HCL.&lt;br &#x2F;&gt;
With Packer you can archive real reproducibility. You create a working image &lt;strong&gt;once&lt;&#x2F;strong&gt; and reuse it a 1000 times. All machines created from this image will have the same, known good base configuration with the same packages installed. Perfect for providing ready-to-go hardened servers. The resulting images are called &lt;em&gt;golden-images&lt;&#x2F;em&gt;.&lt;br &#x2F;&gt;
And now we will use our existing configuration automation code for Ansible with the Packers plugin system to cut down provisioning time for our k8s clusters.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;merging-packer-ansible&quot;&gt;Merging Packer &amp;amp; Ansible&lt;&#x2F;h2&gt;
&lt;p&gt;Let’s work through reusing my existing Ansible playbooks to create golden images by using an concrete example. I want to cut down provisioning time for k8s clusters from 15 minutes to 5 minutes.&lt;br &#x2F;&gt;
For this I will use golden images created by Packer with the the Hetzner &lt;code&gt;hcloud&lt;&#x2F;code&gt; Packer plugin. I need a source and some basic inputs to make it configurable:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;hcl&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; hcloud.pkr.hcl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;packer&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;  required_plugins&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    hcloud&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;      source&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;  =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;github.com&#x2F;hetznercloud&#x2F;hcloud&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;      version&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;gt;= 1.6.0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;variable&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-enummember&quot;&gt; &amp;quot;base_image&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  type&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;    =&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  default&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;debian-12&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;14&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;15&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;variable&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-enummember&quot;&gt; &amp;quot;k8s_version&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;16&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  type&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;    =&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;17&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  default&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;1.32.3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;18&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;19&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;variable&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-enummember&quot;&gt; &amp;quot;user_data_path&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;20&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  type&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;    =&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;21&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  default&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;cloud-init.yml&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;22&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;23&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;24&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;locals&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;25&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  output_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;debian-12-k8s-v&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;var&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;k8s_version&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;26&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;27&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;28&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;source&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-enummember&quot;&gt; &amp;quot;hcloud&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-enummember&quot;&gt; &amp;quot;k8s-amd64&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;29&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  image&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;         =&lt;&#x2F;span&gt;&lt;span&gt; var&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;base_image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;30&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  location&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;      =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;nbg1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;31&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  server_type&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;   =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;cx22&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;32&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  ssh_keys&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;      =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;33&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  user_data&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;     =&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; file&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;var&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;user_data_path&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;34&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  ssh_username&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;  =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;root&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;35&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  snapshot_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;local&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;output_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;-amd64&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;36&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  snapshot_labels&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;37&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    type&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;    =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;infra&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;38&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    base&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;    =&lt;&#x2F;span&gt;&lt;span&gt; var.base_image,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;39&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    version&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;var&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;k8s_version&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;40&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;    =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;local&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;output_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;-amd64&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;41&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    arch&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;    =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;amd64&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;42&lt;&#x2F;span&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;43&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;44&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;source&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-enummember&quot;&gt; &amp;quot;hcloud&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-enummember&quot;&gt; &amp;quot;k8s-arm64&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;45&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  image&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;         =&lt;&#x2F;span&gt;&lt;span&gt; var&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;base_image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;46&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  location&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;      =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;nbg1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;47&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  server_type&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;   =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;cax11&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;48&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  ssh_keys&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;      =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;49&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  user_data&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;     =&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; file&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;var&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;user_data_path&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;50&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  ssh_username&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;  =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;root&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;51&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  snapshot_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;local&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;output_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;-arm64&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;52&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  snapshot_labels&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;53&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    type&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;    =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;infra&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;54&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    base&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;    =&lt;&#x2F;span&gt;&lt;span&gt; var.base_image,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;55&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    version&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;var&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;k8s_version&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;56&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;    =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;local&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;output_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;-arm64&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;57&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    arch&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;    =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;arm64&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;58&lt;&#x2F;span&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;59&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This allows me to create images (or snapshots for Hetzner) for debian based imaged on amd64 and arm64. The image name will be set based on the input parameters.&lt;&#x2F;p&gt;
&lt;p&gt;Now we need a build step. While Packer has a dedicated Ansible plugin, I choose to not use it, since it did not meet my requirements for handling restarts and other parameters. Instead I choose to use the build-in &lt;code&gt;shell&lt;&#x2F;code&gt; provisioner which just runs some inline commands that are a predefined in a shell script:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;hcl&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;build&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  sources&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;source.hcloud.k8s-amd64&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;source.hcloud.k8s-arm64&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;  provisioner&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-enummember&quot;&gt; &amp;quot;shell&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    expect_disconnect&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    env&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;      k8s_version&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;var&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;k8s_version&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    scripts&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ansible-setup.sh&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;span&gt;    ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;  provisioner&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-enummember&quot;&gt; &amp;quot;shell&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;14&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    pause_before&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;30s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;15&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    max_retries&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;16&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    env&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;17&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;      k8s_version&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;var&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;k8s_version&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;18&lt;&#x2F;span&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;19&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    scripts&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;20&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ansible-setup.sh&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;21&lt;&#x2F;span&gt;&lt;span&gt;    ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;22&lt;&#x2F;span&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;23&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This runs the same shell script two times, which is exactly what I need because my IaC code includes a restart to swap the current kernel version. All what my shell script really does is to wait for &lt;code&gt;cloud-init&lt;&#x2F;code&gt; to finish, clone my Ansible git repo and run it with a bunch of predefined vars. Finally it performs some cleanups and resets cloud-init:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#!&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt;&#x2F;bin&#x2F;bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;set&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;e&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;o&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; pipefail&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Waiting for cloud-init to finish...&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;cloud-init&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; status&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-wait&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; setup requirements&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Installing packages...&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;apt-get&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; update&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;qq&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;apt-get&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;qq&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-yes&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-no-install-recommends&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; git&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; python3-pip&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;pip3&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-user&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-break-system-packages&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-no-warn-script-location&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-no-cache-dir&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ansible&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; jmespath&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;PATH&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;l&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;o&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;l&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;b&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;PATH&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;14&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; -d&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;playbooks&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; ]&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;15&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;  git&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; clone&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-depth&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; https:&#x2F;&#x2F;github.com&#x2F;hegerdes&#x2F;ansible-playbooks.git&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; playbooks&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;16&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;17&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;18&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; setup ansible play&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;19&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Running playbook...&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;20&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;cd&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; playbooks&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;21&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Vars:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;22&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;cat&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; &amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;EOF&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;hostvars.yaml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;23&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;k8s_cri: crun&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;24&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;k8s_containerd_variant: github&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;25&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;k8s_ensure_min_kernel_version: 6.12.*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;26&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;EOF&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;27&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;28&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;printenv&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; sed&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;s&#x2F;=&#x2F;\: &#x2F;g&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; k8s&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; &amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;hostvars.yaml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;29&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;cat&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; hostvars.yaml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;30&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;31&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;cat&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; &amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;EOF&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;pb_k8s_local.yml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;32&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;- name: K8s-ClusterPrep&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;33&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;  hosts: localhost&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;34&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;  become: true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;35&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;  gather_facts: true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;36&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;  roles:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;37&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;    - k8s&#x2F;common&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;38&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;EOF&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;39&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;40&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Run playbook&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;41&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;ansible-playbook&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; pb_k8s_local.yml&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-extra-vars&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;@hostvars.yaml&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;v&lt;&#x2F;span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; cd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I just run my existing playbooks locally on the target server to archive the desired configuration. While the reproducibility is provided by the resulting image, we should still try to make our playbooks idempotent, so we can run them over and over again. It should not perform any changes when the desired state is already reached.&lt;br &#x2F;&gt;
With this and some additional cleanup code to minimize image size, I get ready to use golden k8s images, which I can use to quickly spin up a new cluster or use as an autoscaling nodes. Every dependency I need is already in that image. Every kernel parameter is already tuned to my desire. I can just use these, and be sure that they will always act the same, since these are truly reproducible.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;img&#x2F;blog&#x2F;hetzner-debian-packer.webp&quot; alt=&quot;Screenshot of the Hetzner image Snapshot page, showing two Debian images for amd64 and arm64, each with a size of less then 500MB&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The creation of these two images took about 12 minutes. Thats 12 minutes I have to spent once (for every k8s version) and I now save for every deployment. When I now want to create a new k8s cluster, I can just uses these images and be sure they are already configured to my desire. Bootstrapping a new cluster with these images takes actually less then 5 minutes. It saves time and I am much more constable, that my setups are always acting the same, because they are reproducible.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ️ You can find the complete code on my GitHub in my &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;hegerdes&#x2F;GitOps&#x2F;tree&#x2F;main&#x2F;infra&#x2F;hcloud-packer-debian&quot;&gt;GitOps&lt;&#x2F;a&gt; repo.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;Ansible, Packer and even Terraform are great tools that work together and ma a real dream team when put together. Thats one of the reason RedHat bought HashiCorp and now works on putting these even closer together. These tools are &lt;strong&gt;not&lt;&#x2F;strong&gt; competitors!&lt;br &#x2F;&gt;
When you want to save even more time, you can easily glue your Ansible code together with tools like Packer, to create truly reproducible deployments.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Understanding and using modern day authentication frameworks to improve security, productivity and user acceptance</title>
        <published>2025-02-12T00:00:00+00:00</published>
        <updated>2025-02-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              hegerdes
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://henrikgerdes.me/blog/2025-02-ares-oauth2/"/>
        <id>https://henrikgerdes.me/blog/2025-02-ares-oauth2/</id>
        
        <content type="html" xml:base="https://henrikgerdes.me/blog/2025-02-ares-oauth2/">&lt;h1 id=&quot;understanding-modern-day-authentication-with-oauth2-and-oidc&quot;&gt;Understanding modern day Authentication with OAuth2 and OIDC&lt;&#x2F;h1&gt;
&lt;hr &#x2F;&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;ℹ️&lt;&#x2F;em&gt;&lt;&#x2F;strong&gt; This post was written in the context of my employment at ARES. While it does not promote any software or solutions from which ARES or I will benefit off, it is written in a more cooperate tone.&lt;br &#x2F;&gt;
The german version can be found at my company’s website.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Authentication is hard. Especially when the traditional concept of a trusted network becomes increasingly outdated with remote employees and the security aware concept of Zero Trust. Nowadays every entity composes a potential threat. Implementing authentication into every application (even into internal ones) becomes a significant overhead, consumes valuable development time, and drives up cost. We would like to give a top-level overview of modern authentication methods, where these can be used, how they can improve the security of offered services and how they can even help to improve the usability of services.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-need-and-pains-of-authentication&quot;&gt;The need and pains of authentication&lt;&#x2F;h2&gt;
&lt;p&gt;Authentication is needed everywhere. Today there are distinct accounts for every individual which hold personal information. With data becoming more and more valuable and sensitive, it’s a company’s duty to protect user data from unauthorized access. Failing this can result in a massive lost in trust and reputation while also eventually result in legal consequences. This also includes HR information and logged working hours of employees. Managing these information becomes increasingly difficult with the number of different applications deployed. Keeping employee’s data (such as address, accounting, and social information) safe, updated and in sync between multiple applications pose a considerable challenge, due to the duplicated data handling nature of these systems.&lt;&#x2F;p&gt;
&lt;p&gt;When offering services for end users the same problems occur. Users nowadays have lots of different accounts. When there is a change in their life, like moving to a new city, changing banks or an update in their relationship status, they are not likely to update all their information on every platform they use. Inaccurate data lowers the quality of the accumulated information and my also introduced cost due to an incoming service ticked caused by a failed bank transaction.
In a well disingenuous system, there would be a central location where each and every app that needs user data can request them or even enriches them by adding additional information. A 3rd party application could request access to a user’s posts and contacts, do analysis on them, provide users insights about their contents, and offer recommendations for expending their network.
There is an increasing awareness to the value of personal data and some users might not be willing to provide these information to any app. When users are promoted with lengthy registration process, for a new app, they are much more likely to discard dealing with the app compared to a quick an easy setup where they can log in with their existing accounts, like a Google account. The lack of an uncomplicated, quick sign-up process could lead to a significant reduction in the user adoption rate, which could, depending on the business model, reduce the generated revenue stream.&lt;br &#x2F;&gt;
Beside the logical and business aspects of user authentication there is also the technical aspect.&lt;&#x2F;p&gt;
&lt;p&gt;As mentioned at the beginning, authentication is hard. Building it from scratch is only recommended in the rarest cases and when having skilled and experienced developers. They have to consider hashing, salting and storing credentials in a secure manner. There a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;haveibeenpwned.com&#x2F;PwnedWebsites&quot;&gt;plenty of news&lt;&#x2F;a&gt; where companies, even large and reputable companies, faced data breaches, exposing credentials and sensitive personal information about their users. Developers can get 99% of the authentication process right but render their whole implementation vulnerable by making one mistake. Even when authentication is handled by an external library, developers have to consider things like security questions, password rests and 2 Factor Authentication (2FA) with services like One-Time-Passwords (OTP) and hardware tokens. They also have to constantly update and review the used library in order fix disclosed vulnerabilities and to prevent supply chain attacks. Complicating things even further, the combination of username and password is not considered best practice anymore, due to cumbersome nature and susceptibility to being stolen. That’s why companies like Google are researching and pushing new authentication methods, like passkeys, and want to get rid of the traditional password.&lt;&#x2F;p&gt;
&lt;p&gt;Considering and implementing all these aspects while designing and implementing an app introduces a considerable amount of business and application logic, especially if one decides to presume the path of a microservice architecture service. The good thing is that there are a lot of people facing this problem and that there are existing solutions to streamline, enhance and simplify the authentication process for every entity involved. The most promising and widespread approach are the OAuth2 and OIDC approach.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;introduction-to-oidc-and-oauth2&quot;&gt;Introduction to OIDC and OAuth2&lt;&#x2F;h2&gt;
&lt;p&gt;Both OAuth2 and OIDC provide concepts of how one can grant controlled access to specific resources. The OIDC specification restrictions its scope to only authentication, meaning it will only guarantee the legitimacy of the user through an external identity provider. Access control for limiting theses authenticated users to specific subset of resources is explicitly not part of OIDC and must be handled by the apps logic. This is helpful if there is no need for fine grained access control, if just the membership to the organisation must be assessed or if the app already has a system for fine grained access controls implemented. A prominent example is Kubernetes. The users authenticity can be provided via OIDC the access control is handled by Kubernetes RBAC system.&lt;&#x2F;p&gt;
&lt;p&gt;The OAuth2 authentication spec is mainly described in the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc6749&quot;&gt;rfc6749&lt;&#x2F;a&gt; and covers both authentication and authorisation. Therefore it is quite broad and even has some sub specification and several extensions. For simplicity, this article will only focus on the main aspects of this spec needed for understanding and implementing it.
The key concept of OAuth2 is that it provides an authorization framework where the authentication is handled by an external provider, often called the authorization server, where the client (mostly an app or the browser) can request access to information of the resource owner (user) on behalf of that user to access protected resources.&lt;&#x2F;p&gt;
&lt;p&gt;The important aspect in OIDC and OAuth2 is, that the user does not log himself in on the main app or website, but is instead redirected to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;List_of_OAuth_providers&quot;&gt;one of the many existing authorization provides&lt;&#x2F;a&gt; like Google, Microsoft or Facebook. While logging in, the user can see the type of information that the client wants to access (called scope) and can either approve or decline them. By design the client and any external resource never gets to access the user’s credentials and the entire authentication logic is handled by the authorization server. So there is no need to store passwords or implement passwords resets and 2FA yourself.&lt;&#x2F;p&gt;
&lt;p&gt;The OAuth2 spec offers different authentication flows, called “grants”, designed for different use cases. The most common flows, and the ones covered in this article, are the &lt;em&gt;Authorization Code Flow&lt;&#x2F;em&gt; and the &lt;em&gt;Client Credentials Flow&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The visualization below shows the &lt;em&gt;Authorization Code Flow&lt;&#x2F;em&gt;, which is the grant most used for interactive user Authentication. When the user visits a company owned Login-Page he can choose to &lt;em&gt;Login with &amp;lt;My-Auth-Provider&amp;gt;&lt;&#x2F;em&gt;. This button takes the user to the Login-Page of that provider where he can login and give consent to the requested information. On confirmation, the user is redirected back to the original site with an Authorization-Code embedded in the URL. Now the company app can use that Authorization-Code, together with other configuration parameters to request an access and refresh token from the Auth-Provider. Using that access token, the app&#x2F;website can request information about that user or perform actions on behalf of that user, without ever knowing the user’s password. The allowed actions are limited to the degree that the user has agreed to in the beginning. The access token has typically has a very short lifespan and regularly expires. New access tokens can be seamlessly requested via form the authorisation server. This significantly reduces the risk of leaked or stolen credentials while also allowing to easily revoke a users-session.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;img&#x2F;blog&#x2F;oauth_access_token_flow.jpeg&quot; alt=&quot;UML Flow Chart for access token grant&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Even if the theoretical procedures seem complex at first glance, the implementation is relative straightforward. In addition, this setup saves all the complexity required for a user registration process, password storage and reset, mail verification, 2-factor authentication, and maintenance. The app&#x2F;website does not need to store any information about the user, since it can always request up-to-date information. So it does not need to worry that the address may be outdated. Due to the short lifespan of each access token (default is 2h), the users information security is also improved as the risk of session hijacking is significantly reduced. Only the original app can request a new access token with its configuration and the refresh token.&lt;&#x2F;p&gt;
&lt;p&gt;The second grant mentioned is the &lt;em&gt;Client Credentials Flow&lt;&#x2F;em&gt;. It is designed for use cases where no user interaction is needed and where both, client and resource server, is owned by the same entity. This method allows two application to communicate safely with each other, while also providing the advantages of short lived tokens and scoped access. This concept can be extended even further. With federation one can enable a trust relationship between two systems. When this is used there is no need for any credentials anymore. CI systems are ideal candidates for such a setup since it allows secure and low maintenance communication between systems like GitHub Actions to AWS or Azure.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;whats-in-for-me&quot;&gt;Whats in for me?&lt;&#x2F;h2&gt;
&lt;p&gt;The potential savings that can be achieved through OAuth2, especially in enterprises, are enormous. For example, using OAuth2 in conjunction with Microsoft 365 would allow a company to secure and manage all of its systems with one central user account, such as the existing Exchange&#x2F;Microsoft account. Users would have significantly fewer passwords and techniques such as Single Sign On (SSO) could significantly reduce the average number of 12 daily logins (found out by &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.security-insider.de&#x2F;passwortloser-login-auch-in-deutschland-auf-dem-vormarsch-a-faaee5fb1b831f068de1982c10a656d6&#x2F;&quot;&gt;security-insider.de&lt;&#x2F;a&gt;) and the associated time required. Workers will be more productive and less annoyed by re typing passwords all day.&lt;&#x2F;p&gt;
&lt;p&gt;Upon termination of employment, the responsible parties only have to block one account instead of going through long lists of accesses and deleting them with the high risk of overlooking something. The onboarding of new employees is also significantly shortened because only one account needs to be created and the new employee can then access all the necessary systems.
Because of these advantages, the reduced effort required for authentication, the additional security and the convenience for users, the use of OAuth2 continues to grow. Many applications and services such as Jira, GitLab and others already offer built-in support for OAuth2. Even if applications do not support this, such as internal wikis or applications that do not inherently provide authentication, this can be implemented with little effort.&lt;&#x2F;p&gt;
&lt;p&gt;The idea to offload the entire user management might sound a little scary at fist, specially if it is an external identity provider, but since OAuth2 and OIDC are well defined public specifications with a broad adoption there is no risk of a vendor lock-in. If a Microsoft or Google controlled identity store ist not an option, there is a wide range of alternative solution to implement an identity provider. Some of them fully open-source and self-hostable. Well established solutions are KeyCloak and DEX.&lt;&#x2F;p&gt;
&lt;p&gt;Especially in the cloud environment, with many microservices, where Zero Trust is becoming more and more standard, a Kubernetes application can be made OAuth2 ready with just one manifest and thus offer its employees and customers faster, more secure, and better services.&lt;&#x2F;p&gt;
&lt;p&gt;The whole idea of OAuth2 is to push the &lt;strong&gt;One Identity&lt;&#x2F;strong&gt; concept for each user. There should be no additional accounts, the user has a central authority with secure, reliable information and this identity will be authorized to access the necessary resources. This identity concept is provided by the OpenIdConnect (OIDC) standard, which is part of the OAuth2 specification.&lt;&#x2F;p&gt;
&lt;p&gt;If your company struggles with authentication and employees are frustrated by the current status reach out to one of our experts at ARES Consulting GmbH or contact info@ares-consulting.de to make your application ready and secure with the future of authorization. We simplify authorization!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;developer.okta.com&#x2F;assets-jekyll&#x2F;blog&#x2F;illustrated-guide-to-oauth-and-oidc&#x2F;authorize-tpotd-contacts-9f4dca35e4c91b5d808f65f64bb14cc40e7c701742f4b764c5baa8acfeb59020.jpg&quot; alt=&quot;OAuth2 Comic&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>What is new in containerd 2.0</title>
        <published>2024-11-10T00:00:00+00:00</published>
        <updated>2024-11-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              hegerdes
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://henrikgerdes.me/blog/2024-11-containerd-2/"/>
        <id>https://henrikgerdes.me/blog/2024-11-containerd-2/</id>
        
        <content type="html" xml:base="https://henrikgerdes.me/blog/2024-11-containerd-2/">&lt;h1 id=&quot;what-is-new-in-containerd-2-0&quot;&gt;What is new in containerd 2.0?&lt;&#x2F;h1&gt;
&lt;p&gt;Containerd recently released its first major update since its 1.0 release form over 7 years ago. It provides some exciting new features, improves compatibility, gets rid of some deprecated functions and may even improve performance.&lt;br &#x2F;&gt;
This post aims to give a high level overview of the changes made in containerd and takes a closer look into the &lt;em&gt;user-namespaces&lt;&#x2F;em&gt; functionality.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;ℹ️&lt;&#x2F;em&gt;&lt;&#x2F;strong&gt; Containerd is a Container-Runtime-Interface (CRI) compliant implementation that can manage the entire lifecycle of an container. It is used in Docker and most Kubernetes flavors (including AKS&#x2F;EKS&#x2F;GKE) to manage all container processes.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;how-do-i-upgrade&quot;&gt;How do I upgrade&lt;&#x2F;h2&gt;
&lt;p&gt;The containerd project is committed to keep the upgrade path as simple as possible. Most settings should work the same as containerd &lt;code&gt;v1.7x&lt;&#x2F;code&gt;. When you use the deprecated &lt;code&gt;aufs&lt;&#x2F;code&gt; snapshotter (most likely you are not) you have to switch to a new snapshotter. Another change is that you have to explcitly re-enable the image schema V1 if you still depend on those.&lt;br &#x2F;&gt;
Beside that there should be little changes that require attention. To upgrade to the newer config version &lt;code&gt;v3&lt;&#x2F;code&gt; you can just run &lt;code&gt;containerd config migrate&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;new-functions&quot;&gt;New functions&lt;&#x2F;h2&gt;
&lt;p&gt;The &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;containerd&#x2F;containerd&#x2F;releases&#x2F;tag&#x2F;v2.0.0&quot;&gt;GitHub Release&lt;&#x2F;a&gt; from containerd 2.0 gives a first overview of the changes, but does not explain the implications of each change. I piked a few highlight and will cover them in more detail:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;User-Namespaces&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
This is a big one for me and will increase security of containerized workloads by a lot!&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Why is it important?&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;If you run a container today you can set the &lt;code&gt;UID&lt;&#x2F;code&gt;, the user UserID as which the main container process runs. Every single security guide regarding containers recommends to run container processes as none-root and as a unprivileged user, which IDs start at the 1000 range.&lt;br &#x2F;&gt;
For most applications this is not an issue, but there are certain processes that require root. If processes need to install packages they require root, CI-Jobs often require root and it is really hard to run an &lt;code&gt;ssh&lt;&#x2F;code&gt; server as none-root. Even one of the most used containers, &lt;code&gt;nginx&lt;&#x2F;code&gt;, start as root and then drop their permissions to a none privileged user. The problem with root is that if an attacker manages to escape the container sandbox he is automatically root on the host system since UserIDs in a container map one to one to the ones on the host.&lt;br &#x2F;&gt;
User-Namespaces changes this. If you ran a container with the user-namespaces feature enabled a container can run as root, but has a different, unprivileged UserID on the host. This is a great feature that drastically improves security without a performance penalty.&lt;br &#x2F;&gt;
The 2.0 release of containerd supports user-namespaces by default but you may still have to enable it in your kernel via &lt;code&gt;user.max_user_namespaces=1048576&lt;&#x2F;code&gt; (Suggested values from CoreOS for CRI-O).&lt;br &#x2F;&gt;
While the feature is now shipped with containerd, it is still in beta for Kubernetes. Your can enable it by setting the &lt;code&gt;featureGate&lt;&#x2F;code&gt; &lt;code&gt;UserNamespacesSupport&lt;&#x2F;code&gt; to &lt;code&gt;true&lt;&#x2F;code&gt; on the api-server.&lt;br &#x2F;&gt;
To start a pod which uses user-namespaces set the &lt;code&gt;hostUsers&lt;&#x2F;code&gt; parameter to &lt;code&gt;false&lt;&#x2F;code&gt;. Thats all you need to do. This can also be enforced via admission controllers.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;piVersion&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; v&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;k&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ind&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; P&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;od&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;m&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;etadata&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  l&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;abels&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;    r&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;un&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; u&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ser-namespaces-demo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  n&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ame&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; u&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ser-namespaces-demo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;s&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;pec&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;  #&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Enables user-namespaces&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  h&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ostUsers&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  c&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ontainers&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;span&gt;  -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; i&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;mage&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; n&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ginx&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;    n&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ame&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; u&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ser-namespaces-demo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;    r&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;esources&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Intel ISA-L’s igzip&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
This is a nice addition which may increase your container startup times by a few hundred milliseconds. But how?&lt;br &#x2F;&gt;
Container images are just a bunch of gziped archives layered ontop of each other. A manifest specifies which archives belong to which image. When an image is pulled it gets transferred via HTTP over the network and has to be extracted and decompressed. Most of the time this is done via &lt;code&gt;gzip&lt;&#x2F;code&gt;.&lt;br &#x2F;&gt;
But &lt;code&gt;gzip&lt;&#x2F;code&gt; is single-threaded and does not use the full potential of modern processor. To overcome this there is also a multithreaded implementation of &lt;code&gt;gzip&lt;&#x2F;code&gt; called &lt;code&gt;pigz&lt;&#x2F;code&gt;. While &lt;code&gt;pigz&lt;&#x2F;code&gt; is faster then the default variant, &lt;code&gt;igzip&lt;&#x2F;code&gt; is even more performant. Acording to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;simonis&#x2F;zlib-bench&#x2F;blob&#x2F;master&#x2F;Results.md&quot;&gt;benchmark by simonis&lt;&#x2F;a&gt; &lt;code&gt;igzip&lt;&#x2F;code&gt; is twice as fas as &lt;code&gt;gzip&lt;&#x2F;code&gt;.&lt;br &#x2F;&gt;
If you want to profit from this improvement just install &lt;code&gt;igzip&lt;&#x2F;code&gt; (debian package is called &lt;code&gt;isal&lt;&#x2F;code&gt;), containerd automatically check which version is installed on the system and picks the most preformat one.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Container Checkpoints&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
This is more of a debug function, but with containerd 2.0 you now can freeze an entire container at is current state, including all memory and running processes, and export it. The container now can be restored or further inspected. You can read more about this on the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;criu.org&#x2F;Main_Page&quot;&gt;criu-wiki&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Notable mentions&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The config format version changed to v3. You can migrate it with &lt;code&gt;containerd config migrate&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Containerd now allows container processes to bind to privileged ports by default.&lt;&#x2F;li&gt;
&lt;li&gt;Enables the Container-Device-Interface (CDI) by default&lt;&#x2F;li&gt;
&lt;li&gt;Deprecated &lt;code&gt;aufs&lt;&#x2F;code&gt; snapshotter was deleted&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Making OnPrem Kubernetes feel like AKS&#x2F;EKS&#x2F;GKE</title>
        <published>2024-10-28T00:00:00+00:00</published>
        <updated>2024-10-28T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              hegerdes
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://henrikgerdes.me/blog/2024-10-kubelet-credential-provider/"/>
        <id>https://henrikgerdes.me/blog/2024-10-kubelet-credential-provider/</id>
        
        <content type="html" xml:base="https://henrikgerdes.me/blog/2024-10-kubelet-credential-provider/">&lt;h1 id=&quot;improving-onprem-kubernetes-making-it-feel-like-managed-k8s&quot;&gt;Improving OnPrem Kubernetes &amp;amp; making it feel like managed k8s&lt;&#x2F;h1&gt;
&lt;p&gt;Managed Kubernetes services like AKS, EKS or GKE are awesome. The hyperscaler’s take away so many annoying and difficult tasks. When you use a managed Kubernetes offering, you don’t have to deal with the controlplane, no etcd backups and provisioning of new nodes is fast and painless.&lt;br &#x2F;&gt;
A very nice feature of these managed Kubernetes services is that you can just use the container images from your hyperscaler’s container registries &lt;strong&gt;without&lt;&#x2F;strong&gt; having to create a &lt;code&gt;image-pull-secret&lt;&#x2F;code&gt; in every namespace and deployment. Not having to deal with this saves hours of mindless work and saves you from stupid errors that nobody wants to deal with. But how do the hyperscaler’s do that? See, AWS, Azure and Google also just cook with water, it’s no magic. Read on how you can make your OnPrem feel a little more like &lt;em&gt;your-generic-hyperscaler&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-kubelet-credential-provider-api&quot;&gt;The kubelet-credential-provider-api&lt;&#x2F;h2&gt;
&lt;p&gt;What is the kubelet-credential-provider-api?&lt;br &#x2F;&gt;
It is a very small interface where the kubelet (the agent that runs on every kubernetes node) invokes a small program and passes a well-defined &lt;code&gt;CredentialProviderRequest&lt;&#x2F;code&gt; to it. The program is then expected to respond with a &lt;code&gt;CredentialProviderResponse&lt;&#x2F;code&gt;. This response contains the registry credentials which the kubelet then passes to the container-runtime-interface (CRI) which pulls the desired image from the target registry. This way, users can create deployments with images from password protected registries without having to specify any secrets, since the kubelet just pulls the credentials dynamically.&lt;&#x2F;p&gt;
&lt;p&gt;But how does the &lt;code&gt;credential-provider&lt;&#x2F;code&gt; get the registry credentials?&lt;br &#x2F;&gt;
That actually depends on the cloud you are on. On AWS the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;cloud-provider-aws.sigs.k8s.io&#x2F;credential_provider&#x2F;&quot;&gt;ecr-credential-provider&lt;&#x2F;a&gt; uses the IAM role of the ec2 node it is on and then requests a shot lived token from AWS’s secret-token-services for the target registry, if the IAM policy allows it. It’s pretty much the same on Azure, while their &lt;code&gt;credential-provider&lt;&#x2F;code&gt; is not open-source, it is safe to assume that it uses Azures managed identities to acquire credentials for the desired registry. You can read more about the credential-provider-api on the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;kubernetes.io&#x2F;docs&#x2F;reference&#x2F;config-api&#x2F;kubelet-credentialprovider.v1&#x2F;&quot;&gt;Kubernetes Docs&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-can-i-profit-from-that&quot;&gt;How can I profit from that?&lt;&#x2F;h2&gt;
&lt;p&gt;It is quite easy to implement the kubernetes &lt;code&gt;credential-provider-api&lt;&#x2F;code&gt; yourself. And suddenly no developer needs to provide a password anymore if they pull images for you common-internal registry or from your DockerHub mirror. Even if you use &lt;code&gt;docker.io&lt;&#x2F;code&gt; directly, it is easy to reach the 100 pulls per 6h pull limit. But if you use a credential-provider, the limit is immediately doubled without any work for the devs.&lt;&#x2F;p&gt;
&lt;p&gt;Since it is so easy, I did it myself. I created a the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;hegerdes&#x2F;kubelet-static-credential-provider&quot;&gt;kubelet-static-credential-provider&lt;&#x2F;a&gt; which runs on every architecture that is supported by Kubernetes.
All you have to do is download the binary on every kubernetes node, create a small config and add the following arguments to your kubelet:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--image-credential-provider-bin-dir=&#x2F;var&#x2F;lib&#x2F;kubelet-plugins&#x2F;&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;--image-credential-provider-config=&#x2F;srv&#x2F;kscp-conf.yaml&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The &lt;code&gt;kscp-conf.yaml&lt;&#x2F;code&gt; should look like this and can contain as many credential providers as you want:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; &#x2F;srv&#x2F;kscp-conf.yaml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;piVersion&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; k&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ubelet.config.k8s.io&#x2F;v1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;k&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ind&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; C&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;redentialProviderConfig&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;p&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;roviders&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span&gt;  -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; n&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ame&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; s&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;tatic-credential-provider&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;    #&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; You can also use a config file instead of envs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;    #&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; args:[--config, &amp;lt;path-to-password-conf&amp;gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;    m&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;atchImages&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;d&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ocker.io&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;    d&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;efaultCacheDuration&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;12h&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;    a&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;piVersion&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; c&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;redentialprovider.kubelet.k8s.io&#x2F;v1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;    e&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;nv&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; n&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ame&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; K&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;SCP_REGISTRY_USERNAME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;        v&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;alue&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;my-user&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;14&lt;&#x2F;span&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; n&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ame&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; K&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;SCP_REGISTRY_PASSWORD&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;15&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;        v&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;alue&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;my-password&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;16&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;  #&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Optional: More credential providers&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now I doubled my DockerHub pull limit and can use private registries without any additional work for any devs. And let me say this, they will love you for not having to deal with these secrets.&lt;br &#x2F;&gt;
By the way, this is also a good method to bootstrap a cluster where the images are in private registries.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
My &lt;code&gt;static-credential-provider&lt;&#x2F;code&gt; is written in Go and uses the native Kubernetes types. But since it is such a simple interface, you can easily create the same functionality in a bash script when type safety is not so important. Don’t believe me? I also did a bash version, check it out &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;hegerdes&#x2F;kubelet-static-credential-provider&#x2F;blob&#x2F;main&#x2F;hack&#x2F;static-credential-provider.sh&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-word-about-security&quot;&gt;A word about security&lt;&#x2F;h2&gt;
&lt;p&gt;I already hear the screaming. &lt;strong&gt;THIS IS NOT SECURE! This is bad practice!!1!&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
Yeah, my implementation expects credentials that are on every node in plain text. But if some attacker gains access to one of your Kubernetes worker nodes you have far bigger problems to deal with. When an attacker has access to a node, he can get to the information and credentials on every container on that node. He can see all traffic and export any data on that node. Your infrastructure was compromised long before the attacker got access to the registry credentials.&lt;br &#x2F;&gt;
Even more important: Container images are not considered a safe place in the first place. If there is anything sensitive in your container image you are doing things wrong!&lt;&#x2F;p&gt;
&lt;p&gt;My advice is to create credentials that are read-only. So even in the case these leak, they can only be used to pull images with some application code that is to no use for anyone outside the company. It is also entirely possible to authenticate just a few registries with this method. The &lt;code&gt;matchImages&lt;&#x2F;code&gt; attribute allows a list of images for which the kubelet should invoke the &lt;code&gt;credential-provider&lt;&#x2F;code&gt;. You can even use patterns like &lt;code&gt;docker.io&#x2F;company-xyz-common&#x2F;*&lt;&#x2F;code&gt; in each entry to have fine grain control over when to use this functionally.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;If you have a self hosted Kubernetes cluster, this is an easy way to boos the devs productivity. It also allows pulling images from private registry in the bootstrap process when you can’t use &lt;code&gt;image-pull-secrets&lt;&#x2F;code&gt; yes. Implementing this is quite easy. Feel free to use my &lt;code&gt;static-credential-provider&lt;&#x2F;code&gt; or write you own version. Even a bash script can be enough and I also provided some alternatives in the &lt;em&gt;Readme&lt;&#x2F;em&gt; of my implementation. You can check it out here: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;hegerdes&#x2F;kubelet-static-credential-provider&quot;&gt;kubelet-static-credential-provider&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>New Website - Abandon JavaScript Frameworks</title>
        <published>2024-09-01T00:00:00+00:00</published>
        <updated>2024-09-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              hegerdes
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://henrikgerdes.me/blog/2024-09-homepage-v3/"/>
        <id>https://henrikgerdes.me/blog/2024-09-homepage-v3/</id>
        
        <content type="html" xml:base="https://henrikgerdes.me/blog/2024-09-homepage-v3/">&lt;h1 id=&quot;new-website-abandoning-javascript-frameworks&quot;&gt;New Website - Abandoning JavaScript frameworks&lt;&#x2F;h1&gt;
&lt;p&gt;This is the third generation of my website. I went from raw handwritten HTML to falling into the JavaScript frontend framework pit, back to raw HTML with a little templating. Let me tell you about this journey and my thoughts.&lt;br &#x2F;&gt;
Be aware that I’m not a web-developer and I will never be one!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;my-first-website-getting-things-out-there&quot;&gt;My First website - Getting things out there&lt;&#x2F;h2&gt;
&lt;p&gt;I was still in university and wanted to get some practical experience. My university had zero lectures about web-development, but I thought having my own site would be cool.&lt;br &#x2F;&gt;
I also had never shipped any software yet, so I had no clue how to put something out there for others to use. So I found a nice template I liked and customized it to my likings. HTML is not that complicated, and I didn’t need any JavaScript for this simple static site. So building the skeleton was quite easy, unitl I wanted to style it with CSS.&lt;br &#x2F;&gt;
I have worked with various programming languages, also low level languages like C&#x2F;C++ but I’ve never had to fight this much to get things working. I get the idea of classes but to this day I never fully understood the global scope of styles, overrides nor am I even close to know even a subset of all the CSS properties and transformers.&lt;&#x2F;p&gt;
&lt;p&gt;Eventually I had something usable, I needed to get it out there. I bought my first domain from the small German hoster IONOS - which was exiting back then. Now I was looking for a free hosting solution and eventually found &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.netlify.com&#x2F;&quot;&gt;netlify&lt;&#x2F;a&gt;. I needed to put put domain and hosting together. DNS at IONOS sucks (like almost everything from their offerings) so I transferred the DNS zone to netlify and started battling a little with TLS.&lt;&#x2F;p&gt;
&lt;p&gt;Yet, eventually I got to a state that was fine for me. Still the site had issues.&lt;br &#x2F;&gt;
Whenever I wanted to add a project I copied a bunch of HTML and added the new text. The header&#x2F;footer was manually copied to every page and the CSS was looking okay, but was actually a mess. But it worked for back then.&lt;br &#x2F;&gt;
Check out &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;homepage-v1.henrikgerdes.me&quot;&gt;v1&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;getting-into-professionalism-frameworks&quot;&gt;Getting into professionalism - Frameworks&lt;&#x2F;h2&gt;
&lt;p&gt;I was still in university but was working almost full-time at a local software company. My task there was to modernize and automate a lot of the deployment stack. I was given a lot of trust and I learned a lot. Things that work and things that don’t work. Occassionally I helped out on one of there products which was a NodeJS backend and a VUE.JS frontend which used nuxt to facilliate server-side-rendering (SSR).&lt;br &#x2F;&gt;
Everyone on YouTube and Medium was talking about frontend Frameworks for the web. Everything seemed to be build with Angular, React or VUE. So I belived this is the way to build the web. I fully bought into it.&lt;&#x2F;p&gt;
&lt;p&gt;So I started to rebuild my site with nuxt. Being able to reuse components for header and footer was great, but the whole creation process seemed a bit &lt;em&gt;off&lt;&#x2F;em&gt;. Passing object variables to a VUE component as a string is strange.&lt;br &#x2F;&gt;
The complexity added up. I wanted to publish blog posts written in markdown - no problem with nuxt-content. To style it use bootstrap, vuetify and more. Want to add approximation for reading time? Yet another package. Which you have to integrate with webpack. I did’t want to learn webpack, I wanted to create a webpage with a blog. It all seems unnecessary complicated.&lt;br &#x2F;&gt;
Having to keep in mind which part of the app was rendered server-side and which client side added additional cognitive load.&lt;&#x2F;p&gt;
&lt;p&gt;But since everyone is using the technology, it seems like this is the way.&lt;&#x2F;p&gt;
&lt;p&gt;Yet, eventually I got to a state that was fine for me. Still the site had issues.&lt;br &#x2F;&gt;
Load times where a not good, the style was inconsistent, code-blocks looked awful and I never got it working that the site remembered if had dark-mode activated on refreshes. But it was good enough. I used that site for almost three years. It worked for writing articles and I prioritized other things.&lt;br &#x2F;&gt;
Check out &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;homepage-v2.henrikgerdes.me&quot;&gt;v2&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-fresh-start-escaping-the-js-dept&quot;&gt;A fresh start - escaping the JS dept&lt;&#x2F;h2&gt;
&lt;p&gt;The site was automatically build from the main branch via netlify. Dependabot was setup to update my packages. But the JavaScript world is fast moving and a lot of people don’t bother with backwards compatibly. With time nuxt3 was released, but nothing worked with it. The site was using vue2, bootstrab4 and webpack4. Everything got deprecated and Dependabot kept reminding me of updates and vulnabilities. The site was slow, full of outdated packages and vulnerabilities!&lt;&#x2F;p&gt;
&lt;p&gt;To this day I carefully select my JS packages and avoid dependencies when ever possible because I think the JS ecosystem is a &lt;strong&gt;mess&lt;&#x2F;strong&gt;. So manny packages like leftpad, is-even and more - &lt;em&gt;WHY?&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I was looking for alternatives quite some time. I did’t want to go down the JS framework road again, mainly because I did’t need most of their functions. I wanted a static site generator. I looked into hugo which is great but I did’t find nice themes and found the themes creation process to much for my task.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;zola-to-the-rescue&quot;&gt;Zola to the rescue!&lt;&#x2F;h4&gt;
&lt;p&gt;Eventually I found &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.getzola.org&#x2F;&quot;&gt;zola&lt;&#x2F;a&gt; by browsing on the webpage of a colleague.&lt;br &#x2F;&gt;
It looked great, entirely content orientated:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;You can have themes, but you don’t need to&lt;&#x2F;li&gt;
&lt;li&gt;First party support for markdown rendering&lt;&#x2F;li&gt;
&lt;li&gt;Single small binary&lt;&#x2F;li&gt;
&lt;li&gt;Build &amp;amp; refresh is fast as heck&lt;&#x2F;li&gt;
&lt;li&gt;Support for SASS&lt;&#x2F;li&gt;
&lt;li&gt;Auto generation for search index&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;So I started porting over my first page as a proof of concept. And it worked great!&lt;br &#x2F;&gt;
Exactly the feature-set I wanted and nothing more. Templating is done with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;keats.github.io&#x2F;tera&#x2F;&quot;&gt;terra&lt;&#x2F;a&gt;, a python jinja2 like templating language which I was quite familiar with thanks to my countless hours in ansible. I had not a single issue with it. At least not with zola. CSS on the other hand reminded me why I will never be a frontend-developer. Getting things to look nice on every device is hard - even with bootstrap.&lt;&#x2F;p&gt;
&lt;p&gt;If I could change one thing regarding zola, it would be better control on how to pass classed into rendered content and more built-in code syntax highlight themes.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-current-state&quot;&gt;The current state&lt;&#x2F;h2&gt;
&lt;p&gt;I moved my back on JavaScript frontend frameworks - at least for static content.&lt;br &#x2F;&gt;
The whole site is now build with zola and adding new stuff is super easy. I also moved to site to cloudflare, better metrics, performance and I will not be billed 50k if I get DDOSed.&lt;br &#x2F;&gt;
The site works - even without JS enabled, the only thing that does not work without JS is search and the particle effect.&lt;&#x2F;p&gt;
&lt;p&gt;I’m quite happy with it right now. I still need battle some fights. But for my own sanity and well bing I’m shipping early and often to keep seeing progress.&lt;&#x2F;p&gt;
&lt;p&gt;Things to do:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Fix sidebar layout on blog page ✅&lt;&#x2F;li&gt;
&lt;li&gt;Add optional Live Demo button on some project&lt;&#x2F;li&gt;
&lt;li&gt;Dark Theme ✅&lt;&#x2F;li&gt;
&lt;li&gt;Add Search ✅&lt;&#x2F;li&gt;
&lt;li&gt;Write more 🔄️&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Some stats between my site:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;&#x2F;th&gt;&lt;th&gt;RAW&lt;&#x2F;th&gt;&lt;th&gt;Nuxt&lt;&#x2F;th&gt;&lt;th&gt;Zola&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;JS&lt;&#x2F;td&gt;&lt;td&gt;140KB&lt;&#x2F;td&gt;&lt;td&gt;4.2MB&lt;&#x2F;td&gt;&lt;td&gt;156KB&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;HTML&lt;&#x2F;td&gt;&lt;td&gt;544KB&lt;&#x2F;td&gt;&lt;td&gt;13MB&lt;&#x2F;td&gt;&lt;td&gt;1.4MB&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Build Time&lt;&#x2F;td&gt;&lt;td&gt;0s&lt;&#x2F;td&gt;&lt;td&gt;14s&lt;&#x2F;td&gt;&lt;td&gt;2.2s&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;🧾📖 NOTE: You might want to check out &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;homepage-v1.henrikgerdes.me&quot;&gt;v1&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;homepage-v2.henrikgerdes.me&quot;&gt;v2&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;henrikgerdes.me&quot;&gt;v3&lt;&#x2F;a&gt; of my site.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Benchmarking what actually drive our containers</title>
        <published>2024-07-01T00:00:00+00:00</published>
        <updated>2024-07-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              hegerdes
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://henrikgerdes.me/blog/2024-07-kubernetes-cri-bench/"/>
        <id>https://henrikgerdes.me/blog/2024-07-kubernetes-cri-bench/</id>
        
        <content type="html" xml:base="https://henrikgerdes.me/blog/2024-07-kubernetes-cri-bench/">&lt;h1 id=&quot;the-engines-that-run-our-kubernetes-workloads&quot;&gt;The Engines that run our Kubernetes Workloads&lt;&#x2F;h1&gt;
&lt;p&gt;🧾📖 &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;henrikgerdes.me&#x2F;docs&#x2F;kubernetes_cri_bench.pdf&quot;&gt;PDF version&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Target audience:&lt;&#x2F;em&gt; This article is a deep dive for people living the Kubernetes lifestyle, for people who know or want to know how the low level stuff works and performs. I do not explain every container or Kubernetes component as it is expected to be known.&lt;&#x2F;p&gt;
&lt;p&gt;Kubernetes has become THE standard for container orchestration. It is not just a software tool, it is a framework with extensive extensibility features. Entire businesses are built on top of Kubernetes and offer essential, nice to have and abstruse services. Tools like ArgoCD and Crossplane are build for Kubernetes and changed the way how we deploy software. There is even a new category of operating systems like CoreOS, Bottlerocket and Talos that are build purposely to run containers. All that happened in just 10 years. &lt;strong&gt;Happy late birthday K8s!&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;img&#x2F;blog&#x2F;cri-test-thump.jpeg&quot; alt=&quot;Kubernetes Container Stack Thumbnail&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Kubernetes is dominating almost every Ted-talk and system architecture presentation, yet the actual engine that drive our workloads sometimes gets forgotten. Kubernetes is just an orchestrator, and its primary (but not only) task is to manage containers. It does not run any containers itself. That gets delegated to the container runtime interface.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-little-history&quot;&gt;A Little History&lt;&#x2F;h2&gt;
&lt;p&gt;Initially, Kubernetes was build to manage Docker Containers. Docker is the technology that made containers accessible to the mainstream. Containers were not an entirely new technology. LXC containers existed before and Linux namespaces are a thing since 2002, but Docker made it so easy to use containers. By handling software packaging, distribution and all low level network and device configuration, Docker allowed every developer to start any application in an isolated environment. Promising to finally overcoming the famous: &lt;em&gt;It works on my machine&lt;&#x2F;em&gt; meme.&lt;br &#x2F;&gt;
Even the Kubernetes core team admits that Kubernetes would’ve been such a success without Docker. In an alternative universe, we are all using &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Apache_Mesos&quot;&gt;Mesos&lt;&#x2F;a&gt; 😉&lt;&#x2F;p&gt;
&lt;p&gt;At some point, a lot of different people and companies tried to solve similar problems regarding containers. Unlike some dinosaur companies with mediocre stubborn management, they agreed to build some common interfaces for their solutions so that parts of their implementations could be swapped while relying on certain standards. This led to the creation of the Open Container Initiative (OCI), Container Network Interface (CNI), Container Storage Interface (CSI) and Container Runtime Interface (CRI).&lt;br &#x2F;&gt;
Today, I want to talk about the Container Runtime Interface (CRI). With version 1.24, Kubernetes has overcome its dependence on Docker and now only relies on any CRI compliant runtime to start containers. And there are quite a few.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;cris&quot;&gt;CRIs&lt;&#x2F;h2&gt;
&lt;p&gt;The most common CRIs are containerd, CRI-O and Mirantis Container Runtime. Of these three, containerd is the most wildly used option. The containerd project was originally developed by Docker Inc and still is the core of Docker, but its ownership was since donated to the CNCF.&lt;br &#x2F;&gt;
When a new Pod is scheduled to a node, the kubelet communicates with containerd over the container runtime interface to actually pull the image and start the container with the configuration specified in the pod definition. Containerd is now in charge to set up the Linux namespace, mount volumes or devices and apply seccomp profiles and much more for every new container. That’s a lot of tasks, and not quite according to the UNIX philosophy to &lt;em&gt;do one thing and do it well&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;digging-deeper&quot;&gt;Digging deeper&lt;&#x2F;h3&gt;
&lt;p&gt;So containerd doesn’t do that all on its own. It uses something I call the container engine (others also call it OCI runtime, but I believe this would cause some confusion). By default, containerd calls &lt;code&gt;runc&lt;&#x2F;code&gt;. The runc binary actually spawns the container process with all its applied properties. It does not pull images, manages the containers file system, sets up networking or monitors the container process. Overly simplified it is just a &lt;code&gt;spawn&lt;&#x2F;code&gt; syscall with a bunch of extra properties for some isolation, but it still runs on the same kernel since containers are NOT VMs.&lt;&#x2F;p&gt;
&lt;p&gt;Most of the tooling for Kubernetes and containerd is written in go. Go is a great language, but some people argue that it is not the best choice for low level system functions. Discourse and different opinions are great and drive innovation. And since a bunch of smart people choose to standardize container interfaces, everyone can create their own OCI compliant implementation and use it with the existing CRIs and tools.&lt;br &#x2F;&gt;
And that is exactly what people did, and I will take a look at some of them and compare them.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;benchmarking-container-engines&quot;&gt;Benchmarking Container Engines&lt;&#x2F;h2&gt;
&lt;p&gt;Containers are created all the time. We don’t even think about them anymore when we schedule a deployment with 42 replicas. But since it happens so frequently, we might take an occasional look at what actually happens at a low level and how it impacts our cluster’s efficiency. Do container engines impact start-up time and memory consumption? Since I didn’t find any real up-to-date comparisons, I took a look for myself and ended up comparing these implementations:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;runc - The default OCI engine written in go that comes with containerd&lt;&#x2F;li&gt;
&lt;li&gt;crun - Alternative OCI implantation written in C, claiming to be -49.4% faster than runc for running &lt;code&gt;&#x2F;usr&#x2F;bin&#x2F;true&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;gvisor&#x2F;runsc - Googles safe OCI implantation (also written in go) that aims to improve security by running many syscalls in userspace&lt;&#x2F;li&gt;
&lt;li&gt;youki - Quiet young alternative OCI implantation written in rust&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;!---
### Assumtion
The crun project makes some bold claims but for my self managed test cluster I&#x27;ve been using crun for over an year and must say that I had the impression the everything felt a little more snappy with it. I also like its extendability. You can compile crun with webassembly support and run wasm containers the same way as normal one without any additional OCI engine needed. I think it will slightly outperform runc but not as much as claimed. Googles gvisor will defintly be slower since its main purose is enhancing security and that extra layer to run syscalls in userspace will cost performance. For youki I don&#x27;t have any expectation since I&#x27;ve never used it before.  Might be at the same level as runc, maybe a little slower since it didn&#x27;t had time yet to mature and optimize.
--&gt;
&lt;h3 id=&quot;testsetup&quot;&gt;Testsetup&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;em&gt;Disclaimer:&lt;&#x2F;em&gt; This is NOT a scientific benchmark. I’m quite a noop in profiling such applications, and I cannot claim full correctness for my findings. If you know how to do it better, please show me.&lt;&#x2F;p&gt;
&lt;p&gt;I created a VM on the Hetzner-Cloud using their dedicated offerings to avoid the effect of noisy neighbors. I redid the test on another instance to ensure I didn’t get a low-performing one. System Data:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;r&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;egion&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; n&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;bg1-dc3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;o&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;s&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; L&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;inux 6.1.0-21-amd64 Debian 12 (2024-05-03) x86_64 GNU&#x2F;Linux&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;s&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ku&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;4&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  t&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ype&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; C&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;CX33&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;5&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  c&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;pu&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 8&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;6&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  r&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;am&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 32&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The test environment was configured with an &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;hegerdes&#x2F;ansible-playbooks&#x2F;blob&#x2F;cri-bench-v1&#x2F;pb_k8s_cri_test.yml&quot;&gt;ansible playbook and my personal Kubernetes role&lt;&#x2F;a&gt; I use to play around. My benchmark script uses the &lt;code&gt;time&lt;&#x2F;code&gt; tool to measure execution time and calculates min, max and mean for 1000 container creations for the busybox image running &lt;code&gt;&#x2F;usr&#x2F;bin&#x2F;true&lt;&#x2F;code&gt;. I use &lt;code&gt;nerdctl&lt;&#x2F;code&gt; to create containers rather than calling the OCI implementation directly, since it mimics a more realistic use of an CRI. Before every test, I run a small warm-up to allow the CPU to boost clock speed. I found it hard to measure CPU and memory consumption for a short-lived process, so I installed node-exporter and have it scraped by Prometheus (running on another system) every 5 seconds.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;containerd version 1.7.18&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;crun version 1.15&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;runc version 1.1.13&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;runsc version release-20240617.0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;youki version 0.3.3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;results&quot;&gt;Results&lt;&#x2F;h3&gt;
&lt;p&gt;The node’s CPU and RAM were not even remotely utilized as seen in the Grafana dashboard below. In contrast to the production environment where the kubelet can create several containers simultaneously, my benchmark runs in serial. Nevertheless, some conclusions can be drawn.
The test showed indeed that crun outperforms containerd’s default OCI engine, yet the difference is not as big as claimed on the crun website. However, you have to bear in mind that it was not the same test as on the crun page. The performed benchmark includes the overhead of containerd,  to represent a more realistic deployment compared to calling the OCI engine directly.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;img&#x2F;blog&#x2F;oci-data-2.jpg&quot; alt=&quot;Grafana Dashboard showing OCI CPU usage&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Given the claims from crun I was expecting a bigger difference between crun and runc. A 21% difference is still impressive. Surprisingly, the quiet new youki implementation is right up there head to head with runc when it comes to pure performance. Unfortunately, youki didn’t perform as consistent and errored out quite some times. I reported the error to the authors and hope it will be fixed soon, despite its good performance an error rate of 3.6% is not acceptable in a production environment.&lt;br &#x2F;&gt;
As expected, runsc performs worst by far. However, performance is not its primary goal, it aims to improve security by implementing syscalls in userspace. The chosen test may also not favorable for runsc since running a short-lived container with &lt;code&gt;true&lt;&#x2F;code&gt; does not have many syscalls, the lower context switche are still noticeable as shown in the last dashboard below.&lt;br &#x2F;&gt;
The main findings are summarized in the table below.&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;OCI&lt;&#x2F;th&gt;&lt;th&gt;Mean&lt;&#x2F;th&gt;&lt;th&gt;Min&lt;&#x2F;th&gt;&lt;th&gt;Max&lt;&#x2F;th&gt;&lt;th&gt;Errors&lt;&#x2F;th&gt;&lt;th&gt;Total Time&lt;&#x2F;th&gt;&lt;th&gt;Min Mem&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;crun&lt;&#x2F;td&gt;&lt;td&gt;0.28s&lt;&#x2F;td&gt;&lt;td&gt;0.13s&lt;&#x2F;td&gt;&lt;td&gt;0.41s&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;306s&lt;&#x2F;td&gt;&lt;td&gt;160kb&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;runc&lt;&#x2F;td&gt;&lt;td&gt;0.34s&lt;&#x2F;td&gt;&lt;td&gt;0.16s&lt;&#x2F;td&gt;&lt;td&gt;0.44s&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;362s&lt;&#x2F;td&gt;&lt;td&gt;8mb&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;runsc&lt;&#x2F;td&gt;&lt;td&gt;0.62s&lt;&#x2F;td&gt;&lt;td&gt;0.44s&lt;&#x2F;td&gt;&lt;td&gt;1.64s&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;642s&lt;&#x2F;td&gt;&lt;td&gt;32mb&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;youki&lt;&#x2F;td&gt;&lt;td&gt;0.32s&lt;&#x2F;td&gt;&lt;td&gt;0.16s&lt;&#x2F;td&gt;&lt;td&gt;0.46s&lt;&#x2F;td&gt;&lt;td&gt;36&lt;&#x2F;td&gt;&lt;td&gt;354s&lt;&#x2F;td&gt;&lt;td&gt;2mb&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Memory was hard to test, and I found no significant differences here. From the data node-exporter provided it seems like crun and runc use a little less memory compared to the others, but I can not prove that no other process caused the increase, even when I did my best to keep variations low.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;img&#x2F;blog&#x2F;oci-data-1.jpg&quot; alt=&quot;Grafana Dashboard showing OCI CPU &amp;amp; RAM usage&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;A claim that I was able to verify is that cruns authors say it requires far less memory to start a container than runc. I tested how low I could set the memory limit via the CRI for each engine via &lt;code&gt;nerdctl run --memory 4mb ...&lt;&#x2F;code&gt;. The authors claim it requires less than 4mb, which is the lowest limit podman allows. I was able to start busybox with a memory limit of just 160kb. This is indeed impressive, even though it is not directly relevant in a production environment, since most applications within a container will need and have much higher limits.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;honorable-findings&quot;&gt;Honorable findings&lt;&#x2F;h3&gt;
&lt;p&gt;I wanted to compare the runtime and memory performance of these OCI implementations, but when monitoring, I also noticed some spikes in IO.
I did not expect that starting a small container like busybox would cause some significant IO writes, and I don’t really know why write activity is “so high” for just starting a container. Both crun and runc caused around ≈700-800 IOPS and ≈4-4.5 MB&#x2F;s in writes. Slightly less was needed for youki and runsc was using just half of IOPS and MB&#x2F;s in comparison with crun and runc. According to its promises, runsc also caused fewer context switches for syscalls. I’m quite interested in learning more about the “high” writes, though. Especially where the differences come from when the same snaphotter is used across all OCI engines.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;img&#x2F;blog&#x2F;oci-data-3.jpg&quot; alt=&quot;Grafana Dashboard showing OCI IO usage&quot; &#x2F;&gt;
&lt;img src=&quot;&#x2F;img&#x2F;blog&#x2F;oci-data-4.jpg&quot; alt=&quot;Grafana Dashboard showing OCI system context switches&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The complete raw output can be found on my &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;hegerdes&#x2F;c9b1a171d82bf19a10c8505ee6b9ee10&quot;&gt;GitHub Gist&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;The performance differences between the tested OCI implementations are not as big as I expected, and even though crun performs better, I doubt that switching to it justifies the operational overhead for most companies - at least for managed Kubernetes offerings. As far as I know most managed Kubernetes offerings use containerd with runc. Being able to just use AWS managed AMIs (or Azures) is a huge time and cost saver. Unless the last percent of performance is highly important, I would just stick with runc. It would still be nice to see hyperscaler’s include crun in their AMIs (which costs 2MB of space) and give users the choice via runtimeclasses.&lt;br &#x2F;&gt;
For self-hosted and embedded Kubernetes offerings, crun might be worth a look. Even more if companies are running cutting edge technology like WASM within their clusters. Both crun and youki can be compiled with WASM support. Meaning users can run WASM applications in their clusters with the same OCI as all their other containers. Which is SICK! I’ve been using this for quite some time and it works great. The only downside is that WASM support is not enabled by default yet and you have to compile it yourself. (I’ve set up an GH Action automation just for that.)
The first look of youki is promising, but without having these errors solved, I wouldn’t use it in production. When it comes to gvisor&#x2F;runsc I’m a little unsure. It offers additional security, but most people run their own or trusted workloads in their clusters. If one would run random untrusted code, like someone’s leetcode or lambda code I might want to use things like kata containers or firecracker VMs which offer a higher level of isolation. If someone wants to include these in the tests, I’m very interested - I couldn’t run these since they require nested virtualization, which is not supported on Hetzners CCX VMs. This leaves gvisor in some weird middle ground, especially with Kubernetes upcoming ability to run containers in user namespaces further increasing security.&lt;&#x2F;p&gt;
&lt;p&gt;Innovation in the container world has settled down a bit since a lot of the technology as reached mainstream adoption and has standardized. The existing solutions have become more accessible, and the defaults cover the needs of the majority of use cases. Yet, it is still interesting how new solutions hit the market, resulting in a drop in replacements for solving specific problems.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Using GitLab to manage Kubernetes access</title>
        <published>2024-06-12T00:00:00+00:00</published>
        <updated>2024-06-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              hegerdes
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://henrikgerdes.me/blog/2024-06-gitlab-for-k8s-access/"/>
        <id>https://henrikgerdes.me/blog/2024-06-gitlab-for-k8s-access/</id>
        
        <content type="html" xml:base="https://henrikgerdes.me/blog/2024-06-gitlab-for-k8s-access/">&lt;h1 id=&quot;using-gitlab-to-manage-kubernetes-access&quot;&gt;Using GitLab to manage Kubernetes access&lt;&#x2F;h1&gt;
&lt;p&gt;Recently I have been tasked to share access to a Kubernetes test cluster with other teams. Easy: Add them to a group in your &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;openid.net&#x2F;specs&#x2F;openid-connect-core-1_0.html&quot;&gt;OIDC&lt;&#x2F;a&gt; provider and set appropriate RBAC rules. Task done - no need to write this.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;but&quot;&gt;BUT:&lt;&#x2F;h2&gt;
&lt;p&gt;Unfortunately I can’t have an OIDC provider for non-production clusters… because. &lt;em&gt;Sighs…&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;details&gt;
  &lt;summary&gt;TL;DR&lt;&#x2F;summary&gt;
Use Kubernetes built-in OIDC authentication; if this is not possible for whatever reason, the GitLab Kubernetes Agent might be worth a look.
&lt;&#x2F;details&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;img&#x2F;blog&#x2F;kubernetes-glab-auth-logo.jpeg&quot; alt=&quot;Secure Lock Logo Thumbnail&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Okay what other options are there for Kubernetes authentication:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Webhook Token Authentication&lt;&#x2F;li&gt;
&lt;li&gt;Authenticating Proxy&lt;&#x2F;li&gt;
&lt;li&gt;Static token file&lt;&#x2F;li&gt;
&lt;li&gt;X509 client certificates&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Both webhook authentication and an authentication proxy add considerable overhead and ultimately also need to be plunged into a user registry that I can not use or have control of.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;So what about static token files?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
In practice, I’ve never seen them outside of test setups. It requires placing a file with the username, secret and groups on every controlplane node. The effort required to manage and sync such a file, containing static &lt;strong&gt;credentials in plain text&lt;&#x2F;strong&gt;, is just nuts. Even more absurd, the api-server has to be restarted every time this file is changed! And since these tokens have no built-in expiration date, you have to delete an entry and restart the api-server if a credential needs to be invalidated. So this is a hard pass!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;So X509 client certificates it is?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
The X509 client certificates approach does not require the api-server to be restarted and provides a built-in expiration mechanism. Client certificates are a common approach to establishing a secure communication between two entities, it is often also referred to as mutual TLS (mTLS), where both the client and the server have to identify themselves via a certificate. One-directional TLS (where just the server is ensuring its authenticity) is part of almost every website we visit.&lt;br &#x2F;&gt;
TLS is considered very secure since, it uses asymmetric encryption with private keys, with a complexity between 1024 and 4098 bits, depending on the algorithm. Kubernetes uses mTLS for almost all of its components to establish trusted and secure communication between every part of the cluster. Kubernetes clusters created with kubeadm also create a &lt;code&gt;admin.conf&lt;&#x2F;code&gt; which also uses X509 client certificates to authenticate against the Kubernetes api-server.&lt;br &#x2F;&gt;
These X509 client certificates are the default way to authenticate against a Kubernetes cluster. For easier usage, Kubernetes base64 encodes the certificate and the private key and puts them inside the well-known YAML kubeconfig. The file is most likely located at &lt;code&gt;~&#x2F;.kube&#x2F;config&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I have gone the X509 client certificates way and if you are interested, below is a rough draft on how you can automate user config creation. But there is a catch too &lt;em&gt;Sighs…x2&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;details&gt;
&lt;summary&gt;Creating X509 client certificates&lt;&#x2F;summary&gt;
&lt;p&gt;Every user should have their own personal kubeconfig to ensure proper access controls and auditing capabilities. Unfortunately there is no built-in support from Kubernetes for creating these kube-client-configs. Nevertheless the process can easily be automated.&lt;&#x2F;p&gt;
&lt;p&gt;The user has to create a new key-pair with openssl which he will use for accessing the cluster later. This can be done with the following command:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Bits for the key&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;KEY_SIZE&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;4&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;9&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;6&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Username&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;USERNAME&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;M&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Y&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;_&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;U&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;S&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;E&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;R&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Groups&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;GROUP_1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;E&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;A&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;M&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;_&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;A&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;GROUP_2&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;E&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;A&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;M&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;_&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;B&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Creating key and certificate signing request&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;openssl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; req&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;newkey&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; rsa:&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;KEY_SIZE&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;nodes&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;keyout&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; k8s-client-1.key&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;batch&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;out&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; k8s-client-1.csr&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;subj&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;CN=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;USERNAME&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;O=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;GROUP_1&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;O=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;GROUP_1&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;emailAddress=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;USERNAME&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;@example.com&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The resulting certificate signing request (CSR) now has to be signed by the clusters Common Authority (CA).
The signing request can either be done wither the Kubernetes certificate api by creating a &lt;code&gt;CertificateSigningRequest&lt;&#x2F;code&gt; or manually by copying the clients CSR to the api-server and signing it with the clusters CA via openssl. The first option is clearly preferable as it does not require access to the node on which the api-server runs on and there is a traceable audit log.&lt;br &#x2F;&gt;
The resulting certificate and the key are then base64 encoded and inserted into the format of the kubeconfig. The resulting file will have this layout (without the certificate data redacted):&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;piVersion&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; v&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;k&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ind&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; C&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;onfig&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;urrent-context&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; d&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ocker-desktop&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;lusters&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; c&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;luster&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;          c&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ertificate-authority-data&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; L&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;S0...S0K&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;          s&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;erver&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; h&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ttps:&#x2F;&#x2F;Kubernetes.docker.internal:6443&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;      n&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ame&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; d&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ocker-desktop&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ontexts&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; c&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ontext&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;          c&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;luster&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; d&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ocker-desktop&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;          u&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ser&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; d&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ocker-desktop&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;      n&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ame&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; d&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ocker-desktop&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;14&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;u&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;sers&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;15&lt;&#x2F;span&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; n&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ame&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; d&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ocker-desktop&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;16&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;      u&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ser&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;17&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;          c&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;lient-certificate-data&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; L&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;S0...g==&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;18&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;          c&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;lient-key-data&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; L&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;S0...o=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;em&gt;NOTE:&lt;&#x2F;em&gt; If you want a fully automated process for this just send me a massage!&lt;&#x2F;p&gt;
&lt;&#x2F;details&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;img&#x2F;blog&#x2F;one-support-meme.png&quot; alt=&quot;Meme - one support for whole company&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-problems-with-static-credentials&quot;&gt;The Problems with static credentials&lt;&#x2F;h3&gt;
&lt;p&gt;While mTLS is technical very secure, it still suffers from problems organizational standpoint. From a modern standpoint, certificates are still long-lived credentials. Thanks to the exemplary work done by the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;letsencrypt.org&#x2F;&quot;&gt;lets encrypt&lt;&#x2F;a&gt; project, most certificates are issued with shorter lifetimes compared to the previously common validity of 1+ years. Still, a default of three months is a heck longer than the one-hour default lifetime of an OIDC ID-Token.&lt;br &#x2F;&gt;
It is also possible to revoke certificates, but just like the creation process, it is not that easy to implement this process. Even when these security aspects are not considered, client certificates become hard to manage in larger or dynamic teams. You must have a way to revoke access from a retired team member. When a user needs to be added, the whole certification creation process has to be done again. Authorization should be done on group level basis, but you can’t add a group to a certificate after it was issued. This is not flexible and manageable in any larger organization. For this reason, dynamic authentication processes - like OIDC - are often preferred.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;I have a great article about OAuth2 and OIDC coming up soon on my companies website - stay tuned&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;alternatives&quot;&gt;Alternatives&lt;&#x2F;h2&gt;
&lt;p&gt;So what are my alternatives?&lt;br &#x2F;&gt;
The said cluster in deployed in a very restrictive network environment. Ingress is only allowed from specific clients within a corporate network and only specific ports and traffic. Egress is only possible via a proxy. But we needed to deploy from our GitLab (which is on a different network) instance to our cluster.&lt;br &#x2F;&gt;
Other people solved this by creating GitLab runners within the Kubernetes cluster and saving the kube-client-credentials-conf as a CI secret. &lt;strong&gt;DONT DO THIS!&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;You are pulling in random container images from the internet to your cluster and run arbitrary scripts from CI in your critical application environment. You are risking your cluster health, the confidently of secrets and are giving up a considerable amount of compute. And you also have to maintain the runners. This also violates the ISO 27001 norm since now access is not personalized anymore and auditing is really hard.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;gitlab-agent&quot;&gt;GitLab Agent&lt;&#x2F;h3&gt;
&lt;p&gt;Quite some time ago I stumbled upon the GitLab Agent. It’s a small application that creates a reverse tunnel between your control-plane and GitLab instance via websockets. This allows you to use any runner in any network location to securely communicate over the GitLab Instance websocket tunnel, via the GitLab agent to your Kubernetes cluster.
GitLab automatically creates short-lived tokens (&lt;code&gt;CI_JOB_TOKEN&lt;&#x2F;code&gt;) and only allows authorized users to use the tunnel in CI.&lt;&#x2F;p&gt;
&lt;p&gt;You can install the agent easily with:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;helm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; repo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; add&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; gitlab&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; https:&#x2F;&#x2F;charts.gitlab.io&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;helm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; repo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; update&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;helm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; upgrade&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-install&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; test&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; gitlab&#x2F;gitlab-agent&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-namespace&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; gitlab-agent&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-create-namespace&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-set&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; image.tag=v17.0.0&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-set&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; config.token=glagent-xxx&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-set&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; config.kasAddress=wss:&#x2F;&#x2F;gitlab.example.com&#x2F;&#x2F;-&#x2F;Kubernetes-agent&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now you can create a file in you git repo with the path &lt;code&gt;.gitlab&#x2F;agents&#x2F;&amp;lt;agent-name&amp;gt;&#x2F;config.yaml&lt;&#x2F;code&gt; and even share the cluster access with other Git projects:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;i_access&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  p&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;rojects&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; i&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;d&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; m&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;y-team&#x2F;serviceX&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; i&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;d&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; e&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;xternal-team1&#x2F;projectA&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; i&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;d&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; e&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;xternal-team2&#x2F;projectB&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;6&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  g&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;roups&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;7&lt;&#x2F;span&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; i&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;d&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; q&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;a&#x2F;loadtests&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;No secrets needed, secure and controlled access to the cluster.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;WAIT…That wasn’t the problem I wanted to solve. I need to share access with people - not with CI!&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Good News:&lt;&#x2F;strong&gt; This also works for people.&lt;&#x2F;p&gt;
&lt;p&gt;You can just add the following to your &lt;code&gt;.gitlab&#x2F;agents&#x2F;&amp;lt;agent-name&amp;gt;&#x2F;config.yaml&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;u&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ser_access&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  a&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ccess_as&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;    u&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ser&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  p&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;rojects&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; i&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;d&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; g&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;lobal&#x2F;groups&#x2F;admins&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  g&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;roups&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; i&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;d&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; m&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;y-team&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; i&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;d&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; q&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;a&#x2F;loadtests&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now GitLab allows all users that are in these projects or groups to access the cluster endpoint via the agents tunnel.&lt;br &#x2F;&gt;
The important part in that config is the &lt;code&gt;access_as.user&lt;&#x2F;code&gt; property. The Agent will use &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;Kubernetes.io&#x2F;docs&#x2F;reference&#x2F;access-authn-authz&#x2F;authentication&#x2F;#user-impersonation&quot;&gt;impersonation&lt;&#x2F;a&gt; to act like the GitLab user that uses the tunnel. That means you can easily set fine-grained permissions via RBAC to only allow the &lt;code&gt;qa&lt;&#x2F;code&gt; group read access while the &lt;code&gt;admins&lt;&#x2F;code&gt; have cluster-admin roles. If you are a masochist, you can also apply the RBAC rules per user.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-solution&quot;&gt;The Solution&lt;&#x2F;h3&gt;
&lt;p&gt;Now, all users can configure their kubeconfigs to use the cluster endpoint &lt;code&gt;https:&#x2F;&#x2F;gitlab.exmaple.com&#x2F;-&#x2F;Kubernetes-agent&lt;&#x2F;code&gt; and use their GitLab credentials to authenticate.&lt;br &#x2F;&gt;
Basic permissions are handled by GitLab and the fine-grained Kubernetes permissions are controlled via RBAC.&lt;&#x2F;p&gt;
&lt;p&gt;If a team member retires, just remove them from the GitLab group and the access is gone. A new team member needs onboarding, add them to GitLab and he already has access to the cluster. &lt;em&gt;Easy management and even ISO 27001 compliant&lt;&#x2F;em&gt; 🙌&lt;&#x2F;p&gt;
&lt;details&gt;
&lt;summary&gt;Complete Kubeconfig&lt;&#x2F;summary&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;piVersion&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; v&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;k&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ind&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; C&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;onfig&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;urrent-context&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; g&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;itlab-cluster-via-agent-42&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;lusters&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; c&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;luster&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;        s&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;erver&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; h&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ttps:&#x2F;&#x2F;gitlab.exmaple.com&#x2F;-&#x2F;Kubernetes-agent&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;      n&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ame&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; g&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;itlab&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ontexts&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; c&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ontext&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;        c&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;luster&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; g&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;itlab&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;        u&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ser&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; g&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;itlab-agent-42&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;      n&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ame&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; g&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;itlab-cluster-via-agent-42&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;u&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;sers&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;14&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;    #&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Users can use a pat to access the cluster&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;15&lt;&#x2F;span&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; n&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ame&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; g&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;itlab-agent-42&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;16&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;      u&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ser&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;17&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;        t&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;oken&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;pat:42:XXX&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;18&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;    #&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Or use the glab cli for just in time credentials with a 24h expiry&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;19&lt;&#x2F;span&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; n&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ame&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; g&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;itlab-agent-42-glab&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;20&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;      u&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ser&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;21&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;        e&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;xec&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;22&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;            a&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;piVersion&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; c&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;lient.authentication.k8s.io&#x2F;v1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;23&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;            a&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;rgs&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;24&lt;&#x2F;span&gt;&lt;span&gt;                -&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; c&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;luster&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;25&lt;&#x2F;span&gt;&lt;span&gt;                -&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; a&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;gent&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;26&lt;&#x2F;span&gt;&lt;span&gt;                -&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; g&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;et-token&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;27&lt;&#x2F;span&gt;&lt;span&gt;                -&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; --&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;agent&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;28&lt;&#x2F;span&gt;&lt;span&gt;                -&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;42&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;29&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;            c&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ommand&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; g&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;lab&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;30&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;            e&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;nv&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;31&lt;&#x2F;span&gt;&lt;span&gt;                -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; n&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ame&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; G&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ITLAB_HOST&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;32&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;                  v&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;alue&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; h&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ttps:&#x2F;&#x2F;gitlab.example.com&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;33&lt;&#x2F;span&gt;&lt;span&gt;                -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; n&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ame&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; G&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ITLAB_CLIENT_ID&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;34&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;                  v&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;alue&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; X&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;XX&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;35&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;            i&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;nstallHint&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;To access the cluster install glab. Instructions at https:&#x2F;&#x2F;gitlab.com&#x2F;gitlab-org&#x2F;cli#installation.&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;36&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;            i&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;nteractiveMode&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; N&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ever&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;37&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;            p&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;rovideClusterInfo&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;38&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;&#x2F;details&gt;
&lt;h2 id=&quot;side-notes&quot;&gt;Side Notes&lt;&#x2F;h2&gt;
&lt;p&gt;This is not the only solution to access private clusters. But this did the job and security is fine with it. Jump Hosts, VPNs and SSH tunnels are also commonly used but they are often a nightmare to manage or to set up.
A notable alternative is tailscale which also creates a tunnel to you tailnet and allows for user authentication. Unfortunately, tailscale is not used at my current gig.&lt;&#x2F;p&gt;
&lt;p&gt;While these are solutions, I still would recommend to just hook your OIDC provider such as ActiveDirectory, LDAB or Keycloak into the Kubernetes api-server. It is also a much more standardized solution and should be the primary source for all user contexts.&lt;br &#x2F;&gt;
To my surprise not many managed Kubernetes offerings support setting the OIDC args for the api-server. So this might after all be a good solution if your Kubernetes provider is lacking.&lt;&#x2F;p&gt;
&lt;!---




---
Having access to a Kubernetes cluster gives developers a high degree of automonie. They can deploy, update and debug services in a production like enviorment. But it also. This freedom, however, comes with great responsibility. Developers now have not just one machine at their disposal, but a whole range of machines at once. It often also gives them access to certificate managment and often even DNS zones.  

In traditional IT, these were areas that were strictly separated between developers and operators. With the rise of the DevOps approach, these boundaries are becoming increasingly blurred. However, especially in large companies, it is still crutial to separate certain resources between teams according to their responsibilities.


## Types of authentication
When consulting the [Kubernetes doukentation](https:&#x2F;&#x2F;Kubernetes.io&#x2F;docs&#x2F;reference&#x2F;access-authn-authz&#x2F;authentication) regarding authentication is are a bunch of different strategies to authenticate. These can be catagrized into these types:

  * Static Authentication
	  * X509 client certificates
	  * Static token file
	  * Bootstrap tokens
	  * Service account tokens
  * Dynamic Authentfication
	  * OpenID Connect Tokens
	  * Webhook Token Authentication
	  * Authenticating Proxy

## Static Tokens
When looking at the static authentication methods, these can be further subdivided. Both Bootstrap tokens and Service account tokens are primarly used for in-cluster authentication. Bootstrap tokens are tokens that are justed jused to add a new node to a cluster. In general they have a short expiration time and a very limited scope of allowed actions. The kubelet uses these to request a client-configuration set which will be used for all further requests.  
The Service account tokens are compleatly managed by Kubernetes and are intendet to allow pods within the cluster to communicate with the api-server. When a new pod is created, Kubernetes mounts the Service account tokens as a file into the pods filesystem at a wellknown location if not configured otherwise.


## Dynamic Authtification
The lack of easy creation and managment of these static authentication processes is the reson manny managed Kubernetes offerings recommend using dynamic approches that integrate within the existing organization.  
This can be done with Webhook Token Authentication or a Authenticating Proxy but as staited above these can be implemented in any imagable way and will not be further discussed here. Insted this article will focuse on OpenID Connect and will also give an alternative if OIDC is not an option.

--&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>The recurring problem of the Kubernetes metrics server and insecure Kubelet certificate</title>
        <published>2024-05-18T00:00:00+00:00</published>
        <updated>2024-05-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              hegerdes
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://henrikgerdes.me/blog/2024-05-kubelet-server-cert/"/>
        <id>https://henrikgerdes.me/blog/2024-05-kubelet-server-cert/</id>
        
        <content type="html" xml:base="https://henrikgerdes.me/blog/2024-05-kubelet-server-cert/">&lt;h2 id=&quot;the-recurring-problem-of-the-metrics-server-and-insecure-kubelet-certificate&quot;&gt;The recurring problem of the Metrics Server and Insecure Kubelet certificate&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;what-is-this-about&quot;&gt;What is this about:&lt;&#x2F;h3&gt;
&lt;p&gt;Currently the kubelet, the client agent coordinating container lifecycle on each node, also runs a server, using a self signed certificate by default. Therefore any client connecting the the kubelet server, most prominent the metrics server, will not be able to verify the servers identity.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;img&#x2F;blog&#x2F;kubelet-insecure.jpg&quot; alt=&quot;Avengers style fight scene with GitHub OctoCat and GitLab mascot&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;current-state&quot;&gt;Current state:&lt;&#x2F;h3&gt;
&lt;p&gt;Currently if the kubelet starts and no &lt;code&gt;--tls-cert-file&lt;&#x2F;code&gt; and &lt;code&gt;--tls-private-key-file&lt;&#x2F;code&gt; are specified it generated a self-signed pair and uses it for its server component according the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;kubernetes.io&#x2F;docs&#x2F;reference&#x2F;command-line-tools-reference&#x2F;kubelet&#x2F;&quot;&gt;kubelet docs&lt;&#x2F;a&gt;&lt;br &#x2F;&gt;
The is a feature feature flag called &lt;code&gt;RotateKubeletServerCertificate&lt;&#x2F;code&gt; which would allow the use of &lt;code&gt;serverTLSBootstrap&lt;&#x2F;code&gt;. This uses the native &lt;code&gt;CertificateSigningRequest&lt;&#x2F;code&gt; (csr) resource wich is part of the &lt;code&gt;certificates.k8s.io&#x2F;&lt;&#x2F;code&gt; api. When &lt;code&gt;serverTLSBootstrap&lt;&#x2F;code&gt; is enabled the kubelet creates a csr via the kubernetes certificates api for its server component. Users can either approve the csr manually with &lt;code&gt;kubectl certificate approve &amp;lt;my-csr&amp;gt;&lt;&#x2F;code&gt; or create a rolebinding wich allows for auto-approve. The resulting cert is singed by the clusters ca if the kube-controller has access to the ca cert and key (most likely it has).&lt;br &#x2F;&gt;
The process is described in the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;kubernetes.io&#x2F;docs&#x2F;reference&#x2F;access-authn-authz&#x2F;kubelet-tls-bootstrapping&#x2F;#certificate-rotation&quot;&gt;tls-bootstrapping&lt;&#x2F;a&gt; documentation, this provides the prerequisites for a trust chain verification.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-problem&quot;&gt;The problem:&lt;&#x2F;h3&gt;
&lt;p&gt;With self-singed certificates there is no way to reliable verify the kubelet’s server identity. Even the metrics-servers docs says that passing &lt;code&gt;--kubelet-insecure-tls&lt;&#x2F;code&gt; is not a solution for production.&lt;br &#x2F;&gt;
The recent addition &lt;code&gt;serverTLSBootstrap&lt;&#x2F;code&gt; is an approvement but the control over the created csr is very limited to non existed. Most Kubernetes setups are not trivial. Nodes have multiple IPs and may be available over one ore move dns names, let alone IPv6 addresses. From my experience and according to other posts the created kubelet csr does not contain any SANs which could identify the server. The CN ist set to &lt;code&gt;system:node:&amp;lt;name&amp;gt;&lt;&#x2F;code&gt; wich is NOT a valid DNS name.&lt;br &#x2F;&gt;
This lack over the certificate details also results in the lack of the possibility to verify the identity of the kubelet server. Binging us back the the need for &lt;code&gt;--kubelet-insecure-tls&lt;&#x2F;code&gt; for all clients talking to the kubelet. Even managed kubernetes offerings have this problem.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-proposal&quot;&gt;The Proposal:&lt;&#x2F;h3&gt;
&lt;p&gt;Kubernetes admins and vendors should have an easy possibility to crate trusted kubelet server certificates.&lt;br &#x2F;&gt;
This can be achieved either via the certificate generation phase of kubeadm or via passing extra args to the kubelet tls setup to include additional SANs.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Existing behavior with etcd and kube-api-server&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;piVersion&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; k&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ubeadm.k8s.io&#x2F;v1beta3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;k&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ind&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; C&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;lusterConfiguration&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;piServer&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  c&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ertSANs&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;10.100.1.1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ec2-10-100-0-1.compute-1.amazonaws.com&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;e&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;tcd&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  l&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ocal&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;    i&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;mageRepository&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;registry.k8s.io&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;    s&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;erverCertSANs&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ec2-10-100-0-1.compute-1.amazonaws.com&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity&quot;&gt;---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;14&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;piVersion&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; k&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ubeadm.k8s.io&#x2F;v1beta3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;15&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;k&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ind&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; I&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;nitConfiguration&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;16&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;odeRegistration&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;17&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  n&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ame&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ec2-10-100-0-1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;18&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  k&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ubeletExtraArgs&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;19&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;    n&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ode-ip&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;10.100.0.1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;20&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;    #&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Proposal: ether as an arg&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;21&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;    s&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;erverCertSANs&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;10.100.0.1,ec2-10-100-0-1.compute-1.amazonaws.com&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;22&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;  #&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Proposal: or as an own kubeadm nodeRegistration property&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;23&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  s&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;erverCertSANs&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;24&lt;&#x2F;span&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;10.100.0.1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;25&lt;&#x2F;span&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ec2-10-100-0-1.compute-1.amazonaws.com&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Personal I’m in favor of adding an extra arg to the kubelet binary to include a list of additional SANs. This would also allow profit users not using kubeadm to have a properly configured kubelet server certificate.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-workaround&quot;&gt;The Workaround:&lt;&#x2F;h3&gt;
&lt;p&gt;For personal testing setups I use ansible to prepare my nodes and bootstrab a cluster. One the certificate generation phase is complete I can generate my onw private key and certificate request and sing it with the clusters ca.
Though I don’t recommend this for production, this is why we need a more managed and automated approach.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;references&quot;&gt;References&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;kubernetes.io&#x2F;docs&#x2F;reference&#x2F;access-authn-authz&#x2F;kubelet-tls-bootstrapping&#x2F;#certificate-rotation&quot;&gt;Kubernetes Docs TLS Bootstrap&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;kubernetes.io&#x2F;docs&#x2F;setup&#x2F;production-environment&#x2F;tools&#x2F;kubeadm&#x2F;troubleshooting-kubeadm&#x2F;#cannot-use-the-metrics-server-securely-in-a-kubeadm-cluster&quot;&gt;Kubernetes Docs kubeadm troubleshoot tls&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;kubernetes-sigs&#x2F;metrics-server&#x2F;issues&#x2F;196&quot;&gt;GitHub metrics-server error - missing SANs&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;kubernetes&#x2F;kubernetes&#x2F;issues&#x2F;59372&quot;&gt;GitHub kubernetes node - missing SANs&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;kubernetes&#x2F;kubeadm&#x2F;issues&#x2F;1223&quot;&gt;GitHub kubernetes singed serving certificates &lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20230103134730&#x2F;https:&#x2F;&#x2F;old.reddit.com&#x2F;r&#x2F;kubernetes&#x2F;comments&#x2F;1028mw3&#x2F;kubeadm_join_add_ip_sans_to_kubelet&#x2F;&quot;&gt;Reddit - kubeadm not including SANs&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Using AWS from GitHub without Credentials</title>
        <published>2024-03-18T00:00:00+00:00</published>
        <updated>2024-03-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              hegerdes
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://henrikgerdes.me/blog/2024-03-aws-from-gh-actions/"/>
        <id>https://henrikgerdes.me/blog/2024-03-aws-from-gh-actions/</id>
        
        <content type="html" xml:base="https://henrikgerdes.me/blog/2024-03-aws-from-gh-actions/">&lt;h1 id=&quot;using-aws-from-github-without-credentials&quot;&gt;Using AWS from GitHub without Credentials&lt;&#x2F;h1&gt;
&lt;p&gt;AWS allows external services to authenticate without any secrets, which increases security and also reduces management overhead. There is no need to create, distribute, or rotate any secrets.&lt;&#x2F;p&gt;
&lt;p&gt;This short guide shows how to set up and use this federated identity concept.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pre-requirements&quot;&gt;Pre-Requirements&lt;&#x2F;h2&gt;
&lt;p&gt;To follow this guide, you need:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;A GitHub repo with read&#x2F;write access. We will use &lt;code&gt;my-org&#x2F;demo&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;A AWS account that can create roles.&lt;&#x2F;li&gt;
&lt;li&gt;This example will use &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.terraform.io&#x2F;&quot;&gt;terraform&lt;&#x2F;a&gt; for IaC deployments. Other tools or the WebUI should also work.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;configure-aws&quot;&gt;Configure AWS&lt;&#x2F;h2&gt;
&lt;p&gt;You need to configure your AWS account as an identity provider. This can be done via the &lt;code&gt;aws_iam_openid_connect_provider&lt;&#x2F;code&gt; resource or via the AWS console. To use that identity provider, you need to create a role (or use an existing one) and establish a trust relationship with that role and your GitHub repo. This can can be archived with a &lt;code&gt;iam_policy_document&lt;&#x2F;code&gt;. In terraform, this would look like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;hcl&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Get the identity provider arn&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;resource&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-enummember&quot;&gt; &amp;quot;aws_iam_openid_connect_provider&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-enummember&quot;&gt; &amp;quot;github&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  client_id_list&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;  =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;sts.amazonaws.com&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  thumbprint_list&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;1b511abead59c6ce207077c0bf0e0043b1382612&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  url&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;             =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;https:&#x2F;&#x2F;token.actions.githubusercontent.com&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Create iam trust policy with github repo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;data&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-enummember&quot;&gt; &amp;quot;aws_iam_policy_document&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-enummember&quot;&gt; &amp;quot;github_actions_assume_role&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;  statement&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    actions&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;sts:AssumeRoleWithWebIdentity&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;    principals&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;      #&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; GitHub identity provider&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;14&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;      type&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;        =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Federated&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;15&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;      identifiers&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;data&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;aws_iam_openid_connect_provider&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;github&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;arn&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;17&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;    condition&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;18&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;      test&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;     =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;StringLike&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;19&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;      variable&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;token.actions.githubusercontent.com:sub&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;20&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;      #&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; CHANGE ME: Set organization to my-org and to demo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;21&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;      values&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;   =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;repo:&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;var&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;organization&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;var&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;git_repo_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;:*&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;22&lt;&#x2F;span&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;23&lt;&#x2F;span&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;24&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;25&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;26&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Create role and assign iam_policy_document&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;27&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;resource&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-enummember&quot;&gt; &amp;quot;aws_iam_role&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-enummember&quot;&gt; &amp;quot;github_actions&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;28&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;               =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;github-actions-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;lower&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;var&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;organization&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;lower&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;var&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;git_repo_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;29&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  assume_role_policy&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; data&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;aws_iam_policy_document&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;github_actions_assume_role&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;json&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;30&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  tags&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;               =&lt;&#x2F;span&gt;&lt;span&gt; var&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;tags&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;31&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is all that is needed to use this identity on the AWS side. Most likely, you need additional permissions attached to your roles in order to deploy lambda functions, access S3 or push containers to ECR. Just create this polices and attach them to the role as you need.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;configure-github-actions&quot;&gt;Configure GitHub Actions&lt;&#x2F;h2&gt;
&lt;p&gt;Now we need GitHub Actions to log into AWS. For this, we create a workflow with this minimal configuration:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ame&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; D&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;emo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;on&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  p&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ush&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;    b&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ranches&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;m&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ain&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Minimal permissions needed&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;p&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ermissions&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  c&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ontents&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; r&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ead&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  i&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;d-token&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; w&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;rite&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;j&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;obs&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  b&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;uild-image&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;14&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;    r&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;uns-on&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; u&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;buntu-latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;15&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;    s&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;teps&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; n&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ame&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; C&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;heckout repository&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;17&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;        u&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ses&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; a&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ctions&#x2F;checkout@v4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;18&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;19&lt;&#x2F;span&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; n&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ame&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; C&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;onfigure AWS Credentials&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;20&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;        u&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ses&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; a&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ws-actions&#x2F;configure-aws-credentials@v4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;21&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;        w&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ith&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;22&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;          #&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Your region. Can be a var or hardcoded&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;23&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;          a&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ws-region&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;{{ vars.AWS_REGION }}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;24&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;          #&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Your role name you created previously&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;25&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;          r&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ole-to-assume&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;{{ secrets.AWS_ROLE }}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;26&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;27&lt;&#x2F;span&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; n&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ame&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; S&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;3 list&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;28&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;        r&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;un&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; a&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ws s3 ls MY_BUCKET&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;&#x2F;em&gt; When you use repo secrets&#x2F;vars you need to have maintainer or admin permissions for the GitHub repo. Yet, both values are not considered confidential.&lt;&#x2F;p&gt;
&lt;p&gt;Now you can run AWS commands in GitHub actions without having to set or manage any passwords or keys.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Comparing GitHub Actions with GitLab CI&#x2F;CD - A deep dive!</title>
        <published>2024-01-31T00:00:00+00:00</published>
        <updated>2024-01-31T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              hegerdes
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://henrikgerdes.me/blog/2024-01-github-action-vs-gitlab-ci/"/>
        <id>https://henrikgerdes.me/blog/2024-01-github-action-vs-gitlab-ci/</id>
        
        <content type="html" xml:base="https://henrikgerdes.me/blog/2024-01-github-action-vs-gitlab-ci/">&lt;h1 id=&quot;comparing-github-actions-with-gitlab-ci-cd&quot;&gt;Comparing GitHub Actions with GitLab CI&#x2F;CD&lt;&#x2F;h1&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;GitLab just announced the availability of their &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;about.gitlab.com&#x2F;blog&#x2F;2023&#x2F;12&#x2F;21&#x2F;introducing-the-gitlab-ci-cd-catalog-beta&#x2F;&quot;&gt;GitLab CI&#x2F;CD Catalog (2023&#x2F;12),&lt;&#x2F;a&gt; which states a perfect opportunity to compare the current state of the two CI&#x2F;CD systems of everyone’s favourite version control providers: GitLab CI &amp;amp; GitHub Actions.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Disclaimer:&lt;&#x2F;em&gt; While there are a lot of other CI&#x2F;CD systems like Circle CI, Azure DevOps, AWS CodeBuild, Travis CI and surprisingly, even Jenkins is still around, these tools are dedicated to solving one problem and are not part of a fully integrated developer platform. I also have not used most of them to a sufficient extent to be able to provide a meaningful review. This post only focuses on GitLab CI and GitHub Actions, especially their SaaS offerings, from a technical and software engineering standpoint. The value of these tools may vary depending on your specific requirements.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;2024-10-12 Update:&lt;&#x2F;em&gt; GitLab is working on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;handbook.gitlab.com&#x2F;handbook&#x2F;engineering&#x2F;architecture&#x2F;design-documents&#x2F;gitlab_steps&#x2F;&quot;&gt;step-runners&lt;&#x2F;a&gt; a more modular approach of running CI jobs. The existing of this project might give some insides of what GitLab thinks for its current CI design.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;img&#x2F;blog&#x2F;github-vs-gitlab-comic.png&quot; alt=&quot;Avengers style fight scene with GitHub OctoCat and GitLab mascot&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;general-ci-setup-flow&quot;&gt;General CI setup &amp;amp; flow&lt;&#x2F;h2&gt;
&lt;p&gt;GitHub Actions and GitLab both define their CI&#x2F;CD procedures using &lt;code&gt;yaml&lt;&#x2F;code&gt; files which will be parsed, templated&#x2F;interpolated, and processed by the CI&#x2F;CD task scheduler. In general, one or more jobs are created which run in one or more stages. By default, jobs within one stage run in parallel, while stages run in sequence.
Naturally, both GitHub Actions and GitLab have first-party integration support within their Git hosting platforms. While they can also be used to run tasks for Git repos hosted on a third-party service, it comes with limitations, often making it impractical. In fact, many triggers for the CI&#x2F;CD jobs are directly related to the Git repositories on which they perform these actions. While GitHub evaluates each file in &lt;code&gt;.github&#x2F;workflows&lt;&#x2F;code&gt; individually by checking if the emitted event matches one of the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.github.com&#x2F;en&#x2F;actions&#x2F;using-workflows&#x2F;events-that-trigger-workflows&quot;&gt;many workflow triggers&lt;&#x2F;a&gt; specified via the &lt;code&gt;on:&lt;&#x2F;code&gt; keyword, GitLab only has one CI file called &lt;code&gt;.gitlab-ci.yml&lt;&#x2F;code&gt;. Whereas this file can include separate CI configurations, GitLab always merges all definitions into a single monolithic file and evaluates on a job-by-job base if the job should be created and run or not.&lt;&#x2F;p&gt;
&lt;p&gt;GitHub has a lot of triggers for every imaginable event that might accrue within a GitHub repository. Workflows can be run when an issue is created, labelled, or a comment is added. GitLab, on the other hand, only has the predefined &lt;code&gt;CI_PIPELINE_SOURCE&lt;&#x2F;code&gt; variable which, in combination with other &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.gitlab.com&#x2F;ee&#x2F;ci&#x2F;variables&#x2F;predefined_variables.html&quot;&gt;predefined variables,&lt;&#x2F;a&gt; can be used to decide if a CI job is created. It does not support events like issues or comments. However, integration with external event sources is more flexible in GitLab CI with the choice of &lt;code&gt;API&lt;&#x2F;code&gt;, &lt;code&gt;Triggers&lt;&#x2F;code&gt; and chat, enabled by the direct integration support of various applications such as Slack. GitHub only allows to manually create CI jobs via the &lt;code&gt;workflow_dispatch&lt;&#x2F;code&gt; event, which can be triggered via the API or the WebUI. These and other differences also affect the way variables and tokens are used for these CI&#x2F;CD systems. Basic event triggers such as the &lt;code&gt;push&lt;&#x2F;code&gt; of a branch&#x2F;tag or &lt;code&gt;merge_requests&lt;&#x2F;code&gt; are supported by both systems.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;building-the-jobs&quot;&gt;Building the Jobs&lt;&#x2F;h2&gt;
&lt;p&gt;Based on the event and its values, the specified CI&#x2F;CD jobs get created. While the general declaration of a job definition is quite similar, the specification and execution of the actual commands are quite different. Each job has a name, a selector to specify the runner, variables and script or step property. Both systems also support a matrix property to run one job definition multiple times for different environments, runtime versions or operating systems. Users can reference variables, secrets and event values within a job definition. GitHub even allows the usage of a limited set of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.github.com&#x2F;en&#x2F;actions&#x2F;learn-github-actions&#x2F;expressions&quot;&gt;expressions&lt;&#x2F;a&gt; to compare, encode or alter the content of variables. It also includes an additional property to determine if a job should be run after evaluating the &lt;code&gt;on&lt;&#x2F;code&gt; property of a workflow file. GitLab only has one level of conditionals defined via it’s &lt;code&gt;rules&lt;&#x2F;code&gt; property.&lt;br &#x2F;&gt;
Every job can also specify dependencies on other jobs. The actual steps that the CI should run are specified differently depending on the system used:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;github-actions&quot;&gt;GitHub Actions&lt;&#x2F;h3&gt;
&lt;p&gt;GitHub Actions allows users to run an arbitrarily amount of action modules. An action is a (specific) reference to a other Git repository that performs a specific task within the CI. When a job is run, the action is checked out and runs its logic. From the users perspective, most actions are declarative, which allows users to utilize them without having to know their implementation details. Examples of actions include &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;marketplace&#x2F;actions&#x2F;setup-docker&quot;&gt;installing Docker&lt;&#x2F;a&gt; or &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;marketplace&#x2F;actions&#x2F;setup-minikube&quot;&gt;setting up Minikube&lt;&#x2F;a&gt;. GitHub has a huge &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;marketplace?type=actions&quot;&gt;marketplace&lt;&#x2F;a&gt; of official and community actions. Users can customize the behavior of actions by passing input arguments to them. This approach allows for great reuse of tasks, a low entry barrier, and lean CI configurations.&lt;br &#x2F;&gt;
Besides the marketplace actions users can also use a generic &lt;code&gt;run&lt;&#x2F;code&gt; action, which accepts any shell code, allowing any generic imperative commands. In addition to Bash and PowerShell, it is also possible to directly use Python, JavaScript and other interpreted languages. In addition to workflow control and job control, each step has an optional parameter to determine if the step should be executed.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; GitHub Action example workflow&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ame&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; E&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;xample Pipeline&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;on&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  p&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ull_request&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;    b&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ranches&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;releases&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  p&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ush&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;    b&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ranches&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;m&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ain&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;j&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;obs&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  c&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ode-style&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;    r&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;uns-on&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; u&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;buntu-latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;    s&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;teps&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;14&lt;&#x2F;span&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; n&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ame&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; c&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;heckout&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;15&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;      u&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ses&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; a&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ctions&#x2F;checkout@v4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;16&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;17&lt;&#x2F;span&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; n&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ame&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; I&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;nfo for main branch&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;18&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;      i&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;f&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; g&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ithub.ref == &amp;#39;refs&#x2F;heads&#x2F;main&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;19&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;      r&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;un&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; e&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;cho &amp;quot;Running tests in main&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;20&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;21&lt;&#x2F;span&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; u&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ses&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; a&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ctions&#x2F;setup-python@v5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;22&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;      w&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ith&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;23&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;        p&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ython-version&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;3.11&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;24&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;25&lt;&#x2F;span&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; u&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ses&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; h&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ashicorp&#x2F;setup-terraform@v3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;26&lt;&#x2F;span&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; u&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ses&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; t&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;erraform-linters&#x2F;setup-tflint@v4.0.0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;27&lt;&#x2F;span&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; u&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ses&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; p&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;re-commit&#x2F;action@v3.0.0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;gitlab-ci&quot;&gt;GitLab CI&lt;&#x2F;h3&gt;
&lt;p&gt;GitLab has three different run stages: &lt;code&gt;before_script&lt;&#x2F;code&gt;, &lt;code&gt;script&lt;&#x2F;code&gt; and &lt;code&gt;after_script&lt;&#x2F;code&gt;. Each stage allows a list of shell commands and can execute everything a script could. The &lt;code&gt;after_script&lt;&#x2F;code&gt; is always executed, even if previous steps errored. Allowing users to send webhooks, perform error handling and print debug messages. Reusing these scripts is possible via inheriting from an existing job, extending from an existing job, or using the &lt;code&gt;!reference&lt;&#x2F;code&gt; tag which allows using commands specified somewhere else. All commands have to be imperative shell instructions, which requires users to carefully construct every task they want to perform themselves.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; GitLab CI Pipeline example&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;t&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ags&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;d&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ocker&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;v&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ariables&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  M&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;Y_GLOBAL_VAR&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; F&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;oo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  G&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;IT_DEPTH&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; include:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt;   - template: Terraform.latest.gitlab-ci.yml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt;   - template: Security&#x2F;SAST.gitlab-ci.yml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;B&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;uild-Image-Buildah-Template&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  i&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;mage&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; r&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;egistry.access.redhat.com&#x2F;ubi8&#x2F;buildah:latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;14&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  s&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;tage&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; b&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;uild&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;15&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  v&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ariables&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;16&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;    R&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;EGISTRY&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;{CI_REGISTRY}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;17&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;    R&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;EGISTRY_USER&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;{CI_REGISTRY_USER}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;18&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;    R&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;EGISTRY_PASS&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;{CI_REGISTRY_PASSWORD}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;19&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;    C&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ONTEXT&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;CI_PROJECT_DIR&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;20&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;    B&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;UILD_IMAGE_TAG&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;21&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;    D&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;OCKERFILE&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;CONTEXT&#x2F;Dockerfile&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;22&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  s&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;cript&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;23&lt;&#x2F;span&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; b&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;uildah login -u &amp;quot;${CI_REGISTRY_USER}&amp;quot; -p &amp;quot;${CI_REGISTRY_PASSWORD}&amp;quot; &amp;quot;${CI_REGISTRY}&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;24&lt;&#x2F;span&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;25&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;        buildah bud --pull \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;26&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;          --build-arg COMMIT_HASH=$CI_COMMIT_SHORT_SHA \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;27&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;          --build-arg COMMIT_TAG=$CI_COMMIT_REF_NAME \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;28&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;          --tag &amp;quot;${BUILD_IMAGE_TAG}&amp;quot; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;29&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;          --file ${DOCKERFILE} ${CONTEXT}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;30&lt;&#x2F;span&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; b&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;uildah push --creds &amp;quot;${REGISTRY_USER}:${REGISTRY_PASS}&amp;quot; &amp;quot;${BUILD_IMAGE_TAG}&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;31&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  r&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ules&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;32&lt;&#x2F;span&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; i&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;f&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;CI_PIPELINE_SOURCE == &amp;quot;schedule&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;33&lt;&#x2F;span&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; i&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;f&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;CI_PIPELINE_SOURCE == &amp;quot;push&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;34&lt;&#x2F;span&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; !reference&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;global&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; d&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;efault_rules&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;differences&quot;&gt;Differences&lt;&#x2F;h3&gt;
&lt;p&gt;GitHub’s prebuild actions allow for an easy-to-use and quickly configured CI. They are great for reusability and the abstraction of low-level tasks. However, users and organizations must keep in mind that actions in the community marketplace is code written by others. It is recommended to check all actions before using them and to pin their reference to a specific commit to prevent supply chain attacks. GitLab’s approach requires more effort upfront and a deeper knowledge about every step in the setup to perform. While GitLab also allows reusing jobs, it is not as powerful as the later sections will show. The fine-grained and clear structure of GitHub Actions, that determines whether a workflow, job, or step should be executed is an advantage over the monolithic approach of GitLab.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;reusing-ci-configurations&quot;&gt;Reusing CI Configurations&lt;&#x2F;h2&gt;
&lt;p&gt;GitHub Actions allow for great usability at the task level, as the previous section already showed. However, CI jobs are rarely constructed of just on step. Most jobs include checking out the code, installing the language runtime, downloading build dependencies and performing some checks. A Docker build job is almost always the same, just like security scans. They just need some arguments that point to the source and parameters for the output artifact. In an organization, it might be desirable to share these common build steps to keep it &lt;em&gt;DRY&lt;&#x2F;em&gt; and reduce code hygiene maintenance. This would also assure that all jobs are compliant with internal standards and policies.&lt;br &#x2F;&gt;
GitHub Actions offer &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.github.com&#x2F;en&#x2F;actions&#x2F;using-workflows&#x2F;reusing-workflows&quot;&gt;reusable workflows,&lt;&#x2F;a&gt; which are GitHub Action workflow files that can be called from any other project. These reusables define one or more jobs and offer inputs to customize how the included jobs are run. Being built on Git, these workflow files are versioned and can be pinned to a specific commit.&lt;br &#x2F;&gt;
For GitLab, the story is a little more complicated. GitLab uses a monolith &lt;code&gt;.gitlab-ci.yml&lt;&#x2F;code&gt; file in which all jobs are defined. But the jobs don’t have to be declared within that file. They can be included from another project or any other file that is accessible via HTTP from the GitLab instance. In general, there are two types of &lt;code&gt;includes&lt;&#x2F;code&gt; in GitLab, both can have multiple nested includes of their own. There is the generic include of any other job definition file that is offered by a shared repository or a third-party entity. The second type is the official &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;gitlab.com&#x2F;gitlab-org&#x2F;gitlab&#x2F;-&#x2F;tree&#x2F;master&#x2F;lib&#x2F;gitlab&#x2F;ci&#x2F;templates&quot;&gt;GitLab CI&#x2F;CD template&lt;&#x2F;a&gt; type. These templates are common CI&#x2F;CD jobs that are directly provided by GitLab and come with every GitLab installation. Both types do not provide the possibility of directly passing inputs to the included jobs. All customizations must be done via GitLab’s CI&#x2F;CD variables or by explicitly overriding the job to fit the desired needs. To apply these customizations, it is often necessary to look at the source of a specific job, which might be defined in multiple levels of nested includes.&lt;br &#x2F;&gt;
On December 21, 2023, GitLab announced the beta availability of the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;about.gitlab.com&#x2F;blog&#x2F;2023&#x2F;12&#x2F;21&#x2F;introducing-the-gitlab-ci-cd-catalog-beta&#x2F;&quot;&gt;GitLab CI&#x2F;CD Catalog (2023&#x2F;12)&lt;&#x2F;a&gt;. This feature enables a third type of job inclusion into the &lt;code&gt;.gitlab-ci.yml&lt;&#x2F;code&gt;. It provides a community store where every user can create their own definitions for one or more jobs. Anyone can include these components and customize them via a series of inputs. Consumers just need to look at the component page of the catalog item to get a list of all available inputs and further documentation. It’s a much cleaner interface between the provider and consumer of a job. Just like it is with GitHub Actions on the individual task level. The difference is that these catalog items still don’t let users fully alter any jobs on the individual task level. The components include whole jobs and are therefore more similar to GitHub’s reusable workflows than GitHub’s Action. A list of already available GitLab CI&#x2F;CD Components can be found &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;gitlab.com&#x2F;explore&#x2F;catalog&quot;&gt;here&lt;&#x2F;a&gt;.&lt;br &#x2F;&gt;
Creating your own component is quite easy. GitLab requires a specific repository layout and a label on the project to specify it as a CI&#x2F;CD Component. With GitLab releases, a new version of that component is created. To test this new functionality, I created &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;gitlab.com&#x2F;hegerdes&#x2F;gitlab-actions&quot;&gt;my own component&lt;&#x2F;a&gt; that builds Docker images with Googles kaniko builder (which does not require Docker in Docker) and automatically applies some common OCI spec labels. Feel free to check it out.&lt;br &#x2F;&gt;
&lt;em&gt;NOTE:&lt;&#x2F;em&gt; Just like third-party GitHub Actions, before using a third-party component, it should be verified and pinned to an exact version.&lt;&#x2F;p&gt;
&lt;p&gt;While the CI&#x2F;CD Components are a step towards a more user-friendly and reusable CI code, they still don’t offer fine-grained control. GitHub’s conditional controls on workflow, job and step level offer a much more flexible setup and expose a cleaner solution than GitLab by including, merging, extending and overriding jobs from many sources. The complete &lt;code&gt;.gitlab-ci.yml&lt;&#x2F;code&gt; file with all overrides, references and includes applied can be viewed in GitLab’s pipeline editor. However, due to the multiple inclusions, this file can quickly become a few thousand lines long and is not very user-friendly to read.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;runners&quot;&gt;Runners&lt;&#x2F;h2&gt;
&lt;p&gt;To run the defined CI&#x2F;CD jobs, both GitHub and GitLab need runners. Both services offer &lt;em&gt;Hosted Runners&lt;&#x2F;em&gt; that are owned and maintained by the respective provider (SaaS offering). Each provider offers a free plan for their CI&#x2F;CD runners, which includes a certain amount of compute minutes. The table below shows a brief, none complete overview of their offerings.&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Plan&lt;&#x2F;th&gt;&lt;th&gt;Included Minutes&lt;&#x2F;th&gt;&lt;th&gt;Price&lt;&#x2F;th&gt;&lt;th&gt;Cost per minute&#x2F;per core for additional minutes&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;GitHub Free&lt;&#x2F;td&gt;&lt;td&gt;2000&lt;&#x2F;td&gt;&lt;td&gt;0$&lt;&#x2F;td&gt;&lt;td&gt;0.004$*&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;GitHub Pro&lt;&#x2F;td&gt;&lt;td&gt;3000&lt;&#x2F;td&gt;&lt;td&gt;4$&lt;&#x2F;td&gt;&lt;td&gt;0.004$*&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;GitLab Free&lt;&#x2F;td&gt;&lt;td&gt;400&lt;&#x2F;td&gt;&lt;td&gt;0$&lt;&#x2F;td&gt;&lt;td&gt;0.005$*&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;GitLab Pro&lt;&#x2F;td&gt;&lt;td&gt;10.000&lt;&#x2F;td&gt;&lt;td&gt;29$&lt;&#x2F;td&gt;&lt;td&gt;0.005$*&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;&#x2F;em&gt; Cost per minute is for extra minutes that exceed the included minutes. It is calculated based on available price information.&lt;&#x2F;p&gt;
&lt;p&gt;This table is not representative of real-world costs because both providers offer a variety of different runner sizes with different operating systems. Based on the size and operating system (OS), there is a cost multiplier that is factored in for every real compute minute consumed. The numbers in the table are for the default (smallest) runners based on a Linux system. For specific use cases, please refer to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.github.com&#x2F;en&#x2F;billing&#x2F;managing-billing-for-github-actions&#x2F;about-billing-for-github-actions&quot;&gt;GitHub’s pricing docs&lt;&#x2F;a&gt; or &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.gitlab.com&#x2F;ee&#x2F;ci&#x2F;pipelines&#x2F;cicd_minutes.html&quot;&gt;GitLab’s pricing docs&lt;&#x2F;a&gt;.&lt;br &#x2F;&gt;
Both providers offer Linux, macOS and Windows runners. At the time of writing, GitLab’s offerings for macOS and Windows are still in beta.
GitHub’s runners are hosted on the Azure Cloud using the &lt;code&gt;Standard_DS2_v2&lt;&#x2F;code&gt; series VMs and GitLab’s runners are hosted on Google Compute Platform (GCP) using the &lt;code&gt;n2d_machines&lt;&#x2F;code&gt; series. Both runner offerings are hosted in the US only currently, which may have an impact on latency and can interfere with privacy constraints.&lt;br &#x2F;&gt;
The architecture of both CI&#x2F;CD systems envisions that the available runners continuously communicate with the GitHub&#x2F;GitLab instance and process jobs from their task queue. Only the GitHub&#x2F;GitLab instances has to be accessible by the runners, the runners themselves don’t need to be exposed to the internet. This can be important for certain restrictive network topologies. While the CI&#x2F;CD job scheduling is quite similar, there are some differences between GitHub and GitLab in how the jobs are executed.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;github-runners&quot;&gt;GitHub runners&lt;&#x2F;h3&gt;
&lt;p&gt;When an event that triggers a workflow is emitted, the defined jobs within the workflow get templated (using lazy templating) and are added to the job queue. Available GitHub runners that match the &lt;code&gt;runs-on&lt;&#x2F;code&gt; tag automatically pick up queued jobs and execute them on a fresh VM provisioned just for that job. The GitHub provided VMs come preinstalled with a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;actions&#x2F;runner-images&#x2F;blob&#x2F;main&#x2F;images&#x2F;ubuntu&#x2F;Ubuntu2204-Readme.md&quot;&gt;lot of tools&lt;&#x2F;a&gt; to allow for fast execution of the jobs. It essentially runs shell commands directly on the host, even if the actual commands are abstracted by the GitHub Action modules. Each step gets individually templated, which allows users to pass values from one step or job to another using a special &lt;code&gt;GITHUB_OUTPUT&lt;&#x2F;code&gt; variable. These values do not have to be known before a job starts, they can be obtained and computed during job execution.&lt;br &#x2F;&gt;
The command outputs of jobs are streamed back to the GitHub instance, accessible via the GitHub UI in a shell-like output canvas. The output is near real-time, but the canvas can not be reliably searched via &lt;code&gt;Ctrl-F&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;gitlab-runners&quot;&gt;GitLab runners&lt;&#x2F;h3&gt;
&lt;p&gt;The &lt;code&gt;.gitlab-ci.yml&lt;&#x2F;code&gt; gets fully templated and merged every time there is a CI triggering event. If the &lt;code&gt;rules&lt;&#x2F;code&gt; section of a job matches the triggering event, it gets added to the job queue. GitLab uses &lt;code&gt;tags&lt;&#x2F;code&gt; to specify an attribute or a list of attributes that the runner must have in order to run the job. An example would be &lt;code&gt;tags: [linux, large]&lt;&#x2F;code&gt;, where the runner must have at least these tags.&lt;br &#x2F;&gt;
GitLab’s runners can have different executors, which determine how the user-defined job gets executed. The supported executors are Shell, SSH, VirtualBox, Docker, Kubernetes and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.gitlab.com&#x2F;runner&#x2F;executors&#x2F;&quot;&gt;some more&lt;&#x2F;a&gt;. Each executor comes with some advantages and disadvantages. The Shell and SSH executors directly run on the specified machine. Users must make sure that every build dependency is either already installed on the machine or is included in the job script section. These executors change the host filesystem and are not idempotent, which can lead to a lack of reproducibility and unexpected behaviour. Therefore, the use of a virtualized executor is often preferred. Docker and Kubernetes use the container image specified in the &lt;code&gt;image&lt;&#x2F;code&gt; tag and run all scripts within that container. When the job is finished, the container gets deleted and the host system is in the same state as before.&lt;br &#x2F;&gt;
Currently, GitLab’s SaaS runners use the &lt;code&gt;Docker+Machine&lt;&#x2F;code&gt; executor, a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;gitlab.com&#x2F;gitlab-org&#x2F;ci-cd&#x2F;docker-machine&quot;&gt;GitLab maintained fork&lt;&#x2F;a&gt; of the deprecated Docker Machine project. These executors spawn new Google Cloud VMs with Docker installed to run the specified container image and execute all job scripts. At the time of writing, GitLab is working on replacing this executor with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;gitlab.com&#x2F;gitlab-org&#x2F;gitlab&#x2F;-&#x2F;issues&#x2F;341856&quot;&gt;an alternative&lt;&#x2F;a&gt;.&lt;br &#x2F;&gt;
While these executors are idempotent, they have some drawbacks when users want to perform some low-level system actions or need to use virtualisation themselves, resulting in nested virtualisation. Running container builds in the GitLab CI often requires the use of Docker in Docker, resulting in bind-mount of the Docker Socket and slower build performance, unless tools like &lt;em&gt;kaniko&lt;&#x2F;em&gt; or &lt;em&gt;buildah&lt;&#x2F;em&gt; are used. Variables between jobs can be passed to each other by writing them to a file and passing these artefacts between jobs.&lt;br &#x2F;&gt;
The script outputs are also sent back to the GitLab instance in periodic chunks. The resulting log in the UI is fully searchable. Other than GitHub, GitLab automatically downloads the Git repository at the ref specified in the event that triggered the job, unless it’s explicitly turned off. If artefacts were defined in the job, they also get automatically up and downloaded. GitLab also offers a wider set of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.gitlab.com&#x2F;ee&#x2F;ci&#x2F;variables&#x2F;predefined_variables.html&quot;&gt;predefined variables&lt;&#x2F;a&gt; that users can access while the jobs executes.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;comparison&quot;&gt;Comparison&lt;&#x2F;h3&gt;
&lt;p&gt;The execution of jobs is quite different between GitHub and GitLab. While the GitLab solution seems more complex at first glance, knowledge of its runner architecture is not required by developers. Only for GitLab admins who implement their own runners need to know the details in order to decide for an appropriate executor. Depending on the size of the organization, a simple Docker or Kubernetes executor should cover most use cases for a CI&#x2F;CD runner. GitHub also allows users to bring their own, self-hosted runners, which just like GitLab will not be billed (at least not by GitHub&#x2F;GitLab). Own runners allow for better confidentiality between own jobs and the jobs of others, have consistent performance and meet specific requirements such as CPU architecture and GPU support. It also allows overcoming network borders by placing the runner inside restricted network segments to allow for communication with services that are not publicly accessible. Own runners might also be needed to overcome latency issues, since currently both GitHub’s and GitLab’s runners are located in the US.&lt;br &#x2F;&gt;
GitHub’s runners allow for more flexible usage by just being a VM that is owned by you during the duration of the job, while GitLab’s runners might be orientated more towards one specific use case. GitLab’s runners automatically check out the code and manage artefacts distribution for the user. If the right container image is chosen, there it literally no need to install anything since all tools are already the present in container.&lt;br &#x2F;&gt;
Both runners should be able to fulfil most requirements, users should just be aware of the respective limitations regarding location, availability, CPU architecture and other feature and properties like cost. It must be mentioned that self-hosted runners can run more than one job per host concurrently, depending on the configuration. Due to privacy concerns, this feature is not enabled for hosted&#x2F;SaaS runners.&lt;br &#x2F;&gt;
A performance comparison is intentionally not part of this comparison, since there are too many variables and influences present for any meaningful results.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;security-and-secrets&quot;&gt;Security and Secrets&lt;&#x2F;h2&gt;
&lt;p&gt;Both GitHub and GitLab allow users to set variables and secrets that are then available in their CI&#x2F;CD runtime. Both input types can be set at the instance, group&#x2F;organization, project level, and even per registered deployment environment. Secrets are special variables that are considered confidential, these will be masked by the CI system if they are found in the output log. GitLab allows users with the appropriate permissions to view the value of a secret after it has been set, while GitHub never shows the value again. Regarding security, this makes no real difference, as anyone with access to the CI files can output the secrets when executing a job. While the secret values will be masked, this safety mechanism can easily be bypassed by reversing and base64 encoding the value before they get written to the log. Therefore, the general recommendation is the usage of short-lived tokens.&lt;br &#x2F;&gt;
For project-related resources, both CI systems use such a short-lived token to access the code stored in Git, upload artifacts or create releases. The &lt;code&gt;GITHUB_TOKEN&lt;&#x2F;code&gt; or GitLab’s &lt;code&gt;CI_JOB_TOKEN&lt;&#x2F;code&gt; is only valid during the execution of the job. The permissions for these tokens can be limited. GitLab allows altering the permissions of users, they can be limited to a specific scope and certain actions. The &lt;code&gt;CI_JOB_TOKEN&lt;&#x2F;code&gt; will inherent the permissions of the user that triggered the CI job. However, when a CI job runs, this token is accessible, with its specific permissions, for all jobs and tasks within these jobs.&lt;br &#x2F;&gt;
GitHub on the other hand, allows for a more &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.github.com&#x2F;en&#x2F;actions&#x2F;security-guides&#x2F;automatic-token-authentication#permissions-for-the-github_token&quot;&gt;fine-grained permission&lt;&#x2F;a&gt; model for its token. These permissions can also be defined at the workflow or job level. Unlike GitLab, GitHub does not make its token accessible for every step in the CI flow by default. Creating a release via GitHub Actions requires access to the GitHub release API with a valid token, downloading public dependencies or compiling code does not require any tokens. Only steps that request access to the token or are explicitly given access via the &lt;code&gt;${{ secrets.GITHUB_TOKEN }}&lt;&#x2F;code&gt; parameter can use that token. The default untrustworthy approach makes a lot of sense since users are much more likely to use third-party actions in their CI, which is code written by strangers. Before the introduction of the GitLab CI&#x2F;CD catalog, most CI code in GitLab was owned by the project owners or their organization.&lt;br &#x2F;&gt;
GitHub defaults to the least privilege solution with less trust at every step, where access can be given only if required. Organizations can enforce an even more permissive permission scope for the &lt;code&gt;GITHUB_TOKEN&lt;&#x2F;code&gt; and can also limit the allowed GitHub Actions to internal or whitelisted ones in order to meet company compliance policies. GitLab does not currently support such a feature out of the box. Instead, GitLab allows users to extend the permissions of its &lt;code&gt;CI_JOB_TOKEN&lt;&#x2F;code&gt; to access additional Git repositories. In a multi repository&#x2F;microservice project, this results in a smaller number of user-managed tokens. To access multiple private repos in GitHub, users need to create their own token since the &lt;code&gt;GITHUB_TOKEN&lt;&#x2F;code&gt; currently does not support such a feature and is only valid for the current repository.
Both services encourage the use of short-lived tokens or external secret solutions. GitLab has first-party support with HashiCorp Vault to use external secrets. Besides this, both GitHub and GitLab act as an &lt;em&gt;Identity-Provider&lt;&#x2F;em&gt; (IDP) to allow the usage of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;openid.net&#x2F;developers&#x2F;how-connect-works&#x2F;&quot;&gt;OpenID Connect (OIDC)&lt;&#x2F;a&gt; to offer secure communication with the three major cloud providers using short-lived tokens. Depending on the configurations, this allows users to access and manage cloud resources in the CI&#x2F;CD by using a trust relationship rather than any explicit credentials. GitLab builds this functionality directly into their CI&#x2F;CD system, while GitHub relies on GitHub Actions like &lt;code&gt;configure-aws-credentials&lt;&#x2F;code&gt; or &lt;code&gt;azure-login&lt;&#x2F;code&gt;.&lt;br &#x2F;&gt;
A useful extra feature that GitLab does not have is the ability to add secret masks while the CI is already running. Especially when using short-lived access tokens, which the CI cannot know in advance, it is helpful to use &lt;code&gt;echo &quot;::add-mask::MY_TOKEN&quot;&lt;&#x2F;code&gt; to prevent unwanted exposure in logs.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;additional-functionality-services&quot;&gt;Additional Functionality &amp;amp; Services&lt;&#x2F;h2&gt;
&lt;p&gt;Running predefined tasks when a specific event is triggered is the core functionality of a CI&#x2F;CD system, but requirements and competition in the CI&#x2F;CD world are constantly increasing. Having functionality that makes the lives of developers easier might be a major selling point. These following functions were not considered in the previous comparison, but should be mentioned for a complete picture of GitHub Actions and GitLab CI.&lt;br &#x2F;&gt;
Both GitHub Actions and GitLab CI can run additional services besides the main CI tasks. These services are defined as containers that can offer a database or local web server within the CI job. This can allow users to run integration tests within the CI. A job can perform a database migration test on an ephemeral DB or an end-to-end test with playwright against a temporary hosted website, all within a CI job.&lt;br &#x2F;&gt;
Project documentation or a static website can be hosted on GitHub and GitLab using their &lt;em&gt;Pages&lt;&#x2F;em&gt; feature. Both CI&#x2F;CD systems can build and directly deploy HTML sites to their page environments without the need for any extra authentication.&lt;br &#x2F;&gt;
To speed up tests and build jobs, both systems support caches. GitHub has official actions to upload and download caches, while GitLab offers the &lt;code&gt;cache&lt;&#x2F;code&gt; keyword and manages uploading and downloading caches as part of the job initialisation.&lt;br &#x2F;&gt;
When all test succeeded, software packages can be deployed to one or more environments. Both systems offer a &lt;code&gt;environment&lt;&#x2F;code&gt; keyword. Every job that references an environment creates a deployment in that environment. Environments can have their own set of variables and secrets to allow stricter separation between them for increased security. A link to a successful deployment is then shown on the repository or pull request UI. GitHub requires users to create environments beforehand. GitLab can dynamically create environments based on supplied variables, like the branch name. Furthermore, GitLab also has different actions for environments to create, access and delete them on demand. Environments can even be automatically removed after a certain time or after a pull request gets merged. Compared to GitHub, GitLab’s environments are definitely more advanced and versatile. For Kubernetes users, GitLab offers its optional &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.gitlab.com&#x2F;ee&#x2F;user&#x2F;clusters&#x2F;agent&#x2F;&quot;&gt;GitLab Agent&lt;&#x2F;a&gt; to access the insides of a cluster without any additional tokens. The agent gets deployed within a cluster and communicates with a GitLab instance, allowing it to be accessed via the CI.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;overall-comparison&quot;&gt;Overall Comparison&lt;&#x2F;h2&gt;
&lt;p&gt;GitHub Actions and GitLab CI are two very powerful CI&#x2F;CD systems that allow users to automate almost every imaginable task within the software development life cycle. At a functional level, both systems are on a similarly equal level, but the way they are implemented differs significantly.&lt;br &#x2F;&gt;
GitHub offers a stable, versatile and modular platform to run almost every kind of imaginable task. It integrates seamlessly with every one of GitHub’s features. Where needed, it allows for integration with standard solutions, such as the ability to run containers or authenticate with third-party services over OIDC. It relies heavily on its vast marketplace of official and community actions, which do most of the actual work, such as checking out code, installing software, using caches or publishing releases. GitHub also gives fine-grained control over security-related settings, which can be enforced to be significantly more permissive than its competitor, GitLab.&lt;br &#x2F;&gt;
GitLab on the other hand, provides a much more managed solution for its users. It is part of the CI&#x2F;CD system to check out code, manage caches and releases. It directly integrates with Vault and major cloud providers. GitLab itself also seems to allow for easier integration with third-party systems. CI triggers from external services like issue trackers and chat tools are much more versatile, just like the CI environment setup. But GitLab requires the user to write all the CI task implementations themselves. Sharing and reusing CI definitions becomes difficult and quickly confusing with the monolithic approach of one big &lt;code&gt;.gitlab-ci.yml&lt;&#x2F;code&gt; file approach. There are multiple levels of including, inherence and extending which can make it hard to get a quick oversight of what a job actually does. Eventually, this might get better with GitLab’s new CI&#x2F;CD catalog, but this is not guaranteed since components compare much more to GitHub’s reusable workflows instead of individual actions. GitLab is definitely in the middle of a migration process regarding their CI, not just to allow it to be more reusable, but also to get rid of their &lt;code&gt;docker+machine&lt;&#x2F;code&gt; runners. In contrast to GitHub’s modular approach, GitLab seems to have to deal with significantly more historical challenges due to its more managed approach. From a software engineering perspective, GitHub’s design might be the more beneficial long-term position because their modular approach allows them to add features without many legacy impediments.
There is no clear recommendation for one or the other system. Both are more than capable of running any imaginable task. The requirements for the actual development Platform, GitHub and GitLab, should be much more important than its CI features. Costs and data privacy, as well as the ability to self-host, are often more relevant factors than the differences between the CI&#x2F;CD systems.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;i.imgur.com&#x2F;b6THgdq.png&quot; alt=&quot;OctoCar vs Octo Logo GitLab&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Building preconfigured OS images with HashiCorp Packer</title>
        <published>2023-12-12T00:00:00+00:00</published>
        <updated>2023-12-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              hegerdes
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://henrikgerdes.me/blog/2023-12-hetzner-packer/"/>
        <id>https://henrikgerdes.me/blog/2023-12-hetzner-packer/</id>
        
        <content type="html" xml:base="https://henrikgerdes.me/blog/2023-12-hetzner-packer/">&lt;h1 id=&quot;building-preconfigured-os-images-with-packer&quot;&gt;Building preconfigured OS images with Packer&lt;&#x2F;h1&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;Hetzner Cloud provides a number of different operating system images to select from when creating a new virtual machine. These images provide the basic ground to get started with your service, but they are rarely configured according to your specific needs. Maybe you want to install a database or a web server, add a maintenance user, or just tweak system settings to improve performance and security. While there are tools to do this automatically for every new VM, this takes time and may not always be reproducible. Wouldn’t it be easier to have your own known good personal pre-configured OS image that you can use for every new VM?&lt;&#x2F;p&gt;
&lt;p&gt;This can be archived with HashiCorp Packer.&lt;&#x2F;p&gt;
&lt;p&gt;This article demonstrates how to use Packer to create custom images for your Hetzner VMs using Infrastructure as Code (IaC). It even allows users to create VMs with operating systems that are not officially supported by Hetzner.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;&#x2F;em&gt; This article was also published on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;community.hetzner.com&#x2F;tutorials&#x2F;custom-os-images-with-packer&quot;&gt;Hetzner’s Community Blog&lt;&#x2F;a&gt;
&lt;img src=&quot;&#x2F;img&#x2F;blog&#x2F;software-packaging.jpeg&quot; alt=&quot;software-packaging.jpeg&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Prerequisites&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;To follow this tutorial, you need:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Hetzner Cloud &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.hetzner.com&#x2F;cloud&#x2F;api&#x2F;getting-started&#x2F;generating-api-token&quot;&gt;API token&lt;&#x2F;a&gt; in the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;console.hetzner.cloud&#x2F;&quot;&gt;Cloud Console&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Access to the Internet&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;installing-packer&quot;&gt;Installing Packer&lt;&#x2F;h2&gt;
&lt;p&gt;Visit &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;developer.hashicorp.com&#x2F;packer&#x2F;install&quot;&gt;Hashicorp Packer&lt;&#x2F;a&gt; and install Packer according to your OS.&lt;br &#x2F;&gt;
On Debian based Linux, run:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Get the latest version&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;curl&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;sL&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; https:&#x2F;&#x2F;api.github.com&#x2F;repos&#x2F;hashicorp&#x2F;packer&#x2F;releases&#x2F;latest&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; jq&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;r&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; .tag_name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Set the version and download&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;4&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;PACKER_VERSION&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;5&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;curl&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;sL&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; https:&#x2F;&#x2F;releases.hashicorp.com&#x2F;packer&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;$&lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;PACKER_VERSION&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;packer_&lt;&#x2F;span&gt;&lt;span&gt;$&lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;PACKER_VERSION&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;_linux_amd64.zip&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;o&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;tmp&#x2F;packer.zip&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;6&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Unzip - may needs sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;7&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;unzip&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;q&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;tmp&#x2F;packer.zip&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;d&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;usr&#x2F;local&#x2F;bin&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;LICENSE.txt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can run &lt;code&gt;packer --version&lt;&#x2F;code&gt; to view the version and check if the installation was successful.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;creating-a-custom-image&quot;&gt;Creating a custom image&lt;&#x2F;h2&gt;
&lt;p&gt;Create a project folder with &lt;code&gt;mkdir my-hetzner-img&lt;&#x2F;code&gt; and enter the directory.&lt;br &#x2F;&gt;
Similar to Terraform, Packer uses providers to communicate with the needed build system. The usage of different providers allows Packer to offer a vast verity of different target systems. It allows users to create software or OS packages for all major cloud providers, on-prem systems and even Docker images.&lt;br &#x2F;&gt;
To use a provider, create a file called &lt;code&gt;provider.pkr.hcl&lt;&#x2F;code&gt; and add the provider config:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;hcl&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; packer.pkr.hcl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;packer&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;  required_plugins&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    hcloud&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;      source&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;  =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;github.com&#x2F;hetznercloud&#x2F;hcloud&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;      version&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;gt;= 1.2.0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Packer uses the HashiCorp configuration language (HCL) for declaring the desired state, just like Terraform.&lt;&#x2F;p&gt;
&lt;p&gt;To create a personalized custom image, Packer needs a base form where it starts from. This is called the “source”:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;hcl&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; custom-img-v1.pkr.hcl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;source&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-enummember&quot;&gt; &amp;quot;hcloud&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-enummember&quot;&gt; &amp;quot;base-amd64&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  image&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;         =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;debian-12&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  location&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;      =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;nbg1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  server_type&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;   =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;cx11&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  ssh_keys&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;      =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  user_data&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;     =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  ssh_username&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;  =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;root&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  snapshot_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;custom-img&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  snapshot_labels&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    base&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;    =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;debian-12&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    version&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;v1.0.0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;    =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;custom-img&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;14&lt;&#x2F;span&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;15&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This tells Packer where to start. In the case of Hetzner, Packer needs to know the base image, the server type to use for building, and the location of that server. It also specifies the name of the Snapshot that will be created and the tags that should be applied to that server.&lt;&#x2F;p&gt;
&lt;p&gt;The next step is to provide your customization. Meaning the actual build step.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;hcl&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; custom-img-v1.pkr.hcl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;build&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  sources&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;source.hcloud.base-amd64&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;  provisioner&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-enummember&quot;&gt; &amp;quot;shell&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    inline&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;apt-get update&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;apt-get install -y wget fail2ban cowsay&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;usr&#x2F;games&#x2F;cowsay &amp;#39;Hi Hetzner Cloud&amp;#39; &amp;gt; &#x2F;etc&#x2F;motd&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span&gt;    ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    env&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;      BUILDER&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;packer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;&#x2F;span&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;14&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It uses the source specified before and specifies a &lt;code&gt;shell&lt;&#x2F;code&gt; provisioner. Every line in &lt;code&gt;inline&lt;&#x2F;code&gt; will be executed on that server. In this case, it installs &lt;code&gt;fail2ban&lt;&#x2F;code&gt; to harden the server by slowing down the 1000s of SSH login attacks that happen regularly and adding a little message to the &lt;code&gt;motd&lt;&#x2F;code&gt; file.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;&#x2F;strong&gt; When you run &lt;code&gt;packer build .&lt;&#x2F;code&gt;, Packer will automatically create a new server and a new Snapshot in your Hetzner Cloud project. Both will be charged. The server is &lt;strong&gt;automatically&lt;&#x2F;strong&gt; deleted immediately after either the Snapshot was created or the creation failed.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;To create that image run the following commands:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Set your Hetzner API Token&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage&quot;&gt;export&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; HCLOUD_TOKEN&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;XXX&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Initialize the project - only needed once&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;4&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;packer&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; init&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; .&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;5&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Build&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;6&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;packer&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; build&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; .&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now Packer builds that server and streams all the logs to your current terminal. Verify that the new image is available in the Hetzer &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;console.hetzner.cloud&#x2F;&quot;&gt;Cloud Console&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;img&#x2F;blog&#x2F;hetzner-image-overview-1.png&quot; alt=&quot;image-overview-1.png.png&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;taking-it-to-the-next-level&quot;&gt;Taking it to the next level&lt;&#x2F;h2&gt;
&lt;p&gt;Putting all commands in HCL can quickly get crowded. It is also not reasonable to copy-paste the code for every variant of an image you might want to build. To make things more generic, Packer can use variables:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;hcl&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; custom-img-v2.pkr.hcl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;variable&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-enummember&quot;&gt; &amp;quot;base_image&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  type&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;    =&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  default&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;debian-12&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;variable&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-enummember&quot;&gt; &amp;quot;output_name&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  type&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;    =&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  default&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;snapshot&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;variable&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-enummember&quot;&gt; &amp;quot;version&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  type&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;    =&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  default&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;v1.0.0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;14&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;variable&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-enummember&quot;&gt; &amp;quot;user_data_path&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;15&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  type&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;    =&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;16&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  default&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;cloud-init-default.yml&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;17&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;18&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;19&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;source&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-enummember&quot;&gt; &amp;quot;hcloud&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-enummember&quot;&gt; &amp;quot;base-amd64&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;20&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  image&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;         =&lt;&#x2F;span&gt;&lt;span&gt; var&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;base_image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;21&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  location&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;      =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;nbg1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;22&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  server_type&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;   =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;cx11&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;23&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  ssh_keys&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;      =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;24&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  user_data&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;     =&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; file&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;var&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;user_data_path&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;25&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  ssh_username&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;  =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;root&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;26&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  snapshot_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;var&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;output_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;var&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;version&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;27&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  snapshot_labels&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;28&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    base&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;    =&lt;&#x2F;span&gt;&lt;span&gt; var.base_image,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;29&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    version&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; var.version,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;30&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;    =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;var&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;output_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;var&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;version&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;31&lt;&#x2F;span&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;32&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;33&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;34&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;build&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;35&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  sources&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;source.hcloud.base-amd64&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;36&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;  provisioner&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-enummember&quot;&gt; &amp;quot;shell&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;37&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    scripts&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;38&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;os-setup.sh&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;39&lt;&#x2F;span&gt;&lt;span&gt;    ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;40&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    env&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;41&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;      BUILDER&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;packer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;42&lt;&#x2F;span&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;43&lt;&#x2F;span&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;44&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now, we can specify and override the base image at runtime by using &lt;code&gt;packer build -var bas_image=ubuntu-22.04 -var version=v1.1.0 .&lt;&#x2F;code&gt;. This version also uses the &lt;code&gt;scripts&lt;&#x2F;code&gt; parameter rather than in-lining all the commands. This allows for much more complex setups. It also uses &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;cloudinit.readthedocs.io&#x2F;en&#x2F;latest&#x2F;&quot;&gt;cloud-init&lt;&#x2F;a&gt; to configure some settings declaratively.&lt;&#x2F;p&gt;
&lt;p&gt;Hetzner also supports &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.hetzner.com&#x2F;press-release&#x2F;arm64-cloud&quot;&gt;Arm64-based servers&lt;&#x2F;a&gt; which offer a great price-to-performance ratio and impressive efficiency. Due to the different nature of Arm, software needs to be compiled for this architecture and all configurations also need to be applied for this architecture. Fortunately, Packer allows to reuse any build scripts for Arm.&lt;&#x2F;p&gt;
&lt;p&gt;Just add another source to your code and update the build step to include that source:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;hcl&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; custom-img-v2.pkr.hcl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;source&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-enummember&quot;&gt; &amp;quot;hcloud&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-enummember&quot;&gt; &amp;quot;base-arm64&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  image&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;         =&lt;&#x2F;span&gt;&lt;span&gt; var&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;base_image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  location&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;      =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;nbg1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  server_type&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;   =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;cax11&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  ssh_keys&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;      =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  user_data&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;     =&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; file&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;var&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;user_data_path&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  ssh_username&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;  =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;root&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  snapshot_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;var&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;output_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;var&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;version&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  snapshot_labels&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    base&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;    =&lt;&#x2F;span&gt;&lt;span&gt; var.base_image,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    version&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; var.version,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;    =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;var&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;output_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;var&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;version&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;14&lt;&#x2F;span&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;15&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;16&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;17&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;build&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;18&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  sources&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;source.hcloud.base-amd64&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;19&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;+&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  sources&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;source.hcloud.base-amd64&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;source.hcloud.base-arm64&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;20&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;  provisioner&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-enummember&quot;&gt; &amp;quot;shell&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;21&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This version now automatically builds images for Arm64-based servers.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;tips-and-advanced-usage&quot;&gt;Tips and advanced usage:&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;About disk size:&lt;&#x2F;strong&gt;&lt;br&gt;
You may have noticed that the code above uses the smallest instances available on Hetzner. This is not only to reduce cost but also allows for the created Snapshot to be deployed for every VM. Due to the way disks are managed at Hetzner, a new VM must have a disk that is at least the same size as the one from which the Snapshot was created. Using an eight-core server might be a little faster than using a smaller one, but it would limit the servers you can deploy form this image to VMs with at least 240GB disks.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;About Tags:&lt;&#x2F;strong&gt;&lt;br&gt;
Tags are metadata that you can add to a Snapshot. These are useful to provide information about the origin of an image and what it is used for. Also, tags are the only way to select an existing Snapshot in Terraform to deploy a new VM. They should definitely be used.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;About cloud-init:&lt;&#x2F;strong&gt;&lt;br&gt;
You can use &lt;code&gt;cloud-init&lt;&#x2F;code&gt; to do some early setup while building images with Packer, but you might also want to use &lt;code&gt;cloud-init&lt;&#x2F;code&gt; when deploying your custom image. By default, &lt;code&gt;cloud-init&lt;&#x2F;code&gt; only runs once, so it needs to be reset.&lt;br &#x2F;&gt;
Consider adding the following lines to your bash script to wait and reset &lt;code&gt;cloud-init&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; os-setup.sh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#!&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt;&#x2F;bin&#x2F;bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;set&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;e&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;o&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; pipefail&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Waiting for cloud-init to finish...&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;cloud-init&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; status&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-wait&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Installing packages...&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;apt-get&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; update&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;apt-get&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-yes&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-no-install-recommends&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; wget&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; fail2ban&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; My setup...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;14&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Cleanup...&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;15&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;cloud-init&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; clean&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-machine-id&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-seed&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-logs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;16&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;rm&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;rvf&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;var&#x2F;lib&#x2F;cloud&#x2F;instances&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;etc&#x2F;machine-id&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;var&#x2F;lib&#x2F;dbus&#x2F;machine-id&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;var&#x2F;log&#x2F;cloud-init&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt;*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This allows users to run &lt;code&gt;cloud-init&lt;&#x2F;code&gt; a second time.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Different operating systems:&lt;&#x2F;strong&gt;&lt;br&gt;
You can create and boot completely different operating systems and create your own images for them using Packer. By booting into Hetzner’s &lt;em&gt;rescue&lt;&#x2F;em&gt; mode, you can override the entire disk image of a VM:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;hcl&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;build&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  sources&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;source.hcloud.myvm&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;  provisioner&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-enummember&quot;&gt; &amp;quot;shell&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    inline&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;apt-get install -y wget&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;wget https:&#x2F;&#x2F;github.com&#x2F;siderolabs&#x2F;talos&#x2F;releases&#x2F;download&#x2F;v1.5.5&#x2F;hcloud-amd64.raw.xz&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;xz -d -c hcloud-amd64.raw.xz | dd of=&#x2F;dev&#x2F;sda &amp;amp;&amp;amp; sync&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span&gt;    ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;My personal use case for Packer is to create preconfigured Kubernetes images with fine-tuned system parameters and preloaded container images. The horizontal autoscaler can use these images to provision new worker nodes quickly and reliably. But there are plenty of other use cases.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;img&#x2F;blog&#x2F;hetzner-image-overview-2.png&quot; alt=&quot;image-overview-2.png.png&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;For further configuration, check out the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;developer.hashicorp.com&#x2F;packer&#x2F;tutorials&quot;&gt;Packer documentation&lt;&#x2F;a&gt; and the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;developer.hashicorp.com&#x2F;packer&#x2F;integrations&#x2F;hetznercloud&#x2F;hcloud&#x2F;latest&#x2F;components&#x2F;builder&#x2F;hcloud&quot;&gt;Hetzner Packer builder documentation&lt;&#x2F;a&gt;.&lt;br &#x2F;&gt;
You can find the entire code used in this article can be found on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;hegerdes&#x2F;deb361b1383c76e9dabbe030c607ac51&quot;&gt;GitHub&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;This article gave a comprehensive guide on how to install and use HashiCorp Packer. It provided a base project on how to use Packer to create custom OS images for Hetzner Cloud VMs, leveraging Infrastructure as Code practices. It also addressed advanced using variables and cloud-init. This approach allows for the creation of tailored, pre-configured OS images, offering a more efficient and streamlined process for deploying VMs with customized settings and applications.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Building and Cracking the Enigma - Part I</title>
        <published>2023-07-09T00:00:00+00:00</published>
        <updated>2023-07-09T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              hegerdes
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://henrikgerdes.me/blog/2023-07-enigma-p1/"/>
        <id>https://henrikgerdes.me/blog/2023-07-enigma-p1/</id>
        
        <content type="html" xml:base="https://henrikgerdes.me/blog/2023-07-enigma-p1/">&lt;h1 id=&quot;building-and-cracking-the-enigma-part-i&quot;&gt;Building and Cracking the Enigma - Part I&lt;&#x2F;h1&gt;
&lt;p&gt;As more and more parts of our lives are shifted to the internet, the subject of security is becoming increasingly relevant. Large language models (LLMs) and chat controls claim more and more personal data. A significant part of security on the internet is achieved through encryption. During the last few weeks, I have been increasingly engaged with encryption and went down the rabbit-hole of encryption history. Despite the exciting early days of message encoding and encryptions like the Caesar-Cipher, the Enigma has a very special place in history, especially from the point of a computer scientist. Thats way I decided to rebuild the enigma in software, to subsequently also try to crack it.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;img&#x2F;blog&#x2F;Enigma.jpg&quot; alt=&quot;Enigma&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-is-the-enigma&quot;&gt;What is the Enigma&lt;&#x2F;h3&gt;
&lt;p&gt;The Enigma is a cipher device mainly used in the second world war by the Nazis. Most of the military communication was transmitted with messages encrypted via the Enigma. Even when the allies obtained one of the Enigma devices, they were not able to decipher their messages because of its complex design created by Arthur Scherbius.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;how-it-works&quot;&gt;How it works&lt;&#x2F;h3&gt;
&lt;p&gt;To understand the following parts, I want to provide a quick (and none complete) overview of how the Enigma works. The Enigma is a symmetric encryption machine in the form of a typewriter. Each Enigma has at least four rotors (wheels) with about 26 steps. There are some variants of the Enigma which also include additional turnover rotors and switches, but for simplicity these will not be considered her. Common to all Enigmas however, was a plugboard where the user could electricity connect two outlets to interchange the key for the letter that was pressed via the letter input buttons. When the user pressed a key an electrical current went through the, may or may not switched, keys of the plugboard, to the entry rotor stepping it and eventually their subsequent rotors, to a final turnover rotor which ultimately highlighted the ciphered latter on the displayed alphabet. Even though the Enigma is a symmetric encryption device, its design always produced different outputs even when the same key was pressed multiple times.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;img&#x2F;blog&#x2F;Enigma-settings.png&quot; alt=&quot;Enigma-Workings&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;To decipher a given text, the user would need a compatible Enigma machine and must know the exact configuration for the initial rotor state and the plugboard configuration. Overall there where about &lt;strong&gt;150 trillion possible configurations&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;So cracking this will be quiet a challenge. A challenge even worth a hole (and fantastic) movie. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;The_Imitation_Game&quot;&gt;The Imitation Game&lt;&#x2F;a&gt; tells the storey about cracking the Enigma and the invention of our modern day computing model by the mathematician Alan Turing.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;some-cryptographic-context&quot;&gt;Some Cryptographic Context&lt;&#x2F;h3&gt;
&lt;p&gt;Cryptography is the term used to describe the encryption of confidential information so that it can only be fully recovered by the intended recipient. Besides cryptography, there is stenography, which deals with hiding information and there is hashing which is also often used in the context of cryptography. With hash functions, however, information is lost, so that this technique is more suitable for unique assignments and the verification of information.&lt;&#x2F;p&gt;
&lt;p&gt;Cryptography and hash functions are fundamental components of our digital lives today. For example, the layers of the ISO-OSI reference model does not specify how to ensure, the information sent is identical to the information received. That’s why TCP (the most used protocol on the web) has built-in error detection, based on checksums using hash functions. As the Internet grew out of its baby shoes and spread across universities into every aspect of our lives today, it became clear that the Internet was not designed with security in mind.&lt;&#x2F;p&gt;
&lt;p&gt;In today’s world, TLS&#x2F;SSL forms the basis of this, post-field added, security. On the web, public certificates and private keys are used to encrypt information from unauthorized entities. This is based on an asymmetric process where anyone can encrypt information with the public key, but only the owner of the private key can decrypt it. This is also the foundation for SSH keys and digital signatures. Since asymmetric encryption and decryption is quite time consuming, on the web there is a separate handshake (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.cloudflare.com&#x2F;de-de&#x2F;learning&#x2F;ssl&#x2F;what-happens-in-a-tls-handshake&#x2F;&quot;&gt;more about the SSL handshake&lt;&#x2F;a&gt;) negotiated per session, where both sides agree on a secret symmetric key and then use it for encryption. With a symmetrical encryption you can encrypt and decrypt information with the same key, like with the Enigma. With the Enigma, the rotor and switchboard settings are the key, on the Internet it is often a password.&lt;&#x2F;p&gt;
&lt;p&gt;With each and every encryption there is the possibility guess the key. Mathematicians have accordingly searched for cryptographic methods that have a high complexity, making it difficult to guess the key. Trying every possibility in the problem-space through brute-force results in complexity, often measured in bits. Here is a small comparison:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Encryption&lt;&#x2F;th&gt;&lt;th&gt;Possibilities base 2&lt;&#x2F;th&gt;&lt;th&gt;Possibilities base 10&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Enigma&lt;&#x2F;td&gt;&lt;td&gt;2^68&lt;&#x2F;td&gt;&lt;td&gt;≈ 15 × 10^19&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;RSA 2048&lt;&#x2F;td&gt;&lt;td&gt;2^112&lt;&#x2F;td&gt;&lt;td&gt;≈ 51 × 10^32&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;AES 265&lt;&#x2F;td&gt;&lt;td&gt;2^265&lt;&#x2F;td&gt;&lt;td&gt;≈ 59 × 10^78&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Just as a reminder: Every additional bit doubles the possibilities. Current computers would take about 300 trillion years to crack a RSA 2048 key. To get a glims about AES 265 check out this &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=S9JGmA5_unY&quot;&gt;great video&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;implementing-the-enigma&quot;&gt;Implementing the Enigma&lt;&#x2F;h3&gt;
&lt;p&gt;I decided to rebuild the Enigma in software, to deeper understand its working, using my go to prototyping language python. First I needed to narrow down the scope of the parts I wanted to implement. I ended up with the following plan:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Enigma with 3 rotors and 1 reverse rotor&lt;&#x2F;li&gt;
&lt;li&gt;Support for the plugboard&lt;&#x2F;li&gt;
&lt;li&gt;Support for the letters a-z&lt;&#x2F;li&gt;
&lt;li&gt;Support for choice for 3 out of 5 possible rotors&lt;&#x2F;li&gt;
&lt;li&gt;Support for 1 out of 3 reverse rotors&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This is a doable scope while also keeping the core concepts of the original Enigma. Modeling the rotors in software resulted basically in one list for every rotor containing tuples for the next step-position.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;allRotor&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;    1&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 10&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 12&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 11&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;6&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;7&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 16&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;8&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 21&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;9&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 25&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 13&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;11&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 19&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;12&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 14&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;13&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 22&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;14&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 24&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;15&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 23&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;17&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 20&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;18&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 18&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;19&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 15&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;20&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;21&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;22&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;23&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 17&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;24&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;25&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;    2&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 10&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 18&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;6&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 17&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;7&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 20&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;8&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 23&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;9&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 11&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;11&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;12&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 22&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;13&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 19&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;14&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 12&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;15&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 16&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;17&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;18&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 25&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;19&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 13&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;20&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 15&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;21&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 24&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;22&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;23&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 21&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;24&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 14&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;25&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;4&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;    3&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 11&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;6&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;7&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 15&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;8&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 17&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;9&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 19&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 23&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;11&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 21&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;12&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 25&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;13&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 13&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;14&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 24&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;15&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;17&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 22&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;18&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;19&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;20&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 10&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;21&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 12&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;22&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 20&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;23&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 18&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;24&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 16&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;25&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 14&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;5&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;    4&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 18&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 14&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 21&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 15&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 25&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;6&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;7&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;8&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 24&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;9&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 16&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 20&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;11&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;12&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 17&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;13&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;14&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 23&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;15&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 11&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 13&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;17&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;18&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 19&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;19&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;20&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 10&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;21&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;22&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;23&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 12&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;24&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 22&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;25&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;6&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;    5&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 21&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 25&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 17&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;6&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 19&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;7&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 24&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;8&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 20&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;9&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 15&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 18&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;11&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;12&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 13&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;13&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;14&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 11&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;15&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 23&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;17&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 22&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;18&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 12&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;19&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;20&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 16&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;21&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 14&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;22&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;23&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;24&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;25&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 10&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;7&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The plugboard is only a hash map switching two arbitrary letters. The Enigma class just used these inputs as settings and passed each character passed to to the plugboard, the reverse rotor, stepping it, the rotor 1 to 3, stepping them and back to the reverse roter.&lt;&#x2F;p&gt;
&lt;p&gt;Due to the reverse rotor, the Enigma is symmetrical in operation. This means that users do not have to distinguish between cyphering and deciphering inputs. Using it looks something like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; pyenigma.py&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;Provide&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; a&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; strimg&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; to&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; encrypt&#x2F;decrypt:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; dont&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; panic&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;Encryped:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; kihdqqocv&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can checkout the code &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;hegerdes&#x2F;PyEnigma&quot;&gt;on my GitHub&lt;&#x2F;a&gt;.&lt;br &#x2F;&gt;
&lt;em&gt;Disclaimer: This is a quick and dirty implementation I did in collage. Its NOT production grade!&lt;&#x2F;em&gt;&lt;br &#x2F;&gt;
The next step will be cracking it.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;See you!&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>How to send OnPrem Prometheus metrics to MS Azure</title>
        <published>2023-05-25T00:00:00+00:00</published>
        <updated>2023-05-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              hegerdes
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://henrikgerdes.me/blog/2023-05-azure-prometheus-remote-write/"/>
        <id>https://henrikgerdes.me/blog/2023-05-azure-prometheus-remote-write/</id>
        
        <content type="html" xml:base="https://henrikgerdes.me/blog/2023-05-azure-prometheus-remote-write/">&lt;h1 id=&quot;sending-metrics-to-azure-with-prometheus&quot;&gt;Sending metrics to Azure - with Prometheus&lt;&#x2F;h1&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;With this post, I want to provide a quick demonstration on how to send Prometheus metrics to Azure managed Prometheus. Let’s get stared.&lt;&#x2F;p&gt;
&lt;!-- ![Azure meets Prometheus](&#x2F;img&#x2F;blog&#x2F;azure-prometheus-monitor.png) --&gt;
&lt;h2 id=&quot;what-is-prometheus&quot;&gt;What is Prometheus&lt;&#x2F;h2&gt;
&lt;p&gt;Prometheus is an open-source monitoring system that scrapes (pulls) system and application metrics from supported targets. It is an graduated project of the Cloud Native Computing Foundation (CNCF) and the de facto standard in the Kubernetes world. It also supports service discovery and alerting. The major drawback of Prometheus is, that it stores it’s metrics in block storage as local files and has no native support for clustering multiple instances. Horizontal scaling is therefore difficult to archive.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-send-metrics-to-azure&quot;&gt;Why send metrics to Azure&lt;&#x2F;h2&gt;
&lt;p&gt;Cloud services as Azure and Grafana Cloud solve the clustering and storage issues of a single Prometheus instance by providing managed services. (Often implemented through &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;grafana.com&#x2F;oss&#x2F;mimir&#x2F;&quot;&gt;Mimir&lt;&#x2F;a&gt;.) Companies can send metrics from multiple Prometheus instances and different locations, all to a single location, which minimizes duplicated setups (cost), the risk of a singe point of failure and provides scaling, while also providing a single location (called a single pane of glass) for service performance data. When using Azure, Prometheus also integrates nicely with AKS and other Azure services, even without the need of credentials due to service principles.&lt;br &#x2F;&gt;
Prometheus supports sending data to a different location using the &lt;code&gt;remote_write&lt;&#x2F;code&gt; feature, which I will use here to sent data from any system and app to Azure.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;setting-up-azure-prometheus&quot;&gt;Setting up Azure Prometheus&lt;&#x2F;h2&gt;
&lt;p&gt;For simplicity, I will demonstrate the set up process using the Azure Portal. But the process can also be automated via the CLI or terraform.&lt;br &#x2F;&gt;
You have to do the following steps:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Log into Azure&lt;&#x2F;li&gt;
&lt;li&gt;Search for Prometheus&lt;&#x2F;li&gt;
&lt;li&gt;Start Creating a Prometheus instance
&lt;ul&gt;
&lt;li&gt;Set a name and location&lt;&#x2F;li&gt;
&lt;li&gt;Allow public networking&lt;&#x2F;li&gt;
&lt;li&gt;Create and wait&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This will create a new managed monitor resource-group with your Prometheus instance.
&lt;img src=&quot;&#x2F;img&#x2F;blog&#x2F;azure-prom-1-create.png&quot; alt=&quot;Azure meets Prometheus&quot; &#x2F;&gt;
Write down the &lt;em&gt;Metrics ingestion endpoint&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Next step is to create an App&#x2F;User that can push to that endpoint. For this we:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Open the Azure Active Directory&lt;&#x2F;li&gt;
&lt;li&gt;Go to App Registrations&lt;&#x2F;li&gt;
&lt;li&gt;Click New Registration
&lt;ul&gt;
&lt;li&gt;Provide a name&lt;&#x2F;li&gt;
&lt;li&gt;Choose single tenant mode&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Go to Certificates &amp;amp; Secrets&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;For simplicity we use a secret in this demo, but a certificate is safer and recommended. It is best practice to store the certificate in a vault (like Azure Keyvault or Hashicorp Vault) and only request the credentials via the vault’s API. A guide how to do this can be found &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;learn.microsoft.com&#x2F;en-us&#x2F;azure&#x2F;key-vault&#x2F;certificates&#x2F;quick-create-portal#add-a-certificate-to-key-vault&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Create a secret and copy it (you will not be able to see it again). Go back to the overview of the created app registration.
&lt;img src=&quot;&#x2F;img&#x2F;blog&#x2F;azure-prom-2-user.png&quot; alt=&quot;Azure meets Prometheus&quot; &#x2F;&gt;
Copy the ClientId and then press on &lt;em&gt;Endpoints&lt;&#x2F;em&gt; to copy the &lt;em&gt;OAuth 2.0 token endpoint (v2)&lt;&#x2F;em&gt; URL.&lt;&#x2F;p&gt;
&lt;p&gt;Next, we need to authorize our user to push metrics to the &lt;em&gt;Metrics ingestion endpoint&lt;&#x2F;em&gt;. Go back to the created resource-groups for the Prometheus instance and go to &lt;em&gt;Access Control (IMA)&lt;&#x2F;em&gt;. On the role-assignment tab, add a new role-assignment with the role of &lt;em&gt;Monitoring Metrics Publisher&lt;&#x2F;em&gt; and assign it to the created user from the previous step.
&lt;img src=&quot;&#x2F;img&#x2F;blog&#x2F;azure-prom-3-access.png&quot; alt=&quot;Azure meets Prometheus&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This is it for the azure site!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sending-metrics&quot;&gt;Sending Metrics&lt;&#x2F;h2&gt;
&lt;p&gt;Now we can set up our local tools to send metrics.&lt;&#x2F;p&gt;
&lt;p&gt;The flow we created uses the OpenIdConnect (OIDC) standard which is part of the Oauth2 spec. When you want lo learn more abut the described authentication, you can check out this in depth article &lt;strong&gt;TBA&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;To send metrics form on Prometheus instance we need to set up the Prometheus config like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;g&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;lobal&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  s&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;crape_interval&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;m&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;s&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;crape_configs&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span&gt;  -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; j&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ob_name&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;INTERNAL&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;    h&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;onor_labels&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;    s&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;tatic_configs&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; t&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;argets&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;localhost:9090&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;r&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;emote_write&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;span&gt;  -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; n&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ame&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; a&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;zure-write&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;    u&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;rl&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Metrics ingestion endpoint&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;    h&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;eaders&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;14&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;      X&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;-Scope-OrgID&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; a&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;nonymous&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;15&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;    o&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;auth2&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;16&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;      c&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;lient_id&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ClientId&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;17&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;      c&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;lient_secret&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ClientSecret&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;18&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;      t&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;oken_url&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;OAuth 2.0 token endpoint (v2)&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;19&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;      s&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;copes&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; h&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ttps:&#x2F;&#x2F;monitor.azure.com&#x2F;.default&lt;&#x2F;span&gt;&lt;span&gt; ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Thats it.&lt;&#x2F;p&gt;
&lt;p&gt;Start your Prometheus instance and see the logs that are coming in. You can visualize them in Azure Monitor or via the Azure Managed Grafana.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;See you!&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>The Notebook for Developers - now even better</title>
        <published>2023-03-06T00:00:00+00:00</published>
        <updated>2023-03-06T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              hegerdes
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://henrikgerdes.me/blog/2023-05-joplin-plugin/"/>
        <id>https://henrikgerdes.me/blog/2023-05-joplin-plugin/</id>
        
        <content type="html" xml:base="https://henrikgerdes.me/blog/2023-05-joplin-plugin/">&lt;h1 id=&quot;joplin-the-notebook-for-devs&quot;&gt;Joplin: The notebook for Devs&lt;&#x2F;h1&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;How do you keep your digital life organized? How do you store and structure your knowledge in the era of information (overload)? I struggled for sooo long to find a good solution for these problems, but all the systems I tried, every app I used, felt &lt;em&gt;off&lt;&#x2F;em&gt;. They didn’t let me do the things I wanted to, were slow to operate or were just too costly. I almost gave up and went back to analog notes and a mix of digital short notes&#x2F;Google-Notes - until a colleague told me about Joplin. Right from the beginning, I loved the content-focused approach and the lack of the corporate business stuff that wanted to sell me things. And the best thing is: It’s extendable - so I extended it.&lt;&#x2F;p&gt;
&lt;p&gt;With this article, I want to give an overview of Joplin, what differentiates it from other notebook apps and the necessary information to decide if it is a tool fitting for your workflow.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;img&#x2F;blog&#x2F;joplin.png&quot; alt=&quot;Joplin App GUI Overview&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-is-joplin&quot;&gt;What is Joplin?&lt;&#x2F;h2&gt;
&lt;p&gt;Joplin is a cross-platform notebook app (Windows, Linux, macOS, iOS, Android) that is entirely based on Markdown. If you are not comfortable with Markdown, read no further - Joplin is not for you. But if you like Markdown because of its easy formatting and capabilities, use it regularly in ReadMe.md’s or GitHub&#x2F;GitLab Issues, Joplin might be just the right fit.&lt;&#x2F;p&gt;
&lt;p&gt;Its content-focused approach is its main differentiator between other apps. There is no need to switch between &lt;em&gt;heading&lt;&#x2F;em&gt; formatting and &lt;em&gt;normal&lt;&#x2F;em&gt; formatting, and there is almost no need to use the mouse. This approach enables users to work incredibly fast and get their thoughts written down. From personal experience, a lot of other tools do way too much to make the content pretty and flexible instead of focusing on the actual content. More on this later.&lt;br &#x2F;&gt;
When the time comes to make it pretty, Joplin allows users to export their notes in almost every imaginable format, including PDF and HTML.&lt;&#x2F;p&gt;
&lt;p&gt;Another differentiator is that Joplin is open-source software. Everyone can see the sources, and personal data keeps being personal. There are no &lt;em&gt;Upgrade here&lt;&#x2F;em&gt;, &lt;em&gt;Premium there&lt;&#x2F;em&gt; popups, it is just focused on content. There is no big corporation behind Joplin that wants to push their subscription model. Of course, there is the option to spend money, and users can also opt-in to JoplinCloud (between $17 and $80 annually), but this is purely optional. As you might expect, you can sync your notes with Joplin Cloud, but this is not only possible with JoplinCloud. It can also be done with OneDrive, Dropbox, GoogleDrive, and NextCloud. A quick NextCloud setup allows users to store as many notes as they want. End-to-End encryption is also supported.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;comparison-to-other-apps&quot;&gt;Comparison to Other Apps&lt;&#x2F;h2&gt;
&lt;p&gt;As I mentioned earlier, I have tried some other notebook apps, including Notion, OneNote, Evernote, and Google Notes.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;On Evernote:&lt;&#x2F;strong&gt;
Regarding Evernote, I used it way back when I was in school, so things might have changed since then.&lt;br &#x2F;&gt;
First of all, you &lt;strong&gt;need&lt;&#x2F;strong&gt; an account. Even when you have an account, there are artificial limitations such as a maximum upload quota of 60MB per month, a maximum of two synced devices, and no offline access to notes. Also, there is currently no Linux client, although it is in early beta now. I never got up to pace with Evernote. From my experience, it tried to solve too many tasks and fit every use case, but did not solve one thing well or fit perfectly. I was even willing to pay to try their premium features, but since they declined my student discount and I was not willing to pay $13 monthly, I turned my back on Evernote and never looked back. Taking notes and using basic features should not cost more than Spotify or Netflix.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Notion:&lt;&#x2F;strong&gt;
As for Notion, I cannot say too many negative things about it. It just did not fit my requirements. I wanted static, easily writable notes that I can organize and search. Notion is much more dynamic and even has dynamic project boards, agendas, and timesheets. Although I think there are other services that execute project management better than Notion, I know for a fact that there are thousands of people out there who love Notion. However, they have to fix their app - copy and paste is beyond broken.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Others:&lt;&#x2F;strong&gt;
I also tried OneNote, DesktopNotes, and Google Notes. At a certain amount of notes, the latter tools are not capable of staying organized and are too limiting. For a quick note I need to remember, sure, but nothing more. OneNote is fundamentally a good app, but Microsoft screwed up with all these different versions of OneNote (Office OneNote, OneNote WPF, OneNote Online). I still use it if I have to create technical drawings with my tablet, but writing and formatting longer texts - ain’t gonna happen.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;on-joplin&quot;&gt;On Joplin&lt;&#x2F;h2&gt;
&lt;p&gt;As stated before, Joplin is a cross-platform notebook app that is entirely focused on notes. There are no fancy agendas, drawing or advanced formatting support. It supports all the major Markdown features, including headings, bold and italic formatting, enumerations, and tables. Images can be included via drag and drop or Markdown image includes. Math mode is also supported. It is perfect for my workflows because I already write all my docs and notes in Markdown, so I’m quite fast. It is also easy to import text because most of the tools I use have Markdown support. It is easy to copy and paste between Github and Joplin. Even entire websites (or portions of them) can be imported (and converted to Markdown) via a web-clipper. In case users want to stop using Joplin, they can easily export their notes in various formats. But, as I mentioned above, formatting options are limited, and everything that goes beyond the mentioned methods has to be done via HTML or via Plugins. That’s right, Joplin has a significant number of plugins which can do all kinds of stuff. Users can add support for draw.io diagrams, daily agendas, calendar tabs, and much more. It is also considerably easy to build a plugin, so I did it myself to add a feature I really wanted to make Joplin my central knowledge solution.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;my-plugin&quot;&gt;My Plugin&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;Why:&lt;&#x2F;strong&gt; I think almost everyone stumbled at least once upon one of these &lt;em&gt;Awesome lists of _&lt;&#x2F;em&gt;. Notable mentions are &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;RunaCapital&#x2F;awesome-oss-alternatives&quot;&gt;awesome open-source alternatives to SaaS&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;trananhkma&#x2F;fucking-awesome-python&quot;&gt;fucking-awesome-python&lt;&#x2F;a&gt; or &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;onlurking&#x2F;awesome-infosec&quot;&gt;awesome-infosec&lt;&#x2F;a&gt;. Sure, you can copy&#x2F;clip them, but then you have a static version, and you don’t get the newest additions and updates. Realistically, no one regularly visits all of these cheat sheets and updates them.&lt;br &#x2F;&gt;
So I wrote a plugin for that: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;hegerdes&#x2F;joplin-plugin-remote-note-pull&quot;&gt;joplin-plugin-remote-note-pull&lt;&#x2F;a&gt;.&lt;br &#x2F;&gt;
It lets users create new notes from any publicly available website and regularly updates the note with the original upstream version.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;How:&lt;&#x2F;strong&gt; I started with a plugin skeleton. Joplin even provides a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;laurent22&#x2F;joplin&#x2F;tree&#x2F;dev&#x2F;packages&#x2F;generator-joplin&quot;&gt;plugin-generator&lt;&#x2F;a&gt;, which gets you set up. The &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;joplinapp.org&#x2F;api&#x2F;get_started&#x2F;plugins&#x2F;&quot;&gt;docs&lt;&#x2F;a&gt; provide all the other info one might need.&lt;br &#x2F;&gt;
Plugins are written in JavaScript&#x2F;TypeScript and get executed via the NodeJs runtime Joplin is built on. Developers can add new UI elements or register new functions. Basically my plugin just does is make a web-request to the newly added note and download the content. Before storing it as a new note, it fixes some relative links and paths in the gathered content and adds a custom footer to the note. Other than that, it is just a timer-function that runs every x minutes to update all notes created via my plugin. It was a fun project to play around with. Publishing plugins is also relatively easy; they just have to follow a specific naming schema and get automatically picked up by Joplin’s internal plugin browser.&lt;&#x2F;p&gt;
&lt;p&gt;For now, I’m quite happy with this workflow and wished I had it earlier. If anyone is interested in sharing their favorite way to stay organized in this world of information overload, feel free to reach out.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;See you!&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Broken NodeJS Apps due to secerity dot-release - Debugging the NodeJS CVE-2022-32213 fix</title>
        <published>2022-08-18T00:00:00+00:00</published>
        <updated>2022-08-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              hegerdes
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://henrikgerdes.me/blog/2022-08-bug-caused-by-sec/"/>
        <id>https://henrikgerdes.me/blog/2022-08-bug-caused-by-sec/</id>
        
        <content type="html" xml:base="https://henrikgerdes.me/blog/2022-08-bug-caused-by-sec/">&lt;h1 id=&quot;broken-nodejs-apps-due-to-security-dot-release&quot;&gt;Broken NodeJS Apps due to security dot-release&lt;&#x2F;h1&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;On July 7th the vulnerabilities &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.cve.org&#x2F;CVERecord?id=CVE-2022-32213&quot;&gt;CVE-2022-32213&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.cve.org&#x2F;CVERecord?id=CVE-2022-32214&quot;&gt;CVE-2022-32214&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.cve.org&#x2F;CVERecord?id=CVE-2022-32215&quot;&gt;CVE-2022-32215&lt;&#x2F;a&gt; where publicly disclosed. They affected all current NodeJS versions (v14.x, v16.x, v18.x)! The same day fixes for the vulnerabilities where released. My colleagues and I assumed a quick and easy deployment to spit these fixes onto our client’s production systems. A simple rebuild of the old code state with the new NodeJS version and replacement of the old containers. We thought wrong! 🙃&lt;&#x2F;p&gt;
&lt;p&gt;Our staging system showed that some of our apps didn’t get any requests anymore and clients got a HTTP 4xx error code.
&lt;img src=&quot;&#x2F;img&#x2F;blog&#x2F;nodejs-header.png&quot; alt=&quot;VSCode&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;some-background-information&quot;&gt;Some Background Information&lt;&#x2F;h3&gt;
&lt;p&gt;For a better understanding let me give a simplified overview of our system architecture:
&lt;img src=&quot;https:&#x2F;&#x2F;upload.wikimedia.org&#x2F;wikipedia&#x2F;commons&#x2F;thumb&#x2F;6&#x2F;67&#x2F;Reverse_proxy_h2g2bob.svg&#x2F;1200px-Reverse_proxy_h2g2bob.svg.png&quot; alt=&quot;ReverseProxy&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We use a reverse proxy which is the only service directly exposed to the internet. It handles TLS termination and routes the traffic to the appropriate backend service. Some services require TLS client verification (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.cloudflare.com&#x2F;learning&#x2F;access-management&#x2F;what-is-mutual-tls&#x2F;&quot;&gt;mTLS&lt;&#x2F;a&gt;), meaning the client has to send its unique certificate to the server where it gets verified and passed to the backend service if the certificate was valid.&lt;&#x2F;p&gt;
&lt;p&gt;We triggered a new build with the updated NodeJS version (in our case form NodeJS v14.19.3 to v14.20.0) and deployed it to our testing system. The deployment went smooth, but then we saw that every service using client verification was broken after the update.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;debugging-time&quot;&gt;Debugging time&lt;&#x2F;h3&gt;
&lt;p&gt;To verify the bug I deployed the same code with the two different NodeJS versions (v14.19.3 &amp;amp; v14.20.0). On v14.19.3 I got a HTTP 200 response, on v14.20.0 I got a HTTP 400 response indicating a bad-request. But our application never threw a 400 error - nor did it log anything. - &lt;em&gt;Time to dig deeper…&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I created a minimal NodeJS http-server and deployed it with the two different NodeJS versions (&lt;em&gt;and even new ones&lt;&#x2F;em&gt;):&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant&quot;&gt; port&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 3000&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;var&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; http&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; require&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt;Dead simple http server:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;http&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;createServer&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;req&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; res&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  res&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;setHeader&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Content-Type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;application&#x2F;json&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  res&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;write&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant&quot;&gt;JSON&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;stringify&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;req&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;headers&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  console&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;log&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;REQ FROM: path: &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;req&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;url&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;; remote: &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;req&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;ip&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;`&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  console&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;log&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;req&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;headers&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  res&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;end&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;listen&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;port&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;0.0.0.0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I got the same behavior 😒. Not a solution but now I knew it wasn’t a bug in our application. Is it a bug in NodeJS? In a dot-release? For security fixes?&lt;&#x2F;p&gt;
&lt;p&gt;Let’s start by looking at the release notes of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nodejs&#x2F;node&#x2F;blob&#x2F;main&#x2F;doc&#x2F;changelogs&#x2F;CHANGELOG_V14.md&quot;&gt;NodeJS 14.20.0&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-heading&quot;&gt;###&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; Notable Changes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-other z-link&quot;&gt;8e8aef836c&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt; - (SEMVER-MAJOR) src,deps,build,test: add OpenSSL config appname (Daniel Bevenius) #43124&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-other z-link&quot;&gt;98965b137d&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt; - deps: upgrade openssl sources to 1.1.1q (RafaelGSS) #43686&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-heading&quot;&gt;###&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; Commits&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-other z-link&quot;&gt;b93e048bf6&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt; - deps: update archs files for OpenSSL-1.1.1q (RafaelGSS) #43686&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-other z-link&quot;&gt;98965b137d&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt; - deps: upgrade openssl sources to 1.1.1q (RafaelGSS) #43686&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-other z-link&quot;&gt;837a1d803e&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt; - deps: update archs files for OpenSSL-1.1.1p (RafaelGSS) #43527&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-other z-link&quot;&gt;c5d9c9a49e&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt; - deps: upgrade openssl sources to 1.1.1p (RafaelGSS) #43527&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-other z-link&quot;&gt;da0fda0fe8&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt; - http: stricter Transfer-Encoding and header separator parsing (Paolo Insogna) #315&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-other z-link&quot;&gt;48c5aa5cab&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt; - src: fix IPv4 validation in inspector_socket (Tobias Nießen) nodejs-private&#x2F;node-private#320&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-other z-link&quot;&gt;8e8aef836c&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt; - (SEMVER-MAJOR) src,deps,build,test: add OpenSSL config appname (Daniel Bevenius) #43124&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Hmmm - The certificates are generated with &lt;em&gt;openssl&lt;&#x2F;em&gt;, but the actual verification takes place before it reaches NodeJS. The only other notable thing is the stricter http parser. Let’s take a deeper look.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;encoding-is-everything&quot;&gt;Encoding is everything&lt;&#x2F;h3&gt;
&lt;p&gt;I want to see the actual HTTP request that gets proxieed to NodeJS. So I replaced the NodeJS application with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Netcat&quot;&gt;Netcat – The Swiss Army Knife of Networking&lt;&#x2F;a&gt;.
With the help of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bnoordhuis&quot;&gt;@bnoordhuis&lt;&#x2F;a&gt; I found that we were getting the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;# HexDump&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span&gt;00000000: 4745 5420 2f20 4854 5450 2f31 2e31 0d0a 436f 6e6e 6563 7469 6f6e 3a20 7570  GET &#x2F; HTTP&#x2F;1.1..Connection: up&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span&gt;0000001e: 6772 6164 650d 0a48 6f73 743a 2064 6d2d 7465 7374 696e 672d 7374 6167 696e  grade..Host: dm-testing-stagin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span&gt;0000003c: 672d 7369 7465 2e63 632d 6973 6f62 7573 2e63 6f6d 0d0a 4d59 5f43 4552 543a  g-site.exampleio.com..MY_CERT:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span&gt;0000005a: 202d 2d2d 2d2d 4245 4749 4e20 4345 5254 4946 4943 4154 452d 2d2d 2d2d 0a09   -----BEGIN CERTIFICATE-----..&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span&gt;00000078: 4d49 4947 4154 4343 412b 6d67 4177 4942 4167 4942 4154 414e 4267 6b71 686b  MIIGATCCA+mgAwIBAgIBATANBgkqhk&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span&gt;00000096: 6947 3977 3042 4151 7346 4144 4342 6d54 4561 4d42 6747 4131 5545 4177 7752  iG9w0BAQsFADCBmTEaMBgGA1UEAwwR&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span&gt;000000b4: 5132 3974 0a09 6347 4675 6553 3168 6458 526f 6233 4a70 6448 6b78 437a 414a  Q29t..cGFueS1hdXRob3JpdHkxCzAJ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span&gt;000000d2: 4267 4e56 4241 5954 416b 5246 4d52 5177 4567 5944 5651 5149 4441 744d 6233  BgNVBAYTAkRFMRQwEgYDVQQIDAtMb3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Do you see these &lt;code&gt;0a09&lt;&#x2F;code&gt; sequences? That is the encoding for &lt;code&gt;\n\t&lt;&#x2F;code&gt; which is &lt;strong&gt;NOT&lt;&#x2F;strong&gt; a valid sequence for new-lines in HTTP-Headers. But NodeJS accepted these sequences anyway - at least till version v14.20.0.&lt;&#x2F;p&gt;
&lt;p&gt;The correct sequence, based on the protocol, should be &lt;code&gt;0a0d09&lt;&#x2F;code&gt; which is &lt;code&gt;\r\n\t&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-solution&quot;&gt;The Solution:&lt;&#x2F;h3&gt;
&lt;p&gt;The solution is easy - just change the way the certificates are encoded! - &lt;em&gt;Wait! We can’t do that!&lt;&#x2F;em&gt;&lt;br &#x2F;&gt;
Due to the nature of our service we don’t have direct control over the clients connecting to our server. It would be a major inconvenience to change this on all clients. Another option is to start NodeJS with the &lt;code&gt;--insecure-http-parser&lt;&#x2F;code&gt; flag - which isn’t an option either.&lt;br &#x2F;&gt;
What about our reverse proxy? Turns out &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.nginx.com&#x2F;&quot;&gt;NGINX&lt;&#x2F;a&gt; has a dedicated variable for client certificates in its &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;nginx.org&#x2F;en&#x2F;docs&#x2F;http&#x2F;ngx_http_ssl_module.html&quot;&gt;ssl-module&lt;&#x2F;a&gt; since version 1.13.5. Instead of &lt;code&gt;ssl_client_cert&lt;&#x2F;code&gt; we could use &lt;code&gt;ssl_client_escaped_cert&lt;&#x2F;code&gt; which contains the url-encoded (and therefore valid encoded) certificate.&lt;br &#x2F;&gt;
A quick test with the new proxy configuration showed that the new NodeJS version was now working.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;some-background-information-1&quot;&gt;Some Background Information&lt;&#x2F;h3&gt;
&lt;p&gt;Planned was the update from NodeJS v14.19.3 to v14.20.0. The above-mentioned CVE’s are about the &lt;em&gt;llhttp&lt;&#x2F;em&gt; http-parser of NodeJS. It is part of the core of NodeJS and handles http requests &lt;em&gt;before&lt;&#x2F;em&gt; any custom JavaScript executed. The security release made the http parser stricter to only accept requests that follow exactly the HTTP protocol standard. The new behavior prevents attackers to use request smuggling.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-we-learned-what-we-did&quot;&gt;What we learned &amp;amp; what we did&lt;&#x2F;h3&gt;
&lt;p&gt;Unfortunately deploying these security fixes wasn’t as straight forward as we originally thought. We did not expect some of our application to just completely stop working. We needed some time to debug but also didn’t want to expose the other &lt;em&gt;working&lt;&#x2F;em&gt; services to unnecessary risk. So we updated every application that didn’t use client verification as soon as all our tests passed end kept back the update form those that did.&lt;br &#x2F;&gt;
Two and 1&#x2F;2 days later we found a solution for the problem and also updated the application that used client verification. We learned about the importance of working within the protocol specification even though some software allows more than it has to. And even though JavaScript is a high level language, it is important to have understanding for the low level actions of the networking-stack. We also got remained that just because it is a dot-release it still can break a lot and case some quality time with your favorite rubber duck 🦆&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;See you!&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Productive Working - Be lazy and get things done - Part II</title>
        <published>2022-02-12T00:00:00+00:00</published>
        <updated>2022-02-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              hegerdes
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://henrikgerdes.me/blog/2022-02-working-effectively-2/"/>
        <id>https://henrikgerdes.me/blog/2022-02-working-effectively-2/</id>
        
        <content type="html" xml:base="https://henrikgerdes.me/blog/2022-02-working-effectively-2/">&lt;h1 id=&quot;productive-working-be-lazy-get-things-done-part-ii&quot;&gt;Productive Working - Be lazy &amp;amp; get things done - Part II&lt;&#x2F;h1&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;My math teacher always told me that mathematicians are lazy and so should we. Only do the minimal number of steps to reach your desired destination. Whether or not these steps are simple in themselves is another matter. But somehow this phrase stuck with me.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;So here are my favorite shortcuts, scripts and tricks to get things done:&lt;&#x2F;em&gt;&lt;br &#x2F;&gt;
&lt;strong&gt;Personal Favorite:&lt;&#x2F;strong&gt; My favorite feature are the search shortcuts in the Browser ❤️
&lt;img src=&quot;&#x2F;img&#x2F;blog&#x2F;shortcut_meme.jpg&quot; alt=&quot;VSCode&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;automate&quot;&gt;Automate&lt;&#x2F;h3&gt;
&lt;p&gt;Are there tasks that you have to do over and over again? Like setting up your work environment? Start the same programs every time? &lt;strong&gt;Automate them!&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
Some example:&lt;&#x2F;p&gt;
&lt;p&gt;I use SSH &lt;em&gt;a lot&lt;&#x2F;em&gt;. To I created a script in my &lt;code&gt;.bashrc&lt;&#x2F;code&gt; file to automaticly start the ssh-agent and add my private key. So I can run SSH commands from every environment:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; SSH-Agent setup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;env&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;s&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;s&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;h&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;g&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;e&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;t&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;e&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;v&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;agent_load_env&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; test&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; .&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;|&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; &#x2F;dev&#x2F;null&lt;&#x2F;span&gt;&lt;span&gt; ;&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;agent_start&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span&gt;    (&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;umask&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 077&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; ssh-agent&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;|&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;env&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;    .&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;|&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; &#x2F;dev&#x2F;null&lt;&#x2F;span&gt;&lt;span&gt; ;&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;agent_load_env&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; agent_run_state: 0=agent running w&#x2F; key; 1=agent w&#x2F;o key; 2= agent not running&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;agent_run_state&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;ssh-add&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;l&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;|&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; &#x2F;dev&#x2F;null&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;&amp;gt;&amp;amp;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt;?&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;14&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;SSH_AUTH_SOCK&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; ]&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;|&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;agent_run_state&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span&gt; ]&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;15&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;    agent_start&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;16&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;    ssh-add&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;17&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;elif&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;SSH_AUTH_SOCK&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; ]&lt;&#x2F;span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;agent_run_state&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt; ]&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;18&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;    ssh-add&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;19&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;20&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;unset&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; env&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Working with many GIT repos and dont want to pull manually:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;pull_all&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  FAILS&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  workdir&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;pwd&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;  for&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; REPO&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; *&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; -d&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;REPO&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;.git&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; ]&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; then&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; continue&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;    echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;e&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;GRN&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Entering and performing GIT PULL on &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;REPO&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;NC&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;    cd&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;REPO&lt;&#x2F;span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; bash&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;git pull --recurse-submodules&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt;?&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; -eq&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt; ]&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;      echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;e&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;GRN&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Done&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;NC&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;    else&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;      FAILS&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;+=&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;REPO&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;e&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;RED&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Command faild&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;NC&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;    fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;    cd&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;workdir&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;14&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;  done&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;15&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;  #&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Result&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;16&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;  if&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span&gt; $&lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;FAILS&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;@&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; -eq&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt; ]&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;17&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;    echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;e&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;GRN&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;All commands sucseeded&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;NC&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;18&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;  else&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;19&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;    echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;e&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;RED&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;The following repos exited with an error:\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;FAILS&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;@&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;NC&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;20&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;  fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;21&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Backup your Dotfiles:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Create Dotfiles&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;DOT_ARCHIVE&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;HOME&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;o&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;o&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;l&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;s&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;d&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;o&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;t&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;l&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;e&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;s&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;t&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;r&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;g&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;z&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; -f&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;DOT_ARCHIVE&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; ]&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;|&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span&gt; $(&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;date&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +%s&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt; - &lt;&#x2F;span&gt;&lt;span&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;date&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;r&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;DOT_ARCHIVE&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; -gt&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 604800&lt;&#x2F;span&gt;&lt;span&gt; ]&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    ORI_PWD&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;pwd&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;    cd&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;HOME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;    echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Creating dofiles archive... &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;    tar&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;czf&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;DOT_ARCHIVE&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-exclude=&lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;.vscode&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;.git&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;..&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;.*&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt; $(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;find&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; .&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;maxdepth&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;.*&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;%P\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;    gpg&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-yes&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-batch&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-passphrase=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;DOTFILES_PW&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; base64&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-decode&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; )&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;o&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;DOT_ARCHIVE&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;.gpg&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;DOT_ARCHIVE&lt;&#x2F;span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;    echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;done&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;    cd&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;ORI_PWD&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There are soo many more!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;choose-your-tools&quot;&gt;Choose your tools&lt;&#x2F;h2&gt;
&lt;p&gt;Take your time to find the appropriate tool for the job. And then learn it until you can use it in your sleep.&lt;br &#x2F;&gt;
Choose the editor and mail client you like and get really good at it. The same goes for your browser. All chromium based browsers support search-shortcuts in the addressbar of the browser. So you can directly search YouTube instead of googling YT, clicking the first link and then start searching form there. &lt;strong&gt;This saves more than 3 clicks!!!&lt;&#x2F;strong&gt;
&lt;img src=&quot;&#x2F;img&#x2F;blog&#x2F;search_shorts.png&quot; alt=&quot;VSCode&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;shortcuts-1&quot;&gt;Shortcuts!!!1!&lt;&#x2F;h2&gt;
&lt;p&gt;Not having to leave the keyboard to reach the mouse in order to click a button that is hidden behind two menues gives you a &lt;strong&gt;huge&lt;&#x2F;strong&gt; advantage over others. It lets you archive your goal quicker so you can focus on the next step. There are some universall shortcuts that work in almost every application that everybody shoud know:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Common:&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Copy              # Print                         # Search            # Swicht between windows  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;Ctrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; c&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;            Ctrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; p&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;                        Win&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; SeachWord&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;     Alt&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; tab&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Past              # Open                          # Desktop           # Open app x in taskbar  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;Ctrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; v&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;            Ctrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; o&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;                        Win&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; d&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;             Win&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span&gt; [0-9&lt;&#x2F;span&gt;&lt;span&gt;]  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Cut               # New document                  # Snap Window       # Duplicate&#x2F;Extend monitor  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;Ctrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; x&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;            Ctrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; n&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;                        Win&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; any-arrow&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;     Win&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; p&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Search            # New tab                       # Open explorer     # Open settings  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;Ctrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;            Ctrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; t&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;                        Win&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; e&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;             Win&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; i&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Undo              # close tab                     # Lock screen       # Screen Record  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;Ctrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; z&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;            Ctrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; w&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;                        Win&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; l&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;             Win&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; g&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Redo              # Select all                    # Emoj              #Paste with history clipbord  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;Ctrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; y&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;            Ctrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; a&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;                        Win&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; .&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;             Win&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; v&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Save              # Mark wohle word               # Open              Screenshot  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;14&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;Ctrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; s&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;            Ctrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Shift&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; arrow&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;            Ctrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; o&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;            Win&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Shift&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; s&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;em&gt;Browser:&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Reload            # Open history                  # Switch tabs       # Go to tab [1-9]  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;Ctrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; r&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;            Ctrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; h&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;                        Ctrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; tab&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;          Ctrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span&gt; [0-9&lt;&#x2F;span&gt;&lt;span&gt;]  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Add favo          # Focuse searchbar              # Reopen tab        # Zoom  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;4&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;Ctrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; d&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;            Ctrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; e&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;                        Ctrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Shift&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; t&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;    Ctrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Shift&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&#x2F;-&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;5&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Go back           # go forward  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;6&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;alt&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; left-arrow&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;    alt&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; right-arrow&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;em&gt;VSCode:&lt;&#x2F;em&gt;
&lt;img src=&quot;&#x2F;img&#x2F;blog&#x2F;vscode_shorts.png&quot; alt=&quot;VSCode&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;&#x2F;strong&gt; I also created a collection with my favorite shortcuts, scripts and tricks to work efficient as a programmer.&lt;br &#x2F;&gt;
&lt;a href=&quot;&#x2F;articles&#x2F;2022-02-working-effectively-1&quot;&gt;Read it here&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;See you!&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Productive Working - Be lazy and get things done - Part I</title>
        <published>2022-02-09T00:00:00+00:00</published>
        <updated>2022-02-09T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              hegerdes
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://henrikgerdes.me/blog/2022-02-working-effectively-1/"/>
        <id>https://henrikgerdes.me/blog/2022-02-working-effectively-1/</id>
        
        <content type="html" xml:base="https://henrikgerdes.me/blog/2022-02-working-effectively-1/">&lt;h1 id=&quot;productive-working-be-lazy-get-things-done-part-i&quot;&gt;Productive Working - Be lazy &amp;amp; get things done - Part I&lt;&#x2F;h1&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;My math teacher always told me that mathematicians are lazy and so should we. Only do the minimal number of steps to reach your desired destination. Whether or not these steps are simple in themselves is another matter. But somehow this phrase stuck with me.&lt;br &#x2F;&gt;
As I grow older I measured more value to my time. Doing my obligatory tasks efficiently gave me more time that I could spend on hobbies. So developed certain principles to get my stuff done, some of which I want to share today.&lt;br &#x2F;&gt;
&lt;img src=&quot;&#x2F;img&#x2F;blog&#x2F;efficient.jpg&quot; alt=&quot;Pic&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;overall-principles&quot;&gt;Overall Principles&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;em&gt;Disclaimer:&lt;&#x2F;em&gt; The following practices have been developed with an IT background and may not be applicable to everyone. However, I have tried to make the introductory practices as general as possible so that they can be used by as many people as possible.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;time-managment&quot;&gt;Time Managment&lt;&#x2F;h3&gt;
&lt;p&gt;To increase our efficiency we need to measure the amount of tasks we can complete in a certain amount of time. Split the amount of time you have in equaly sized chunks like 15mins. Prioritize your tasks according to their importance and duration. If you complete 3-4 small tasks within the first 15mins of allocated time, the amount of overall work you will have to complete looks a lot smaller, and you are more motivated. This can be things like teaching garbage, putting away clothes or taking away a letter&#x2F;package. For work allocate one or two chunks of our time for replaying to emails. Collect the mails over the day and replay to them on one session, &lt;strong&gt;don’t&lt;&#x2F;strong&gt; let incoming mails distract you from your current task. Finish your current tasks and then start something new. Peaking at the mail or your phone will only take a second, but it will take you over 1.5 minutes to fully mentally switch back to the previous task. A wonderful article from Johnn Hari in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.theguardian.com&#x2F;science&#x2F;2022&#x2F;jan&#x2F;02&#x2F;attention-span-focus-screens-apps-smartphones-social-media&quot;&gt;The Gurdian&lt;&#x2F;a&gt; diecribes how our all attention span decreased how &lt;em&gt;expensive&lt;&#x2F;em&gt; these context switches between tasks are. Tasks can be completed a lot quicker when you fully concentrate on one thing at a time.&lt;br &#x2F;&gt;
When the amount of tasks becomes too much to sort in your head write them down or maybe even visualize them with a method like Gnatt diagrams:
&lt;img src=&quot;&#x2F;img&#x2F;blog&#x2F;gnatt.png&quot; alt=&quot;Gnatt&quot; &#x2F;&gt;
These diagrams allow to visually lay out your tasks and identify blocking tasks. These are tasks that have to be done before others can start. Before you can send a package you have to pack it first. When you wait for certain things to finish you can complete other stuff. For example while waiting for your oven to heat up your food you can clean and store the dishes from last day. Combining things like putting your cloths in the washing machine while heading downstairs to buy groceries allows you to complete multiple things in one run.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;take-breaks&quot;&gt;Take breaks&lt;&#x2F;h3&gt;
&lt;p&gt;Keeping up with all the tasks of today’s life is exhausting. So you need time to recharge. Keep this in mind when planing you day and allocate some breaks. When taking a break really stop what you were working on, stand up and do something that lets you relax for a little time. Don’t feel bad for taking these breaks, they are in your schedule and there letting you brain relax a little. If you are disturbed by others tell them that you are having a break right now and will come back to them in 10 min.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;recurring-tasks&quot;&gt;Recurring Tasks&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;routine&quot;&gt;Routine&lt;&#x2F;h3&gt;
&lt;p&gt;Certain tasks keep recurring and need to be done over and over again. Plan these tasks in advance, do not be surprised by them and try to develop regular processes so that they become a routine. Once these tasks have entered the daily routine, you can do them in your sleep. If you notice that the current task exhausts you, or you get stuck, you can take a break and while going for a walk you can complete some of these recurring tasks. The brain can relax during this time and you don’t feel guilty for interrupting your current task, because you are doing other tasks. These breaks may help you to find a new point of view to the previous task. More than once the visit to the restroom or quick shower gave me a new approach for autually solving my previos task 😁&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;&#x2F;strong&gt; I also created a collection with my favorite shortcuts, scripts and tricks to work efficient as a programmer.&lt;br &#x2F;&gt;
&lt;a href=&quot;&#x2F;articles&#x2F;2022-02-working-effectively-2&quot;&gt;Read it here&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;See you!&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>LaTeX - A getting started for Devs</title>
        <published>2022-01-22T00:00:00+00:00</published>
        <updated>2022-01-22T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              hegerdes
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://henrikgerdes.me/blog/2022-01-vscode-latex/"/>
        <id>https://henrikgerdes.me/blog/2022-01-vscode-latex/</id>
        
        <content type="html" xml:base="https://henrikgerdes.me/blog/2022-01-vscode-latex/">&lt;h1 id=&quot;getting-started-with-latex-as-a-dev&quot;&gt;Getting started with LaTex as a Dev&lt;&#x2F;h1&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;about-latex&quot;&gt;About LaTeX&lt;&#x2F;h2&gt;
&lt;p&gt;LaTeX is a typesetting system that allows the user to write plain text, while the formatting is provided via markup tags, similar to &lt;code&gt;HTML&lt;&#x2F;code&gt;. It differs from WYSIWYG (&lt;em&gt;What You See Is What You Get&lt;&#x2F;em&gt;) applications like Word in that the final document must first be generated by a compiler. While the output of a LaTeX document is reproducible, minimal and just &lt;strong&gt;&lt;em&gt;beautiful&lt;&#x2F;em&gt;&lt;&#x2F;strong&gt;, it can be a challenge to get started for beginners. To get started users need to choose one of the multiple existing LaTeX distributions, choose an editor and setup a script to automatically build the document and preview it.&lt;&#x2F;p&gt;
&lt;p&gt;This article will automate and abstract most of the pain points and will let you focus on the content - like it is supposed by LaTeX.
&lt;img src=&quot;&#x2F;img&#x2F;blog&#x2F;tex-wide.png&quot; alt=&quot;Pic&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;!-- &lt;img src=&quot;https:&#x2F;&#x2F;latex.codecogs.com&#x2F;gif.latex?O_t=\text { Onset event at time bin \LaTeX } t&quot; width=&quot;10&quot;&#x2F;&gt; test
Lift($L$) can be determined by Lift Coefficient ($C_L$) like the following equation.
$$ L = \frac{1}{2} \rho v^2 S C_L $$ --&gt;
&lt;h2 id=&quot;functions&quot;&gt;Functions&lt;&#x2F;h2&gt;
&lt;p&gt;The setup provided by this article you will have the following features:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;A quick, clean, working LaTeX environment setup based on TeXLive&lt;&#x2F;li&gt;
&lt;li&gt;Pandoc - To convert your projects between different formats&lt;&#x2F;li&gt;
&lt;li&gt;Have LaTeX Workshop an LaTeX Utilities preinstalled&lt;&#x2F;li&gt;
&lt;li&gt;GUI for math symbols and some TiKz&lt;&#x2F;li&gt;
&lt;li&gt;BibTeX support&lt;&#x2F;li&gt;
&lt;li&gt;Spell checking&lt;&#x2F;li&gt;
&lt;li&gt;Markdown support&lt;&#x2F;li&gt;
&lt;li&gt;Git support&lt;&#x2F;li&gt;
&lt;li&gt;Scientific project template&lt;&#x2F;li&gt;
&lt;li&gt;Have our environment on a remote computer&lt;&#x2F;li&gt;
&lt;li&gt;A platform independent setup that can be used on any OS (Win&#x2F;Unix&#x2F;macOS)&lt;&#x2F;li&gt;
&lt;li&gt;Have a setup that is faster than MiKTeX on Windows&lt;&#x2F;li&gt;
&lt;li&gt;Support for x86&#x2F;arm&#x2F;arm64 architectures&lt;&#x2F;li&gt;
&lt;li&gt;Persistent bash_history&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;pre-requirements&quot;&gt;Pre-Requirements&lt;&#x2F;h2&gt;
&lt;p&gt;This is a &lt;em&gt;getting-started&lt;&#x2F;em&gt; guide focused on developers. Therefore, it will use tools common in the software developing world. Nevertheless, everyone can follow this guide to create a quick latex environment.&lt;&#x2F;p&gt;
&lt;p&gt;The following tools are needed for this guide:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;vscodoe&quot;&gt;VSCodoe&lt;&#x2F;h3&gt;
&lt;p&gt;VSCode is a cross-platform text editor designed for fast coding developed by Microsoft. It is heavily extendable with various extensions provided by a large community. It can be downloaded &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;code.visualstudio.com&#x2F;&quot;&gt;here&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;docker&quot;&gt;Docker&lt;&#x2F;h3&gt;
&lt;p&gt;Docker is a universal container runtime that allows users to run various software in a predefined environment isolated from the actual host system. Depending on your system you need one of the following:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Host&lt;&#x2F;th&gt;&lt;th&gt;Version&lt;&#x2F;th&gt;&lt;th&gt;Link&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Linux&lt;&#x2F;td&gt;&lt;td&gt;docker-ce&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.docker.com&#x2F;engine&#x2F;install&#x2F;debian&#x2F;&quot;&gt;Download&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Windows&lt;&#x2F;td&gt;&lt;td&gt;Docker Desktop&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.docker.com&#x2F;desktop&#x2F;windows&#x2F;install&#x2F;&quot;&gt;Download&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;MacOS&lt;&#x2F;td&gt;&lt;td&gt;Docker Desktop&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.docker.com&#x2F;desktop&#x2F;mac&#x2F;install&#x2F;&quot;&gt;Download&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;&#x2F;em&gt; Docker builds upon functions provided by the Linux kernel. Windows and macOS need to virtualize the kernel. Therefore, the best performance is achievable on Linux.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;getting-started&quot;&gt;Getting started&lt;&#x2F;h2&gt;
&lt;p&gt;To get started you have two options: Having the source files locally on host drive or in a persistent volume managed by Docker.&lt;br &#x2F;&gt;
If you pan to modify and access your project files with other tools as well I would suggest using the local setup. For slightly better disk performance or if you just want to use VSCode to edit your document you can also use a persistent volume managed by Docker.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;local-setup&quot;&gt;Local setup&lt;&#x2F;h3&gt;
&lt;p&gt;The TeX source is on your host OS and gets mounted as volume&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Open a terminal an type:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;git&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; clone&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; https:&#x2F;&#x2F;github.com&#x2F;hegerdes&#x2F;VSCode-LaTeX-Container&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;code&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; VSCode-LaTeX-Container&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; In VSCode hit F1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; Remote-Containers: Reopen in Container&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Wait for the initial pull and build&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Note: You need to have Docker and VSCode remote extentions installed&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Search for &amp;quot;ms-vscode-remote.vscode-remote-extensionpack&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;in-a-container&quot;&gt;In a container&lt;&#x2F;h3&gt;
&lt;p&gt;The entire project is within the container&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Open VSCode&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; In VSCode hit F1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; Remote-Containers: Clone Repository in Container Volume&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;4&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; https:&#x2F;&#x2F;github.com&#x2F;hegerdes&#x2F;VSCode-LaTeX-Container&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;5&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Wait for the initial pull and build&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;6&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Note: You need to have Docker and VSCode remote extentions installed&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;7&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Search for &amp;quot;ms-vscode-remote.vscode-remote-extensionpack&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;👉 Start typing you next big article!&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;some-background&quot;&gt;Some background:&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;the-latex-template&quot;&gt;The LaTeX template&lt;&#x2F;h3&gt;
&lt;!-- ![Pic](&#x2F;img&#x2F;blog&#x2F;latex-template.png) --&gt;
&lt;p&gt;The included template was build up over the time and is designed for scientific projects. But I didn’t start from scratch either. Credit goes to:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;latex&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;%&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Original author:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;%&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; WikiBooks (LaTeX - Title Creation) with modifications by:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;%&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Vel (vel@latextemplates.com)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;4&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;%&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; hegerdes (hegerdes@outlook.de)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;about-the-docker-image&quot;&gt;About the Docker image&lt;&#x2F;h3&gt;
&lt;p&gt;There are multiple base images &lt;strong&gt;debian-[bullseye|buster (deprecated)] and ubuntu-[focal|bionic (deprecated)]&lt;&#x2F;strong&gt;. All these images have &lt;strong&gt;texlive, texlive-latex-extra texlive-lang-english, texlive-luatex, texlive-xetex, texlive-pstricks, texlive-science, latexmk, cm-super, chktex&lt;&#x2F;strong&gt; with additional tools like &lt;strong&gt;git, zsh and pandoc(not in alpine)&lt;&#x2F;strong&gt; installed. Every image is available on x86&#x2F;arm&#x2F;arm64 architectures.&lt;&#x2F;p&gt;
&lt;p&gt;The slim images only contain &lt;strong&gt;texlive, texlive-latex-extra, texlive-lang-english, latexmk, cm-super, chktex&lt;&#x2F;strong&gt;
If you want a minimal image use these, but this might lack common tools&#x2F;packages.&lt;&#x2F;p&gt;
&lt;p&gt;There are two full images that contain &lt;strong&gt;everything&lt;&#x2F;strong&gt; in the LaTeX world except for docs. These are &lt;strong&gt;BIG&lt;&#x2F;strong&gt; and generally not recommended for fast startups.&lt;&#x2F;p&gt;
&lt;p&gt;There are a bunch of language specific images that are build up on the &lt;strong&gt;bullseye-base&lt;&#x2F;strong&gt; and &lt;strong&gt;focal-base&lt;&#x2F;strong&gt; images. Languages are: &lt;strong&gt;all, arabic, chinese, cjk, cyrillic, czechslovak, english, european, french, german, greek, italian, japanese, korean, other, polish, portuguese, spanish&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Use one of these if your work on a none English project! Simply change the &lt;code&gt;VARIANT&lt;&#x2F;code&gt; arg in the devcontainer.json to &lt;code&gt;bullseye-lang-&amp;lt;YOUR_LANGUAGE&amp;gt;&lt;&#x2F;code&gt; or &lt;code&gt;ubuntu-lang-&amp;lt;YOUR_LANGUAGE&amp;gt;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I plan on updating these images every second month.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;vscode-workspace&quot;&gt;VSCode workspace&lt;&#x2F;h3&gt;
&lt;p&gt;I added a VSCode workspace file with &lt;em&gt;sensible&lt;&#x2F;em&gt; setting. It includes some settings for Docker and the LaTeX extensions. Feel free to customize it after your own taste.&lt;&#x2F;p&gt;
&lt;p&gt;If you want to see what I did with the template look over to &lt;a href=&quot;&#x2F;papers&quot;&gt;henrikgerdes.me&#x2F;papers&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-all-this&quot;&gt;Why all this&lt;&#x2F;h2&gt;
&lt;p&gt;I always liked the concept of LaTeX and its focus on content instead of the formatting. But getting started was hard and I wanted to contribute to make it a little more accessible. I first used MiKTeX and TeXworks, but I found the usage of shortcuts hard and didn’t like the PDF viewer. I switched to Notepad++, SumataPDF (both great tools) and a handy script. It was great until my projects got bigger. So I used VSCode and LaTeX Workshop and I loved it. All my shortcuts and tools I used before now applied to LaTeX. I was satisfied until I realized how slow MiKTeX on Windows is compared to Linux.&lt;&#x2F;p&gt;
&lt;p&gt;I love Linux, but some things are more convenient on Windows. I started my Bachelor theses about development environments and the usage of container tools. So I have further developed my setup to bring everything together.&lt;&#x2F;p&gt;
&lt;p&gt;I found that the &lt;code&gt;tianon&#x2F;latex&lt;&#x2F;code&gt; and other image were outdated and did not meet my expectations. I rather created my own image. It is own the large side, but I rather have all my tools there at any time instead of being slowed down by missing them or have to install packages manually. I hope some of you find some interesting tips and tricks in my setup.&lt;&#x2F;p&gt;
&lt;p&gt;If you find any issues let me &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;hegerdes&#x2F;VSCode-LaTeX-Container&#x2F;issues&quot;&gt;know&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;See you!&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Reddit Video Downloader</title>
        <published>2021-12-24T00:00:00+00:00</published>
        <updated>2021-12-24T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              hegerdes
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://henrikgerdes.me/blog/2021-12-reddvid/"/>
        <id>https://henrikgerdes.me/blog/2021-12-reddvid/</id>
        
        <content type="html" xml:base="https://henrikgerdes.me/blog/2021-12-reddvid/">&lt;h1 id=&quot;one-day-build-webapp-to-download-videos-from-reddit&quot;&gt;One Day Build: WebApp to download Videos from Reddit&lt;&#x2F;h1&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;It has become kind of annoying to download a simple video from Reddit. My sister wanted to save a video but couldn’t do it. So, I did what all programmers do - I wrote a small app.&lt;br &#x2F;&gt;
You can try it out &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;reddvid.netlify.app&#x2F;&quot;&gt;here&lt;&#x2F;a&gt; or use it via your terminal like described &lt;em&gt;below&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;img&#x2F;blog&#x2F;reddvid_small.jpg&quot; alt=&quot;Pic&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;some-background&quot;&gt;Some Background&lt;&#x2F;h2&gt;
&lt;p&gt;The URLs of videos on Reddit are not directly visible. You have dig through some HTML tags and even more annoying, Reddit sores to video and audio files separably. So we need to find the URLs, download the content and combine video and audio. For this I wrote a small Python backend.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-backend&quot;&gt;The Backend&lt;&#x2F;h3&gt;
&lt;p&gt;The backend requires a URL as an argument, and makes a request to that URL. The result is analyzed with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.crummy.com&#x2F;software&#x2F;BeautifulSoup&#x2F;bs4&#x2F;doc&#x2F;&quot;&gt;&lt;code&gt;BeautifulSoup&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;. After the video and audio URL got extracted, both files are downloaded separably and are then combined with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;ffmpeg.org&#x2F;&quot;&gt;&lt;code&gt;ffmpeg&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.
I used Flask to handle the HTTP requests and provide routing. It is a simple-to-use minimal framework that was fast to implement.&lt;br &#x2F;&gt;
I wanted people to be able to use the backend directly, so it is possible to download videos with a terminal. The following bash function should download any Reddit video for you without the need to use any browser:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Add this function to yor terminal session - or put it into your .bash_rc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; This need wget, curl and jq&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;reddvid&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;4&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;    wget&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; https:&#x2F;&#x2F;reddvid.herokuapp.com&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;curl&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;X&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; GET&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;https:&#x2F;&#x2F;reddvid.herokuapp.com&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-form&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;url=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;  |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; jq&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;r&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;.download&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;6&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Call the function&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;7&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;reddvid&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;REDDIT_UR&lt;&#x2F;span&gt;&lt;span&gt;L&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Any non-technical person has the option to use the WebApp frontend.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-frontend&quot;&gt;The Frontend&lt;&#x2F;h3&gt;
&lt;p&gt;The WebApp is a simple VUE app that was build with nuxt.js, simply because I already know VUE and I like my WebApps to be a static page that can be served by any HTTP-Server. This allows for a broad range of deployment options.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;deployment&quot;&gt;Deployment&lt;&#x2F;h3&gt;
&lt;p&gt;The deployment strategy I chose was only based on tractability and cheep criteria. I am a student that did this project for fun and did not and couldn’t spend much on server infrastructure. The backend is deployed via a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;hub.docker.com&#x2F;r&#x2F;hegerdes&#x2F;reddvid&quot;&gt;Python Docker Image&lt;&#x2F;a&gt; on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;heroku.com&#x2F;&quot;&gt;Heroku&lt;&#x2F;a&gt; with a deployment option that goes to sleep after 30 min. The WebApp is hosted on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.netlify.com&#x2F;&quot;&gt;Netlify&lt;&#x2F;a&gt; which is a cheap option for static apps that creates a new deployment for every commit.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;have-fun&quot;&gt;Have Fun&lt;&#x2F;h2&gt;
&lt;p&gt;This is a project I build for my own usage and without much testing. I’m sure it has bugs and that it will beak on specific actions. Just use it if it is handy to you, share your thoughts, encountered issues and possible improvements. Swarm knowledge is the bast way to learn!!!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;See you!&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Install &amp; Configure Grafana Promtail</title>
        <published>2021-12-21T00:00:00+00:00</published>
        <updated>2021-12-21T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              hegerdes
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://henrikgerdes.me/blog/2021-12-promtail/"/>
        <id>https://henrikgerdes.me/blog/2021-12-promtail/</id>
        
        <content type="html" xml:base="https://henrikgerdes.me/blog/2021-12-promtail/">&lt;h1 id=&quot;install-configure-promtail-for-grafana-loki&quot;&gt;Install &amp;amp; Configure Promtail for Grafana Loki&lt;&#x2F;h1&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;This post will demonstrate a reliable and easy way to install Promtail to your server in order to collect all system logs in a central place for proper monitoring.&lt;br &#x2F;&gt;
&lt;em&gt;NOTE:&lt;&#x2F;em&gt; This post will only cover the install and setup for Linux based systems&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;img&#x2F;blog&#x2F;promtail.jpg&quot; alt=&quot;pic&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;about-promtail&quot;&gt;About Promtail&lt;&#x2F;h2&gt;
&lt;p&gt;Promtail is part of the Grafana platform. The Grafana platform is increasing in popularity due to its open-source nature, easy usability and ability to plug into existing infrastructure. Grafana allows to visualize and query data from multiple sources. The data can be stored in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;grafana.com&#x2F;docs&#x2F;grafana&#x2F;latest&#x2F;datasources&#x2F;influxdb&#x2F;&quot;&gt;InfluxDB&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;grafana.com&#x2F;docs&#x2F;grafana&#x2F;latest&#x2F;datasources&#x2F;elasticsearch&#x2F;&quot;&gt;ELK&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;grafana.com&#x2F;docs&#x2F;grafana&#x2F;latest&#x2F;datasources&#x2F;prometheus&#x2F;&quot;&gt;Prometheus&lt;&#x2F;a&gt; or the in-house &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;grafana.com&#x2F;docs&#x2F;loki&#x2F;latest&#x2F;&quot;&gt;Loki&lt;&#x2F;a&gt; data store. Loki is often called the Prometheus version of logs. But to query log-data in Loki over Grafana, the logs have to be shipped first. For Docker, this can easily be done with the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;grafana.com&#x2F;docs&#x2F;loki&#x2F;latest&#x2F;&quot;&gt;Docker Loki Log-Driver&lt;&#x2F;a&gt;, but what about logs of none dockerized applications or logs of the host system? This is where Promtail comes in! It constantly reads log-files (e.g. in &lt;code&gt;&#x2F;var&#x2F;log&lt;&#x2F;code&gt;) and sends them to a Loki instance.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;installing-promtail&quot;&gt;Installing Promtail&lt;&#x2F;h2&gt;
&lt;p&gt;Promtail is available as a static binary on the official &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;grafana&#x2F;loki&#x2F;releases&quot;&gt;Grafana Loki GitHub&lt;&#x2F;a&gt; page. We could download it by hand, &lt;em&gt;or&lt;&#x2F;em&gt; we could use the terminal like a real programmer:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Download latest:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;curl&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;s&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; https:&#x2F;&#x2F;api.github.com&#x2F;repos&#x2F;grafana&#x2F;loki&#x2F;releases&#x2F;latest&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;    grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; browser_download_url&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;    cut&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;d&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; promtail-linux-amd64.zip&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;    wget&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Unzip and&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;unzip&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; promtail-linux-amd64.zip&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;mv&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; promtail-linux-amd64&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;usr&#x2F;local&#x2F;bin&#x2F;promtail&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Verify&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;promtail&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;-version&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We are using the GitHub API to get the latest release of Promtail and are filtering for the &lt;code&gt;linux-and64&lt;&#x2F;code&gt; binary with &lt;code&gt;grep&lt;&#x2F;code&gt;. The result gets piped to &lt;code&gt;wget&lt;&#x2F;code&gt; in order to download the zip file. Subsequently, we unzip the archive and move it to a place that is in our &lt;code&gt;PATH&lt;&#x2F;code&gt;. Now we can test if Promtail is working.&lt;&#x2F;p&gt;
&lt;p&gt;Now we need a Promtail config:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Promtail config&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;s&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;erver&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  d&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;isable&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;p&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ositions&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  f&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ilename&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;tmp&#x2F;promtail-positions.yaml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;lients&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span&gt;  -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; u&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;rl&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; h&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ttp:&#x2F;&#x2F;&amp;lt;SERVER&amp;gt;:3100&#x2F;loki&#x2F;api&#x2F;v1&#x2F;push&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;s&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;crape_configs&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;span&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; j&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ob_name&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; a&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;uthlog&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  s&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;tatic_configs&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;14&lt;&#x2F;span&gt;&lt;span&gt;  -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; t&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;argets&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;15&lt;&#x2F;span&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; l&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ocalhost&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;16&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;    l&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;abels&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;17&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;      j&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ob&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; a&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;uthlog&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;18&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;      s&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;hipper&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; p&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;romtail&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;19&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;      _&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;_path__&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;var&#x2F;log&#x2F;auth.log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;20&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;21&lt;&#x2F;span&gt;&lt;span&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; j&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ob_name&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; d&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;aemonlog&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;22&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;  s&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;tatic_configs&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;23&lt;&#x2F;span&gt;&lt;span&gt;  -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; t&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;argets&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;24&lt;&#x2F;span&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; l&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ocalhost&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;25&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;    l&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;abels&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;26&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;      j&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;ob&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; s&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;yslog&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;27&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;      s&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;hipper&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; p&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;romtail&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;28&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;      _&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;_path__&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;var&#x2F;log&#x2F;daemon.log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Our Promtail do not need to receive any logs we are just querying local files, so we can disable the server. The positions-file is a marker file for Promtail to remember where it stopped reading a log file, and the client is the destination of our logs. The &lt;code&gt;scrape_configs&lt;&#x2F;code&gt; specifies what logs Promtail should send to Loki. In this example, we are using &lt;code&gt;daemon.log&lt;&#x2F;code&gt; and &lt;code&gt;auth.log&lt;&#x2F;code&gt;. There are tones of other possibilities, like access logs from ´nginx´ and alike, but this would be too much for this post.&lt;&#x2F;p&gt;
&lt;p&gt;We could start Promtail with &lt;code&gt;promtail -config.file promtail-config.yml&lt;&#x2F;code&gt;, but we would have little control over the process, and it would not start again if the process fails or the host is restarted. So let’s create separate user for Promtail (optional) and a service:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Create promtail user&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;useradd&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;r&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; promtail&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;usermod&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;G&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; adm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; promtail&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Create a service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;tee&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;etc&#x2F;systemd&#x2F;system&#x2F;promtail.service&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;&amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;EOF&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;dev&#x2F;null&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;[Unit]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Description=Promtail service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;After=network.target&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;[Service]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Type=simple&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;User=promtail&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ExecStart=&#x2F;usr&#x2F;local&#x2F;bin&#x2F;promtail -config.file &#x2F;path&#x2F;to&#x2F;promtail-config.yml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;14&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Restart=always&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;15&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;16&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;[Install]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;17&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;WantedBy=multi-user.target&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;18&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;EOF&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now we can simply run the following and have a reliable and good Promtail setup that can easily be automated with tools like Ansible or Puppet.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Start the service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; systemctl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; daemon-reload&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; systemctl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; enable&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; promtail.service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;4&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; systemctl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; start&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; promtail.service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;5&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Verify status&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;6&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; systemctl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; status&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; promtail.service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;See you!&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Dockerfile for NodeJS &amp; Typescript</title>
        <published>2021-11-15T00:00:00+00:00</published>
        <updated>2021-11-15T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              hegerdes
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://henrikgerdes.me/blog/2021-11-dockerfile-typescript-node/"/>
        <id>https://henrikgerdes.me/blog/2021-11-dockerfile-typescript-node/</id>
        
        <content type="html" xml:base="https://henrikgerdes.me/blog/2021-11-dockerfile-typescript-node/">&lt;h1 id=&quot;how-to-build-a-docker-image-for-a-typescript-based-nodejs-project&quot;&gt;How to build a Docker image for a TypeScript based NodeJS project&lt;&#x2F;h1&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;You just finished your TypeScript project and now you want to release it to the internet by using ECS, GKE, Azure or any other cloud service? Or maybe you just want to share it with your co-workers without having them to install and configure additional software. Docker is a great use case for this!&lt;&#x2F;p&gt;
&lt;p&gt;This post shows demonstrates how to create an optimized production ready Docker image for your project.
&lt;img src=&quot;&#x2F;img&#x2F;blog&#x2F;docker.png&quot; alt=&quot;pic&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pre-requirements&quot;&gt;Pre-Requirements&lt;&#x2F;h2&gt;
&lt;p&gt;In order to build a Docker image you must have access to system that has the Docker engine installed. Depending on your system you need one of the following:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Host&lt;&#x2F;th&gt;&lt;th&gt;Version&lt;&#x2F;th&gt;&lt;th&gt;Link&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Linux&lt;&#x2F;td&gt;&lt;td&gt;docker-ce&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.docker.com&#x2F;engine&#x2F;install&#x2F;debian&#x2F;&quot;&gt;Download&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Windows&lt;&#x2F;td&gt;&lt;td&gt;Docker Desktop&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.docker.com&#x2F;desktop&#x2F;windows&#x2F;install&#x2F;&quot;&gt;Download&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;MacOS&lt;&#x2F;td&gt;&lt;td&gt;Docker Desktop&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.docker.com&#x2F;desktop&#x2F;mac&#x2F;install&#x2F;&quot;&gt;Download&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;&#x2F;em&gt; Docker builds upon functions provided by the Linux kernel. Windows and macOS need to virtualize the kernel. Therefore, the best performance is achievable on linux.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;project-setup&quot;&gt;Project setup&lt;&#x2F;h2&gt;
&lt;p&gt;Assuming the following file structure:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;project&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  - src&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      - server.ts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      - util.ts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  - node_modules&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  - index.ts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  - tsconfig.json&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  - package.json&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In order to run our app we need to:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Install our dependencies&lt;&#x2F;li&gt;
&lt;li&gt;Transpile TS to JS&lt;&#x2F;li&gt;
&lt;li&gt;Start our app&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This needs to be specified in our Dockerfile which acts as the build instructions for our Docker image. We create a file named Dockerfile and add the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;docker&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;FROM&lt;&#x2F;span&gt;&lt;span&gt; node&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;WORKDIR&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;app&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;4&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;COPY&lt;&#x2F;span&gt;&lt;span&gt; . &#x2F;app&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;5&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;RUN&lt;&#x2F;span&gt;&lt;span&gt; npm install &amp;amp;&amp;amp; npm build&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Our image is based on the official NodeJS Docker image. We copy our source code into the image and run the install and compile command.&lt;&#x2F;p&gt;
&lt;p&gt;This would work but is not an optimal solution. We are using Docker to get a consistent runtime that works everywhere but by not using a specific tag for our base image we are losing the consistence. If no tag is specified the &lt;code&gt;latest&lt;&#x2F;code&gt; tag is used which changes often.&lt;&#x2F;p&gt;
&lt;p&gt;A lot of images include a lot of software that we actually do not need. These increases image size, storage consumption and network transfer times. It also increases to attack surface because any other program can have additional vulnerabilities. Let’s fix some of this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;docker&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;FROM&lt;&#x2F;span&gt;&lt;span&gt; node:16-alpine&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;WORKDIR&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;app&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;COPY&lt;&#x2F;span&gt;&lt;span&gt; package.json package-lock.json &#x2F;app&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;RUN&lt;&#x2F;span&gt;&lt;span&gt; npm install&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;COPY&lt;&#x2F;span&gt;&lt;span&gt; . &#x2F;app&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;RUN&lt;&#x2F;span&gt;&lt;span&gt; npm run build&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now we are using an exact version and the much smaller alpine version of Nodes Docker image. We are also utilizing Dockers caching functionality. Docker only runs the commands that changed since the last run. Since we are not modifying the &lt;code&gt;package.json&lt;&#x2F;code&gt; as often as our source code we can cache the install command and save time. This is better but not perfect yet. In order to run our app we neither need the TypeScript files nor the &lt;code&gt;tsc&lt;&#x2F;code&gt; compiler.&lt;&#x2F;p&gt;
&lt;p&gt;This is where multi-stage build come handy. We can build our JavaScript in one stage and then copy the result to another stage that is actually used.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;docker&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;FROM&lt;&#x2F;span&gt;&lt;span&gt; node:16-alpine &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;as&lt;&#x2F;span&gt;&lt;span&gt; build&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;WORKDIR&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;app&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;COPY&lt;&#x2F;span&gt;&lt;span&gt; package.json package-lock.json &#x2F;app&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;RUN&lt;&#x2F;span&gt;&lt;span&gt; npm install&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;COPY&lt;&#x2F;span&gt;&lt;span&gt; . &#x2F;app&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;RUN&lt;&#x2F;span&gt;&lt;span&gt; npm run generate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;FROM&lt;&#x2F;span&gt;&lt;span&gt; node:16-alpine &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;as&lt;&#x2F;span&gt;&lt;span&gt; production&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;USER&lt;&#x2F;span&gt;&lt;span&gt; node&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;WORKDIR&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;app&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;14&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;COPY&lt;&#x2F;span&gt;&lt;span&gt; --chown=node:node --from=build &#x2F;app&#x2F;compiledJS &#x2F;app&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;15&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;RUN&lt;&#x2F;span&gt;&lt;span&gt; npm install --only=production&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now the code is compiled in one stage and shipped in another. We are also changing to user in order to omit running our app as root. Lower privileges are another step to increase your app’s security.&lt;&#x2F;p&gt;
&lt;p&gt;To increase the flexibility of our Dockerfile we can add arguments. With arguments, we can influence the building process on execution without modifying the Dockerfile. A common argument is the &lt;code&gt;VARIANT&lt;&#x2F;code&gt; variable. Which allows to change the version of our base image.&lt;&#x2F;p&gt;
&lt;p&gt;The last step is to include an &lt;code&gt;ENTRYPOINT&lt;&#x2F;code&gt; to specify what command should be executed when a container is created. I strongly recommend to directly call &lt;code&gt;node index.js&lt;&#x2F;code&gt; instead of using &lt;code&gt;npm start&lt;&#x2F;code&gt;. When using &lt;code&gt;npm&lt;&#x2F;code&gt;, npm becomes our main process and acts as a process manager for the node process. Unfortunate &lt;code&gt;npm&lt;&#x2F;code&gt; performs poorly as a process manager. It does not redirect any control or exit signals to the main node process. This can lead to a container not willing to stop or an unexpected shutdown of our node process without properly handling exit tasks.&lt;&#x2F;p&gt;
&lt;p&gt;The final Dockerfile should look something like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;docker&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;FROM&lt;&#x2F;span&gt;&lt;span&gt; node:16-alpine &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;as&lt;&#x2F;span&gt;&lt;span&gt; build&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;WORKDIR&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;app&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;COPY&lt;&#x2F;span&gt;&lt;span&gt; package.json package-lock.json &#x2F;app&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;RUN&lt;&#x2F;span&gt;&lt;span&gt; npm install&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 6&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;COPY&lt;&#x2F;span&gt;&lt;span&gt; . &#x2F;app&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;RUN&lt;&#x2F;span&gt;&lt;span&gt; npm run generate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt; 9&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;ARG&lt;&#x2F;span&gt;&lt;span&gt; VARIANT=16-alpine&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;11&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;FROM&lt;&#x2F;span&gt;&lt;span&gt; node:${VARIANT} &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;as&lt;&#x2F;span&gt;&lt;span&gt; production&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;12&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;13&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;USER&lt;&#x2F;span&gt;&lt;span&gt; node&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;14&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;WORKDIR&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;app&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;15&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;COPY&lt;&#x2F;span&gt;&lt;span&gt; --chown=node:node --from=build &#x2F;app&#x2F;compiledJS &#x2F;app&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;16&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;RUN&lt;&#x2F;span&gt;&lt;span&gt; npm install --only=production&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;17&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;18&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;ARG&lt;&#x2F;span&gt;&lt;span&gt; COMMIT_TAG=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;none&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;19&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;LABEL&lt;&#x2F;span&gt;&lt;span&gt; COMMIT_TAG=$COMMIT_TAG&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;giallo-ln&quot;&gt;20&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;ENTRYPOINT&lt;&#x2F;span&gt;&lt;span&gt; [ &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;node&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; , &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;index,js&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We now can build our image with:&lt;br &#x2F;&gt;
&lt;code&gt;docker build -t my-app --build-arg COMMIT_TAG=&quot;version-1.0.0&quot; .&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Placeholder</title>
        <published>2021-11-14T00:00:00+00:00</published>
        <updated>2021-11-14T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              hegerdes
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://henrikgerdes.me/blog/2021-10-demo/"/>
        <id>https://henrikgerdes.me/blog/2021-10-demo/</id>
        
        <content type="html" xml:base="https://henrikgerdes.me/blog/2021-10-demo/">&lt;h1 id=&quot;more-is-comming-soon&quot;&gt;More is comming soon&lt;&#x2F;h1&gt;
&lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque consequat pretium mauris ac scelerisque. Sed semper egestas nisl. Integer tempus turpis mauris, eu dictum mauris porta id. Quisque nec ultricies erat. Mauris accumsan nisl velit, nec semper velit vehicula ornare. Pellentesque eu tortor ac ante finibus tincidunt. Phasellus tortor arcu, mattis id mauris a, fermentum pulvinar sem. Sed quis interdum velit. Vestibulum convallis arcu eget rutrum elementum. Nullam sapien orci, ullamcorper sit amet consequat at, tempus at dolor. Nunc et malesuada odio. Nam laoreet tempor metus vel vestibulum. Nullam convallis, risus eu venenatis rhoncus, sem ex bibendum enim, vel interdum dolor nisl quis urna. Curabitur in sodales enim, vel mattis velit&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;img&#x2F;blog&#x2F;soon.jpg&quot; alt=&quot;pic&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;See you&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
