<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>firewall on Digi Hunch</title><link>https://www.digihunch.com/tag/firewall/</link><description>Recent content in firewall on Digi Hunch</description><generator>Hugo -- gohugo.io</generator><language>en-US</language><lastBuildDate>Tue, 08 Apr 2025 14:19:11 -0400</lastBuildDate><atom:link href="https://www.digihunch.com/tag/firewall/index.xml" rel="self" type="application/rss+xml"/><item><title>Firewall Deployment Patterns</title><link>https://www.digihunch.com/2024/11/firewall-deployment-patterns/</link><pubDate>Sat, 16 Nov 2024 16:24:15 -0400</pubDate><guid>https://www.digihunch.com/2024/11/firewall-deployment-patterns/</guid><description>&lt;img src="https://www.digihunch.com/wp-content/uploads/2025/04/feature-fw-deploy.webp" alt="Featured image of post Firewall Deployment Patterns" /&gt;&lt;p class="wp-block-paragraph"&gt;The Hub-and-Spoke topology is the most common topic in the discussion for building cloud infrastructure design. This topology appeared in both AWS and Azure design papers and had been around as a very important option in physical networking design. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The AWS whitepaper &lt;a href="https://docs.aws.amazon.com/pdfs/whitepapers/latest/building-scalable-secure-multi-vpc-network-infrastructure/building-scalable-secure-multi-vpc-network-infrastructure.pdf"&gt;Building a Scalable and Secure Multi-VPC AWS Network Infrastructure &lt;/a&gt;has thorough discussion on the topology. This topology often feature a Transit Gateway as the hub. In addition to workload VPCs, the network topology often includes some special-purpose VPCs, such as &lt;a href="https://github.com/aws-samples/landing-zone-accelerator-on-aws-for-cccs-medium/blob/main/architecture-doc/readme.md#632-endpoint-vpc"&gt;interface endpoints&lt;/a&gt; VPC, or &lt;a href="https://github.com/aws-samples/landing-zone-accelerator-on-aws-for-cccs-medium/tree/main/architecture-doc#636-central-vpc"&gt;shared tooling &lt;/a&gt;VPCs. One of the special-purpose VPC is the inspection VPC. It is a key design area to suit the need of inspection and traffic management for the business and the design may vary a lot depending on the available inspection tools such as a Firewall appliance. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Inspection Requirements&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The most common situation with an enterprise is connecting with on-prem networking. Options including Direct Connect, site-to-site IPsec or SD-WAN overlay. The business decides whether and at what level they would like to inspect the traffic between on-prem and their VPCs. Here is an example.&lt;/p&gt;&#10;&lt;figure class="wp-block-table"&gt;&lt;table class="has-fixed-layout"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Connectivity&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Inspection Requirement&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Between Workload VPCs (East-West)&lt;/td&gt;&lt;td&gt;No inspection&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Between a workload VPC and a special-purpose VPC&lt;/td&gt;&lt;td&gt;Normal Inspection&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Ingress Traffic from Internet to Workload VPC&lt;/td&gt;&lt;td&gt;Deep Packet Inspection&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Egress Traffic from Workload VPC to Internet&lt;/td&gt;&lt;td&gt;Deep Packet Inspection&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Between Workload VPC and on-prem networking over Direct Connect&lt;/td&gt;&lt;td&gt;Normal Inspection&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&amp;#8230;&amp;#8230;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;With a normal inspection, the firewall appliance only checks the information in the packet&amp;#8217;s header, such as the source and destination IP addresses, port number, etc. With deep packet inspection, the appliance examins a larger range of metadata as well as the data in each packet. DPI provides a more effective mechanism to perform network packet filtering and find otherwise hidden threats. It is however an expensive operations from a performance standpoint. Ultimately the business makes the call but it is important to identify ALL connectivity scenarios in this phase and explicitly document the decision and rationales. They can choose from an NGFW product or the Network Firewall service from AWS, depending on capability required.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Inspection Architecture&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;At minimum, inspection is required for ingress and egress traffic to and from workload VPC. The design must account for both routing and inspection. Many would use the same VPC for ingress/egress traffic and for inspection. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;It is also possible to separate these two purposes into two different dedicated VPCs: an inspection VPC that hosts firewall services or appliances, and an ingress/egress VPC that directs traffic from and to the Internet but we must route the traffic to the inspection appliance. If all traffic to be inspected has to be routed through the Transit Gateway both ways, the cost would be high. In 2020 AWS introduced Gateway Load Balancer (GWLB) to address this use case. &lt;/p&gt;&#10;&lt;figure class="wp-block-image size-full"&gt;&lt;img loading="lazy" decoding="async" width="1024" height="351" src="https://www.digihunch.com/wp-content/uploads/2024/11/fw-gwlb.webp" alt="" class="wp-image-12996" srcset="https://www.digihunch.com/wp-content/uploads/2024/11/fw-gwlb.webp 1024w, https://www.digihunch.com/wp-content/uploads/2024/11/fw-gwlb-300x103.webp 300w, https://www.digihunch.com/wp-content/uploads/2024/11/fw-gwlb-768x263.webp 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The &lt;a href="https://aws.amazon.com/blogs/networking-and-content-delivery/integrate-your-custom-logic-or-appliance-with-aws-gateway-load-balancer/"&gt;recommended pattern&lt;/a&gt; using GWLB allows you to place firewall appliance and a GWLB in one VPC, and place the GWLB endpoint (GWLBE) in a different VPC. The connectivity between GWLBE and GWLB is backed by HyperPlane, a technology that also enables other endpoint service such as PrivateLink. The connectivity between GWLB and the appliance take place with &lt;a href="https://en.wikipedia.org/wiki/Generic_Network_Virtualization_Encapsulation"&gt;Geneve&lt;/a&gt; encapsulation. This pattern places any appliance behind an endpoint, so long as the appliance supports Geneve protocol. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The GWLB technology enables a number of inspection patterns based on distributed ingress paths, as summarized in &lt;a href="https://d1.awsstatic.com/architecture-diagrams/ArchitectureDiagrams/distributed-inspection-architectures-gwlb-ra.pdf"&gt;this&lt;/a&gt; document. Distributed ingress/egress means each workload VPC can have their own Internet Gateway and NAT gateways. They must configure their route table so as to send the traffic via GWLBEs to inspection appliances. In general, I recommend this pattern over the centralized &lt;a href="https://d1.awsstatic.com/architecture-diagrams/ArchitectureDiagrams/centralized-ingress-with-alb-and-ec2-target-ra.pdf?did=wp_card&amp;amp;trk=wp_card"&gt;ingress&lt;/a&gt;/&lt;a href="https://d1.awsstatic.com/architecture-diagrams/ArchitectureDiagrams/NAT-gateway-centralized-egress-ra.pdf?did=wp_card&amp;amp;trk=wp_card"&gt;egress&lt;/a&gt; patterns where only the inspection VPC can take ingress traffic from Internet Gateway. The &lt;a href="https://d1.awsstatic.com/events/reinvent/2021/Network_architectures_for_inbound_traffic_inspection_REPEAT_NET311-R1.pdf"&gt;Network architectures for ingress traffic inspection&lt;/a&gt; presentation from 2021 ReInvent covered this topic as well, especially about the scaling benefit of distributed ingress.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Firewall deployment patterns&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The firewall deployment pattern available differ between vendors and the requirements. Since the GWLB pattern places appliances behind the GWLB, the appliances rely on Geneve traffic that GWLB forward over. Some vendors may argue that this pattern keeps the NGFW product from performing other tasks that do not support Geneve traffic. One example is Network Address Translation. The native NAT gateway services is very expensive (consider &lt;a href="https://fck-nat.dev/stable/"&gt;fck-nat&lt;/a&gt; as an alternative for NAT). Many clients want to use the NAT feature of the NGFW product. The architecture therefore has to be adjusted in favour of centralized egress. Review &lt;a href="https://aws.amazon.com/blogs/networking-and-content-delivery/best-practices-for-deploying-gateway-load-balancer/"&gt;this post &lt;/a&gt;about one-arm mode and two-arm mode.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;If we have to go with central ingress/egress anyways, there are still numerous options. Take FortiGate for example, while the GWLB pattern of deployment is &lt;a href="https://github.com/fortinet/fortigate-terraform-deploy/tree/main/aws/7.6/gwlb-transit"&gt;supported&lt;/a&gt;, other available options include:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;a href="https://github.com/fortinet/fortigate-terraform-deploy/tree/main/aws/7.6/transitgwy"&gt;Traditional pattern&lt;/a&gt; with multiple interfaces across different subnets in the inspection VPC (L3 mode)&lt;/li&gt;&#10;&lt;li&gt;Integration with Transit Gateway using Transit Gateway &lt;a href="https://github.com/fortinet/fortigate-terraform-deploy/tree/main/aws/7.6/transitgwyconnect"&gt;Connect Attachment&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;Integration with Transit Gateway using Transit Gateway &lt;a href="https://community.fortinet.com/t5/Blogs/FortiGate-in-AWS-Landing-Zone-Accelerator/ba-p/339107"&gt;VPN Attachment&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I regard the first option as traditional because it does not &lt;span style="text-decoration: underline;"&gt;directly&lt;/span&gt; integrate with Transit Gateway and it is very similar to how we deploy them in a physical networking environment. Fortigate refers to it as &lt;a href="https://docs.fortinet.com/document/fortigate/7.4.0/ips-architecture-guide/756476/l3-nat-route-mode"&gt;L3 (NAT/route) mode&lt;/a&gt;. In this mode the Firewall appliance can also influence network routing. &lt;/p&gt;&#10;&lt;figure class="wp-block-image size-full"&gt;&lt;img loading="lazy" decoding="async" width="1024" height="680" src="https://www.digihunch.com/wp-content/uploads/2024/11/fgt-deploy.webp" alt="" class="wp-image-12997" srcset="https://www.digihunch.com/wp-content/uploads/2024/11/fgt-deploy.webp 1024w, https://www.digihunch.com/wp-content/uploads/2024/11/fgt-deploy-300x199.webp 300w, https://www.digihunch.com/wp-content/uploads/2024/11/fgt-deploy-768x510.webp 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The second and the third options are similar except for different types of Transit Gateway attachments are used. The reason to directly integrate with Transit Gateway is so that the Transit Gateway can route the traffic for inspection therefore no need for a Gateway Load Balancer, and thus no dependency on the firewall features supporting Geneve. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The second option builds a GRE (Generic Routing Encapsulation) tunnel over a Transit Gateway Connect attachment as the transport tunnel, and uses BGP to exchange routes between the Transit Gateway and the appliance. It treats the firewall instances as &lt;a href="https://aws.amazon.com/blogs/networking-and-content-delivery/migrating-sd-wan-appliances-to-aws-transit-gateway-connect/"&gt;SD-WAN appliance&lt;/a&gt; and has performance benefit. The third option uses VPN attachment with the main benefit of encryption if it is part of compliance requirement.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Rules&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The rule configuration for Firewall is critical to the operation of the entire multi-VPC network configuration. Unfortunately, there is no standard with the rule syntax across majore NGFW vendors, leading to challenges for customers to swap vendors. Most flavours of rules have common elements such as&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Action (Pass, drop, or alert)&lt;/li&gt;&#10;&lt;li&gt;Source and Destination&lt;/li&gt;&#10;&lt;li&gt;Protocol and Port&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;A very common open-source firewall rule syntax is the &lt;a href="https://docs.suricata.io/en/latest/index.html"&gt;Suricata&lt;/a&gt;-compatible format. One important adopter is the AWS Network Firewall, which supports both stateful and stateless rule groups. With stateful rule group, there are two options for how the Suricata engine &lt;a href="https://docs.aws.amazon.com/network-firewall/latest/developerguide/suricata-rule-evaluation-order.html"&gt;evaluates rules&lt;/a&gt;. &lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;With &amp;#8220;Action Order&amp;#8221; option, Suricata engine evaluates the rules in the order of: pass, drop, reject and alert. You can use the priority attribute to influence evaluation; &lt;/li&gt;&#10;&lt;li&gt;With strict order, the rules are evaluated in the order of the rule definition;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;It is important to be aware of the rule evaluation order since it impacts the firewall behaviour deeply.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Summary&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In the networking infrastructure design, ingress and egress routing are the most critical one-way door decision. This decision must account for both routing and inspection. While there are many options, we usually start with capturing the key requirements. In this post we reviewed how to approach the requirement, a key technology Gateway Load Balancer and some firewall deployment patterns with FortiGate as an example. The approach is similar for other NGFW vendors, such as &lt;a href="https://www.paloaltonetworks.com/resources/guides/aws-transit-gateway-deployment-guide"&gt;Palo Alto&lt;/a&gt;, &lt;a href="https://checkpoint.awsworkshop.io/"&gt;Check Point&lt;/a&gt; or &lt;a href="https://catalog.us-east-1.prod.workshops.aws/workshops/38565e8c-3a5f-4e93-8412-5fdec23744ca/en-US"&gt;Cisco&lt;/a&gt; Secure Firewall. &lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://www.digihunch.com/2024/10/choosing-cloud-certifications-wisely/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Cloud Certifications for Learning?&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://www.digihunch.com/2025/02/the-most-cost-effective-web-and-email-hosting/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;The Leanest Web and Email Hosting&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>WordPress Security Basics</title><link>https://www.digihunch.com/2023/11/wordpress-security/</link><pubDate>Fri, 17 Nov 2023 12:02:00 -0400</pubDate><guid>https://www.digihunch.com/2023/11/wordpress-security/</guid><description>&lt;img src="https://www.digihunch.com/wp-content/uploads/2025/04/feature-wp-basic.webp" alt="Featured image of post WordPress Security Basics" /&gt;&lt;h2 class="wp-block-heading"&gt;Background&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In 2019, I moved &lt;a href="https://www.digihunch.com/2019/04/build-a-wordpress-site-in-one-hour-with-lightsail/"&gt;this site&lt;/a&gt; to WordPress hosted on an Amazon Lightsail instance. There were few visits at that time so I lived with the single-server architecture. The website traffic has since been in steady growth but I have been too busy to catch up with the WordPress security setup. In July 2023, a malware impacted this site as well as the web traffic. It took me several months to fix a few related issues but the traffic still has not fully recovered. This post is about the lessons.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;The Incident&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I first noticed the issue when I clicked on links to my web page from Google result and got redirected to some spam site. It did not happen 100% of time, but it is annoying enough. In the mean time, from Google search analytics I noticed traffic volume going up with a lot of traffic going to URLs that I did not recognize or create. Somehow these URLs have a lot of clicks and impression counts. These are signs of artificial traffic.&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-full is-resized"&gt;&lt;img loading="lazy" decoding="async" width="730" height="536" src="https://www.digihunch.com/wp-content/uploads/2023/11/wp-traffic.webp" alt="" class="wp-image-12965" style="width:508px;height:auto" srcset="https://www.digihunch.com/wp-content/uploads/2023/11/wp-traffic.webp 730w, https://www.digihunch.com/wp-content/uploads/2023/11/wp-traffic-300x220.webp 300w" sizes="auto, (max-width: 730px) 100vw, 730px" /&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Obviously the site was hacked. The first thing to determine is whether the server access was compromised. From the audit log (/var/log/auth.log and auth.log.gz) I can see a lot of brute force attempts to connect but fortunately none was successful. That also prompt me to change the default SSH port and use ECDSA key pair. Since the OS access is safe, the hack happens at the WordPress level. I suspected the sideloaded plugins from a few days ago. So I immediately removed all sideloaded plugins. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The attack is called malicious redirect. The plugin puts creepy pages in WordPress directory without my awareness and direct user traffic via my website. To clean up the damage, I looked into my WordPress directories at &lt;code&gt;/opt/bitnami/wordpress&lt;/code&gt; and found many suspicious signs:&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&#10;&lt;li&gt;There are directories with weird names, such as &lt;code&gt;rexall-vitalmin&lt;/code&gt;, or &lt;code&gt;q4lee3&lt;/code&gt;, etc&lt;/li&gt;&#10;&lt;li&gt;In each of those directories there was an &lt;code&gt;index.php&lt;/code&gt; file and &lt;code&gt;.htaccess&lt;/code&gt; file; &lt;/li&gt;&#10;&lt;li&gt;Those directories also have other files which look like red herrings;&lt;/li&gt;&#10;&lt;li&gt;All those files have the same date time (from July 6);&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Other directories to look at are &lt;code&gt;/bitnami/wordpress/wp-content/plugins&lt;/code&gt;, where I noticed two directories (named &lt;code&gt;gokyfozaxy&lt;/code&gt; and &lt;code&gt;q199n071&lt;/code&gt;) that are not accounted for; and &lt;code&gt;/bitnami/wordpress/wp-content/themes/&lt;/code&gt;, which contains unknown directories.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Clean up and hardening&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In one of the .htaccess file I noticed segments of mojibake (garbled texts). I first tried to manually remove those files, but the problems stayed. Because the malicious redirect did not happen consistently on every single click, I sometime had false impression that the problem went away. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;However, the challenges with manual cleaning are: 1. there are too many bad files (.htaccess and php files containing mojibake segments); 2. some existing files are impacted with mojibake segments too. I found a free plugin called &lt;a href="https://www.wordfence.com/"&gt;WordFence&lt;/a&gt; to scan the file directory for malicious chagnes, and delete the bad files or bad segments. I also tried a paid scanner (&lt;a href="https://www.malcare.com/"&gt;Malcare&lt;/a&gt;) which found an bad file in /bitnami/wordpress/wp-content/themes/. However, it also blocked my site so I removed Malcare right away. Using the combination of WordFence and Malcare appears to have cleared up the offending files. After restarting apache, the bad URLs are no longer redirecting to spam sites.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This time, I decided to harden the WordPress system given the evidence of brute force attack at different point of entries. At OS level, I mentioned the changes to SSH daemon configuration. At WordPress level, I used WordFence to perform several levels of scans for problems and and improved posture such as admin user&amp;#8217;s MFA. I also noticed a few unrecognized wordpress users and used wordpress CLI to delete those and other unused users.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The wordpress.org website has some &lt;a href="https://wordpress.org/documentation/article/faq-my-site-was-hacked/"&gt;general guidance&lt;/a&gt; on what to do when a site is hacked, and a &lt;a href="https://wordpress.org/documentation/article/hardening-wordpress/"&gt;general guidance&lt;/a&gt; on hardening WordPress.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Back Links&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Another clean up work I had to do is dealing with back links. Back links are URLs from other sites that references this site. There are several situations:&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&#10;&lt;li&gt;If it&amp;#8217;s a made-up URL, then it returns 404. In my case, these are URLs that stopped working once I cleaned up my server from the incident. However, the sources are still using these bad URLs. They are bad back-links;&lt;/li&gt;&#10;&lt;li&gt;If it&amp;#8217;s a legit URL, look at if it&amp;#8217;s hot linking, such as another site directly access an image from my site. These are bad back-links;&lt;/li&gt;&#10;&lt;li&gt;If it&amp;#8217;s legit URLs, and the referrer site has a good &lt;a href="https://en.wikipedia.org/wiki/Domain_authority"&gt;domain authority&lt;/a&gt; score. These are likely to be good back links&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Generally, it is painful to deal with bad back links because I&amp;#8217;m not in control. I used a few free backlink checker tools (e.g. &lt;a href="https://search.google.com/search-console/links"&gt;Links report&lt;/a&gt; on Google Search Console, &lt;a href="https://seomator.com/free-backlink-checker-tool"&gt;SEOMATOR&lt;/a&gt;, SEMRush free) and found a lot of spammy sites that I had to request Google to &lt;a href="https://search.google.com/search-console/disavow-links"&gt;disavow&lt;/a&gt;. Otherwise, they may negatively impact the search performance.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Repercussions&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In the next few months, my pages are no longer a stop for their redirect. However, web request for those invalid URLs keep coming. The bad pages are still in Google&amp;#8217;s cache. There are a lot of page request with 404 return code, and we consider this an HTTP flood. The problem now is that the amount of 404 return code is impacting how my site ranks in search engine. To make it worse, the amount of these requests with invalid URL increase since August. &lt;/p&gt;&#10;&lt;figure class="wp-block-image size-full"&gt;&lt;img loading="lazy" decoding="async" width="1024" height="289" src="https://www.digihunch.com/wp-content/uploads/2023/11/wp-404.webp" alt="" class="wp-image-12966" srcset="https://www.digihunch.com/wp-content/uploads/2023/11/wp-404.webp 1024w, https://www.digihunch.com/wp-content/uploads/2023/11/wp-404-300x85.webp 300w, https://www.digihunch.com/wp-content/uploads/2023/11/wp-404-768x217.webp 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To fix this, there are two measures. First, in Google search console, I have to tell Google to remove those URLs from its cache. I have identified a number of prefix patterns, and submitted a request for each URL pattern. It takes google a day to have them cleared. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;After that, the bad request will no longer come from Google users clicking on bad URL. In my case, the requests did not reduce significantly, suggesting that most of the requests come from bots. Therefore I had to figure out a way to prevent those bad request hitting my server, which is a typical web application firewall requirement. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Looking for such a solution for my WordPress Security I landed on Cloudflare. Cloudflare is pretty user-friendly with an easy-to-understand &lt;a href="https://developers.cloudflare.com/reference-architecture/cdn-reference-architecture/"&gt;reference architecture&lt;/a&gt;. When I started, Cloudflare can import my DNS records, and guided me to change my name servers so I delegate my DNS management it. When I first move to Cloudflare the website gives &lt;a href="https://developers.cloudflare.com/ssl/troubleshooting/too-many-redirects/"&gt;ERR_TOO_MANY_REDIRECTS&lt;/a&gt;. I ended up having to go to SSL/TLS and set encryption mode to Full (strict) to get rid of this error. I also have to re-configure email forwarding as a result of name server change.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;CloudFlare &lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Even for a self-hosted single-server site, it is very beneficial to place an Application Firewall upfront for WordPress security. I find CloudFlare are very useful service that provides everything else you need to host the web site. For example, it contains a domain registry itself. It manages DNS and allows email forwarding. In addition, it helps generate TLS certificate etc. The free tier covers everything for a small website, with the Application Firewall as the core feature. Within the free tier I can have these features:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;domain registrar and name servers (not for free but at a reasonable cost)&lt;/li&gt;&#10;&lt;li&gt;SSL certificate (not for free but at a reasonable cost)&lt;/li&gt;&#10;&lt;li&gt;Request event tracking&lt;/li&gt;&#10;&lt;li&gt;redirect rule: zone apex to www, and /status to uptime status page&lt;/li&gt;&#10;&lt;li&gt;return code 409 for obsolete URLs (using routes and workers)&lt;/li&gt;&#10;&lt;li&gt;email routing and forwarding&lt;/li&gt;&#10;&lt;li&gt;WAF rules (path, parameter, rate, etc)&lt;/li&gt;&#10;&lt;li&gt;DDoS protection and Bot Fight mode&lt;/li&gt;&#10;&lt;li&gt;hot-linking prevention (i.e. other sites references images on your site directly)&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I am still exploring features for CloudFlare. One stunning feature is routes and workers. Essentially you can serve a function in response to HTTP request at a specific route. This is particularly useful in scenarios where it is not straightforward to add web pages on the backend server. For example, I want requests with certain paths to return HTTP code 490 and do not want to mock with the WordPress server, we can make use of CloudFlare worker.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Lessons Learned&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For WordPress security, never use suspicious plugins. Keep an additional layer of defense in WordPress such as Wordfense. It helps block malicious traffic that went through the first layer. It also helps configure MFA for administrators. &lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://www.digihunch.com/2023/10/the-systems-manager-hodgepodge/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;AWS Systems Manager is an Omnipotent Hodgepodge&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://www.digihunch.com/2023/12/workload-identity-on-kubernetes-1-of-2-aks/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Workload Identity on Kubernetes 1 of 2 – AKS&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Connect kubectl to private Kubernetes cluster in EKS and AKS</title><link>https://www.digihunch.com/2023/06/connect-kubectl-to-private-kubernetes-cluster-in-eks-and-aks/</link><pubDate>Sat, 10 Jun 2023 19:31:00 -0400</pubDate><guid>https://www.digihunch.com/2023/06/connect-kubectl-to-private-kubernetes-cluster-in-eks-and-aks/</guid><description>&lt;img src="https://www.digihunch.com/wp-content/uploads/2025/04/feature-kubectl-private-cluster.webp" alt="Featured image of post Connect kubectl to private Kubernetes cluster in EKS and AKS" /&gt;&lt;p class="wp-block-paragraph"&gt;Managed Kubernetes services give user a cluster endpoint and a number of worker nodes, with the choice. For each access, users have the choice of making them publicly available, or keeping them on private networking. In my opinion, any deployment beyond personal hobbies, should use Kubernetes private cluster, with both cluster endpoint and worker nodes on private subnet. There is no reason to expose computing nodes or Kubernetes management traffic publicly. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For worker nodes, it is fairly easy to put VMs on private network, but many companies still have the cluster endpoint exposed publicly. There are usually two reasons. First, their CI/CD agent is hosted somewhere else on the Internet (instead of on private network with private connectivity to Kubernetes cluster) and need to access Kubernetes cluster endpoint. Second, when the cluster needs to connect with third-party identity provider as OIDC provider, a two-way communication is needed. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;There is a classic pattern of using a public bastion host (jump box), with a bastion host on the public subnet, routable to the private endpoint of managed Kubernetes service. Clients then connect to the bastion host via port 22 on a public IP address. The authentication is based on SSH key pair, or worse, password. The port forwarding (aka &lt;a href="https://www.ssh.com/academy/ssh/tunneling-example"&gt;SSH tunnelling&lt;/a&gt;) capability enables all the magics. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Exposing a jump box in the public subnet with RSA key authentication is still not favourable. In this post, I&amp;#8217;ll examine some secure patterns to connect to private endpoint with improved security posture. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-aws-options"&gt;AWS options&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;There are two problems. First, how to establish connectivity to the Bastion host in a private subnet. Second, how to use the Bastion host to proxy traffic to the cluster endpoint also in private subnet. To the first problem, there are two potential solutions: SSM Session Manager, and EC2 Instance Connect (EIC) with EIC endpoint (EICE).&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;SSM Session Manager was introduce in 2018. It runs an agent on the EC2, which initiates a connection to the SSM endpoint on the AWS side. This connection enables not only Session Manager, but also other Systems Managers (SSM) services such as Fleet Manager, Patch Manager and State Manager. The problem that session manager originally addresses is server management.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;AWS launched EC2 Instance Connect (EIC) in 2019, and EIC Endpoint (EICE) in 2023. EIC addresses the problem with managing SSH key pairs at scale. It dynamically generates an SSH key pair for server access, based on IAM permission. However, it still requires an instance to have its SSH port publicly accessible. With EICE, it is no longer a requirement. In the &lt;a href="https://aws.amazon.com/blogs/compute/secure-connectivity-from-public-to-private-introducing-ec2-instance-connect-endpoint-june-13-2023/?utm_content=bufferfded7&amp;amp;utm_medium=social&amp;amp;utm_source=linkedin.com&amp;amp;utm_campaign=buffer"&gt;diagram&lt;/a&gt;, EICE is placed in a private subnet, allowing EICE service to reach private instances at their SSH port. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Here is a comparison of the two:&lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-stripes"&gt;&lt;table class="has-white-background-color has-background"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;EC2 Instance Connect (EIC) with EIC Endpoint&lt;/th&gt;&lt;th&gt;SSM Session Manager&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Location of Bastion host&lt;/td&gt;&lt;td&gt;Private Subnet.&lt;/td&gt;&lt;td&gt;Private Subnet&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Need Ingress Port&lt;/td&gt;&lt;td&gt;Yes. Port 22 must open to the endpoint.&lt;/td&gt;&lt;td&gt;No. SSM agent initiate outbound connection from the instance&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Traffic Path&lt;/td&gt;&lt;td&gt;AWS CLI → AWS EIC ES → EICE→EC2 Inst&lt;/td&gt;&lt;td&gt;AWS CLI → AWS SSM ES → SSM ← EC2 Inst&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Authentication&lt;/td&gt;&lt;td&gt;AWS IAM and ephemeral SSH key when using AWS CLI directly&lt;br&gt;AWS IAM and long-term SSH key when using SSH proxy command&lt;/td&gt;&lt;td&gt;AWS IAM and long-term SSH key when using AWS CLI directly or SSH proxy command&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Work with OpenSSH&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Cost&lt;/td&gt;&lt;td&gt;There is no additional cost for using EIC.&lt;/td&gt;&lt;td&gt;No additional cost, unless private SSM Endpoint.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Let&amp;#8217;s take a look at each option.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;EC2 Instance Connect&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To use EIC, pick an AMI that has it pre-installed and ensure instance profile has correct policy, as the document states &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-connect-prerequisites.html"&gt;here&lt;/a&gt;. AWC CLI will make use of local OpenSSL client. So make sure there connection at port 22 is open. To make it work with EC2 instance on a private subnet, create an EC2 Instance Connect Endpoint on the VPC, and ensure that the security group of EC2 allows port 22 from the Endpoint. Run this command:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ aws ec2-instance-connect ssh --instance-id i-00ea30a6e02db33fe&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The command above simply generates a key pair internally, add the public key to the server side, and connect with SSH from the client side. The command takes you to an SSH session. Checking &lt;code&gt;ps -ef | grep ssh&lt;/code&gt; on the client machine, you can see the full parameter of SSH, including the location of the ephemeral private key. &lt;/p&gt;&#10;&lt;figure class="wp-block-image size-full"&gt;&lt;img loading="lazy" decoding="async" width="1024" height="95" src="https://www.digihunch.com/wp-content/uploads/2023/06/ssh-process.webp" alt="" class="wp-image-12921" srcset="https://www.digihunch.com/wp-content/uploads/2023/06/ssh-process.webp 1024w, https://www.digihunch.com/wp-content/uploads/2023/06/ssh-process-300x28.webp 300w, https://www.digihunch.com/wp-content/uploads/2023/06/ssh-process-768x71.webp 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;However, if you use AWS CLI open-tunnel as proxy command to ssh, then you&amp;#8217;d still have to use the key pair used to create the EC2 instance. As suggested at the bottom of &lt;a href="https://aws.amazon.com/blogs/compute/secure-connectivity-from-public-to-private-introducing-ec2-instance-connect-endpoint-june-13-2023/?utm_content=bufferfded7&amp;amp;utm_medium=social&amp;amp;utm_source=linkedin.com&amp;amp;utm_campaign=buffer"&gt;this&lt;/a&gt; blog post, the command is:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ssh ec2-user@&lt;span style="color:#f92672"&gt;[&lt;/span&gt;INSTANCE&lt;span style="color:#f92672"&gt;]&lt;/span&gt; -i &lt;span style="color:#f92672"&gt;[&lt;/span&gt;SSH-KEY&lt;span style="color:#f92672"&gt;]&lt;/span&gt; -o ProxyCommand&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;aws ec2-instance-connect open-tunnel --instance-id %h&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;This is a bummer, because with native SSH tool you do not get the primary benefit of EIC &amp;#8211; ephemeral key pair. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;SSM Session Manager&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Now let&amp;#8217;s look at SSM session manager. Similarly, it needs an agent installed and &lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/setup-instance-permissions.html"&gt;IAM role&lt;/a&gt; configured. You can connect to from web console but more importantly, from AWS CLI:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ aws ssm start-session --target i-0531b19bec8ad022d&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;This command takes you to an SSH session with user &lt;code&gt;ssm-user&lt;/code&gt;, without starting an OpenSSH client process locally. User do not have to manage key pair. There is also a &lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-getting-started-enable-ssh-connections.html"&gt;document&lt;/a&gt; about using this command as proxy command, which uses an SSM document. I have one of the SSH config entry as:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;host i-* mi-*&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ProxyCommand sh -c &lt;span style="color:#e6db74"&gt;&amp;#34;aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters &amp;#39;portNumber=%p&amp;#39;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; User ec2-user&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; IdentityFile ~/.ssh/id_rsa&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;This allows me to directly SSH to client using OpenSSL client (e.g. &lt;code&gt;ssh i-0531b19bec8ad022d&lt;/code&gt;) by Instance ID. With this, I also need to specify my own OS user and matching private key.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I know I will use the OpenSSH client a lot from pipelines because it is very powerful. In both options, I have to live with managing key pairs myself. With SSM session manager&amp;#8217;s proxy command, the instance does not need port 22 to open, which is a great advantage, in terms of security and operation. SSM Session Manager is a winner.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;SOCKS5 proxy for kubectl&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Either SSM Session Manager or EIC with EICE enables an SSH tunnel with key encryption between client (a local computer or a pipeline agent). On top of the SSH tunnel, we can build a &lt;a href="https://en.wikipedia.org/wiki/SOCKS#SOCKS5"&gt;SOCKS5&lt;/a&gt; proxy. Kubernetes document has a good &lt;a href="https://kubernetes.io/docs/tasks/extend-kubernetes/socks5-proxy-access-api/"&gt;page&lt;/a&gt; on how to do this. I managed to get this to work with a few gotchas.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="827px" viewBox="-0.5 -0.5 827 512" style="max-width:100%;max-height:512px;"&gt;&lt;defs&gt;&lt;linearGradient x1="0%" y1="100%" x2="0%" y2="0%" id="mx-gradient-f78e04-1-d05c17-1-s-0"&gt;&lt;stop offset="0%" style="stop-color: rgb(208, 92, 23); stop-opacity: 1;"/&gt;&lt;stop offset="100%" style="stop-color: rgb(247, 142, 4); stop-opacity: 1;"/&gt;&lt;/linearGradient&gt;&lt;style type="text/css"&gt;@import url(https://fonts.googleapis.com/css?family=Architects+Daughter);&amp;#xa;&lt;/style&gt;&lt;/defs&gt;&lt;g&gt;&lt;rect x="0" y="0" width="825" height="510" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/&gt;&lt;rect x="25" y="78.88" width="270" height="251.12" rx="25.11" ry="25.11" fill="#dae8fc" stroke="#6c8ebf" stroke-width="2" pointer-events="all"/&gt;&lt;rect x="435" y="60" width="370" height="240" rx="24" ry="24" fill="#dae8fc" stroke="#6c8ebf" stroke-width="2" pointer-events="all"/&gt;&lt;rect x="455" y="80" width="260" height="200" rx="20" ry="20" fill="#f5f5f5" stroke="#666666" stroke-width="2" pointer-events="all"/&gt;&lt;g fill="#333333" font-family="Helvetica" text-anchor="middle" font-size="12px"&gt;&lt;text x="584.5" y="97.5"&gt;Private Subnet&lt;/text&gt;&lt;/g&gt;&lt;rect x="475" y="123.75" width="120" height="130" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 131px; margin-left: 476px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Bastion Host&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="535" y="143" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Bastion Host&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="75" y="110" width="190" height="193.75" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 188px; height: 1px; padding-top: 117px; margin-left: 76px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Pipeline Agent&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="170" y="129" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Pipeline Agent&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 351.25 68 C 351.25 66.34 353.49 65 356.25 65 C 357.58 65 358.85 65.32 359.79 65.88 C 360.72 66.44 361.25 67.2 361.25 68 L 361.25 309.5 C 361.25 311.16 359.01 312.5 356.25 312.5 C 353.49 312.5 351.25 311.16 351.25 309.5 Z" fill="#bac8d3" stroke="#23445d" stroke-miterlimit="10" transform="rotate(-90,356.25,188.75)" pointer-events="all"/&gt;&lt;path d="M 361.25 68 C 361.25 69.66 359.01 71 356.25 71 C 353.49 71 351.25 69.66 351.25 68" fill="none" stroke="#23445d" stroke-miterlimit="10" transform="rotate(-90,356.25,188.75)" pointer-events="all"/&gt;&lt;rect x="312.5" y="163.75" width="90" height="20" fill="none" stroke="none" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 174px; margin-left: 314px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;SSH Tunnel&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="358" y="177" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;SSH Tunnel&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 513.09 207.45 L 511.26 176.65 L 513.7 176.11 L 515.76 178.18 C 516.3 178.12 516.83 178.15 517.37 178.25 L 518.13 176.72 L 520.42 176.27 L 522.1 177.3 L 522.6 180.77 C 523.56 181.65 524.4 182.82 525.08 184.21 L 527.37 184.71 L 528.05 186.81 L 526.83 189.64 C 527.07 191.14 527.15 192.69 527.06 194.23 L 528.66 196.75 L 528.21 199.5 L 525.92 200.03 C 525.37 201.1 524.73 202.03 524.01 202.79 L 524.01 206.34 L 522.56 207.22 L 519.96 207.6 L 517.44 204.08 L 514.92 207.52 Z M 517.9 192.62 L 517.21 189.79 C 516.97 189.6 516.7 189.72 516.5 190.12 C 516.31 190.52 516.2 191.14 516.22 191.78 C 516.29 192.51 516.57 193.09 516.93 193.27 C 517.29 193.45 517.67 193.2 517.9 192.62 Z" fill="#697079" stroke="#697079" stroke-width="0.46" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;rect x="505" y="159.91" width="0" height="0" fill="none" stroke="none" pointer-events="all"/&gt;&lt;path d="M 529.43 191.24 L 527.6 160.44 L 530.04 159.91 L 532.1 161.97 C 532.63 161.92 533.17 161.94 533.7 162.05 L 534.47 160.52 L 536.76 160.06 L 538.44 161.09 L 538.93 164.57 C 539.89 165.45 540.74 166.62 541.41 168.01 L 543.7 168.51 L 544.39 170.61 L 543.17 173.44 C 543.41 174.93 543.49 176.48 543.4 178.02 L 545 180.55 L 544.54 183.3 L 542.25 183.83 C 541.71 184.9 541.06 185.83 540.34 186.58 L 540.34 190.14 L 538.89 191.02 L 536.3 191.4 L 533.78 187.88 L 531.26 191.32 Z M 534.24 176.42 L 533.55 173.59 C 533.31 173.4 533.04 173.52 532.84 173.92 C 532.64 174.32 532.53 174.94 532.56 175.58 C 532.63 176.31 532.9 176.89 533.26 177.07 C 533.62 177.25 534 177 534.24 176.42 Z" fill="#697079" stroke="#697079" stroke-width="0.46" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;path d="M 529.43 191.24 L 527.9 190.48 L 527.52 186.93 C 526.49 186.07 525.58 184.89 524.85 183.45 L 522.63 183.07 L 521.79 180.77 L 523.24 177.95 C 522.97 176.43 522.87 174.86 522.94 173.28 L 521.34 170.69 L 521.79 168.47 L 524.08 168.13 C 524.63 166.9 525.3 165.83 526.07 164.95 L 526.07 161.51 L 527.6 160.44 L 529.27 162.58 C 530.33 162.26 531.42 162.26 532.48 162.58 L 534.47 160.52 L 535.99 161.44 L 536.22 164.8 C 537.17 165.7 538 166.9 538.66 168.32 L 541.03 168.7 L 541.87 171.07 L 540.57 173.82 C 540.82 175.34 540.9 176.92 540.8 178.48 L 542.56 181.31 L 542.02 183.91 L 539.81 183.91 C 539.24 185.16 538.55 186.25 537.75 187.12 L 537.67 190.71 L 536.22 191.4 L 534.16 189.03 C 533.18 189.36 532.17 189.41 531.18 189.18 Z M 532.02 178.94 C 532.55 178.94 533.05 178.6 533.41 177.99 C 533.77 177.38 533.96 176.57 533.93 175.73 C 533.75 174.32 532.73 173.24 531.49 173.13 C 531 173.07 530.52 173.37 530.21 173.93 C 529.89 174.49 529.77 175.25 529.89 175.96 C 529.91 177.54 530.84 178.84 532.02 178.94" fill="#c0c6d2" stroke="#697079" stroke-width="0.46" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;path d="M 513.09 207.45 L 511.56 206.68 L 511.18 203.13 C 510.15 202.28 509.24 201.09 508.51 199.65 L 506.3 199.27 L 505.46 196.98 L 506.91 194.15 C 506.64 192.64 506.53 191.06 506.6 189.49 L 505 186.89 L 505.46 184.67 L 507.75 184.33 C 508.29 183.1 508.96 182.03 509.73 181.16 L 509.73 177.72 L 511.26 176.65 L 512.94 178.79 C 514 178.46 515.09 178.46 516.15 178.79 L 518.13 176.72 L 519.66 177.64 L 519.89 181 C 520.84 181.91 521.67 183.1 522.33 184.52 L 524.69 184.9 L 525.53 187.27 L 524.24 190.02 C 524.48 191.54 524.56 193.12 524.47 194.68 L 526.22 197.51 L 525.69 200.11 L 523.47 200.11 C 522.91 201.36 522.21 202.45 521.41 203.32 L 521.34 206.91 L 519.89 207.6 L 517.82 205.23 C 516.85 205.56 515.84 205.62 514.85 205.38 Z M 515.69 195.14 C 516.21 195.14 516.71 194.8 517.07 194.19 C 517.43 193.59 517.62 192.77 517.6 191.93 C 517.41 190.52 516.4 189.44 515.15 189.33 C 514.66 189.28 514.19 189.57 513.87 190.13 C 513.55 190.69 513.43 191.45 513.55 192.16 C 513.58 193.74 514.5 195.04 515.69 195.14" fill="#c0c6d2" stroke="#697079" stroke-width="0.46" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;path d="M 530.06 204.96 L 529.21 190.65 L 530.34 190.4 L 531.3 191.36 C 531.55 191.34 531.8 191.35 532.04 191.4 L 532.4 190.69 L 533.46 190.48 L 534.24 190.95 L 534.47 192.57 C 534.92 192.98 535.31 193.52 535.62 194.17 L 536.69 194.4 L 537.01 195.38 L 536.44 196.69 C 536.55 197.38 536.59 198.1 536.55 198.82 L 537.29 199.99 L 537.08 201.27 L 536.02 201.52 C 535.76 202.01 535.46 202.44 535.13 202.79 L 535.13 204.44 L 534.45 204.85 L 533.25 205.03 L 532.08 203.4 L 530.91 204.99 Z Z M 532.29 198.07 L 531.97 196.76 C 531.6 196.9 531.4 197.3 531.51 197.68 C 531.7 198.03 532 198.18 532.29 198.07 Z" fill="#697079" stroke="#697079" stroke-width="0.46" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;path d="M 530.06 204.96 L 529.35 204.6 L 529.17 202.95 C 528.69 202.56 528.27 202.01 527.93 201.34 L 526.9 201.16 L 526.51 200.09 L 527.18 198.78 C 527.06 198.08 527.01 197.35 527.04 196.62 L 526.3 195.41 L 526.51 194.38 L 527.57 194.22 C 527.83 193.65 528.14 193.15 528.5 192.75 L 528.5 191.15 L 529.21 190.65 L 529.98 191.65 C 530.48 191.49 530.98 191.49 531.47 191.65 L 532.4 190.69 L 533.11 191.11 L 533.21 192.68 C 533.66 193.1 534.04 193.65 534.35 194.31 L 535.45 194.49 L 535.84 195.59 L 535.23 196.87 C 535.35 197.57 535.38 198.31 535.34 199.03 L 536.16 200.34 L 535.91 201.55 L 534.88 201.55 C 534.61 202.13 534.29 202.64 533.92 203.04 L 533.89 204.71 L 533.21 205.03 L 532.26 203.93 C 531.8 204.09 531.33 204.11 530.87 204 Z M 531.26 199.24 C 531.54 199.3 531.82 199.16 532 198.85 C 532.18 198.55 532.24 198.13 532.15 197.75 C 532.03 197.04 531.56 196.54 531.02 196.54 C 530.8 196.55 530.59 196.7 530.44 196.95 C 530.3 197.2 530.24 197.53 530.27 197.86 C 530.32 198.57 530.73 199.15 531.26 199.24 Z" fill="#c0c6d2" stroke="#697079" stroke-width="0.46" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 215px; margin-left: 525px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"&gt;SSHD&lt;br /&gt;Process&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="525" y="227" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;SSHD&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 195 204.89 L 195 169.8 L 213.58 165.22 L 229.15 169.93 L 229.15 205.42 L 210.83 209.74 Z" fill="#abb4c5" stroke="none" pointer-events="all"/&gt;&lt;path d="M 195 169.8 L 213.58 165.22 L 229.15 169.93 L 210.83 174.39 Z" fill="#b8bfd1" stroke="none" pointer-events="all"/&gt;&lt;path d="M 210.83 174.39 L 229.15 169.93 L 229.15 205.42 L 210.83 209.74 Z" fill="#5b6369" stroke="none" pointer-events="all"/&gt;&lt;path d="M 211.02 193.68 C 207.61 192.37 204.34 190.7 201.28 188.71 C 199.81 187.69 198.56 186.38 197.62 184.86 C 196.97 183.67 196.63 182.34 196.65 180.98 C 196.59 179.53 196.62 178.07 196.73 176.61 C 196.8 175.31 196.94 174.02 197.15 172.74 C 197.34 172.03 197.63 171.35 198.01 170.72 C 198.8 170.18 199.71 169.74 200.68 169.41 C 202.34 168.85 204.02 168.36 205.73 167.97 C 207.51 167.49 209.32 167.14 211.15 166.92 C 212.39 166.77 213.64 166.72 214.89 166.79 C 216.92 166.94 218.92 167.38 220.83 168.1 L 227.03 170.38 C 227.58 171.28 227.93 172.29 228.08 173.34 C 228.25 174.75 228.35 176.16 228.37 177.58 C 228.47 180.71 228.38 183.84 228.1 186.95 C 228.07 188.33 227.6 189.66 226.77 190.75 C 225.56 192.09 223.92 192.97 222.14 193.24 C 220.71 193.46 219.27 193.57 217.82 193.55 Z" fill-opacity="0.4" fill="#ffffff" stroke="none" pointer-events="all"/&gt;&lt;rect x="195" y="165.22" width="0" height="0" fill="none" stroke="none" pointer-events="all"/&gt;&lt;path d="M 196.83 175.17 L 196.83 174.25 L 208.74 177.92 L 208.74 178.84 Z M 198.79 202.93 L 198.79 202.01 L 206.12 204.11 L 206.12 205.02 Z" fill="#52595e" stroke="none" pointer-events="all"/&gt;&lt;path d="M 195 204.89 L 195 169.8 L 213.58 165.22 L 229.15 169.93 L 229.15 205.42 L 210.83 209.74 Z" fill="none" stroke="#000000" stroke-width="0.31" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;rect x="195" y="165.22" width="0" height="0" fill="none" stroke="none" pointer-events="all"/&gt;&lt;ellipse cx="224.81" cy="202.43" rx="9.839712136081127" ry="9.846174392076122" fill="#008cce" stroke="none" pointer-events="all"/&gt;&lt;path d="M 218.09 195.38 C 218.19 195.65 218.32 195.91 218.49 196.15 C 218.76 196.18 219.02 196.26 219.26 196.4 C 219.2 196.67 219.31 196.96 219.55 197.11 C 219.74 197.22 219.86 197.4 219.89 197.61 C 219.9 197.72 219.95 197.82 220.03 197.88 C 220.11 197.95 220.21 197.99 220.32 197.98 C 220.44 197.96 220.56 197.95 220.69 197.95 C 220.95 197.92 221.22 197.97 221.45 198.11 L 222.28 198.71 C 222.41 198.8 222.51 198.94 222.55 199.1 C 222.59 199.25 222.59 199.41 222.55 199.56 C 222.48 199.58 222.41 199.57 222.35 199.54 C 222.3 199.41 222.2 199.3 222.08 199.24 C 221.92 199.18 221.74 199.18 221.58 199.24 C 221.37 199.36 221.12 199.4 220.88 199.36 C 220.68 199.37 220.5 199.47 220.38 199.63 C 220.29 199.76 220.14 199.84 219.98 199.86 C 219.82 199.87 219.67 199.81 219.55 199.69 C 219.46 199.56 219.3 199.49 219.13 199.51 C 218.97 199.52 218.83 199.62 218.76 199.77 C 218.67 199.96 218.62 200.17 218.6 200.37 C 218.6 200.64 218.55 200.91 218.45 201.16 C 218.4 201.29 218.3 201.39 218.18 201.46 C 217.99 201.52 217.87 201.7 217.89 201.9 C 218.05 202.09 218.17 202.3 218.25 202.53 C 218.32 202.67 218.27 202.84 218.12 202.93 C 217.97 203.05 217.9 203.24 217.93 203.43 C 217.7 203.44 217.47 203.4 217.25 203.33 C 217.17 203.22 217.05 203.14 216.92 203.1 C 216.8 203.07 216.67 203.12 216.59 203.22 C 216.44 203.43 216.33 203.67 216.27 203.93 C 216.22 204.1 216.19 204.28 216.19 204.46 C 216.36 204.78 216.45 205.13 216.43 205.5 L 216.56 206.56 C 216.57 206.7 216.54 206.84 216.46 206.96 C 216.38 207.07 216.27 207.14 216.14 207.18 C 214.05 203.26 214.84 198.43 218.08 195.38 Z" fill="#00527f" stroke="none" pointer-events="all"/&gt;&lt;path d="M 230.12 194.25 C 230.08 194.4 229.99 194.53 229.86 194.61 C 229.74 194.66 229.61 194.69 229.49 194.69 L 228.76 194.78 C 228.44 194.75 228.12 194.78 227.82 194.89 C 227.85 194.99 227.81 195.11 227.72 195.17 C 227.64 195.23 227.52 195.24 227.43 195.18 C 227.24 195.19 227.06 195.27 226.93 195.41 C 226.84 195.52 226.71 195.59 226.56 195.61 C 226.36 195.65 226.19 195.78 226.1 195.97 C 226.01 196.13 225.85 196.16 225.74 196.05 C 225.67 195.9 225.62 195.74 225.61 195.58 C 225.48 195.27 225.24 195.01 224.94 194.85 C 224.64 194.72 224.35 194.54 224.1 194.32 C 223.94 194.2 223.84 194.01 223.84 193.81 C 223.83 193.69 223.84 193.57 223.88 193.45 C 223.78 193.25 223.57 193.1 223.34 193.08 C 223.17 193.04 223.03 192.91 222.97 192.75 C 225.5 192.28 228.12 192.82 230.26 194.25 Z" fill="#64aadc" stroke="none" pointer-events="all"/&gt;&lt;path d="M 234.25 205.1 C 234.22 204.79 234.1 204.5 233.91 204.26 C 233.71 204.24 233.51 204.34 233.41 204.52 C 233.25 204.76 233 204.92 232.72 204.96 C 232.52 204.74 232.56 204.44 232.81 204.26 C 232.97 204.02 233.01 203.71 232.92 203.43 C 232.9 203.31 232.85 203.2 232.79 203.1 C 232.6 202.91 232.46 202.69 232.39 202.43 C 232.21 202.55 232 202.53 231.84 202.39 C 231.68 202.25 231.59 202.01 231.61 201.77 C 231.62 201.48 231.52 201.21 231.32 201 C 231.34 200.54 231.2 200.1 230.92 199.73 C 230.65 199.46 230.28 199.29 229.89 199.27 C 229.56 199.27 229.29 199.08 229.28 198.83 C 229.27 198.59 229.53 198.38 229.86 198.38 C 230.36 198.43 230.86 198.42 231.35 198.34 C 231.83 198.28 232.29 198.13 232.72 197.91 L 233.18 197.27 C 234.61 199.62 235 202.45 234.25 205.1 Z" fill="#0a79b9" stroke="none" pointer-events="all"/&gt;&lt;path d="M 233.25 207.56 C 233.02 207.84 232.72 208.06 232.39 208.18 C 232.12 208.26 231.93 208.5 231.92 208.78 C 231.89 208.88 231.86 208.83 231.84 208.64 C 231.81 208.45 231.79 208.14 231.79 207.78 C 231.83 207.45 231.95 207.13 232.15 206.85 C 232.36 206.65 232.55 206.43 232.72 206.19 C 232.78 206.09 232.78 205.97 232.72 205.87 C 232.66 205.77 232.55 205.72 232.44 205.73 C 232.32 205.74 232.23 205.81 232.19 205.92 C 231.94 206.21 231.72 206.52 231.52 206.85 C 231.2 207.34 230.73 207.54 230.28 207.39 C 230.02 207.25 229.72 207.19 229.42 207.18 C 229.24 207.25 229.13 207.37 229.12 207.49 C 229.11 207.62 229.19 207.74 229.36 207.82 C 229.6 207.9 229.82 208.07 229.95 208.29 C 230.16 208.65 229.74 209.01 228.93 209.18 C 228.37 209.2 227.82 209.3 227.29 209.49 C 226.99 209.77 226.78 210.14 226.69 210.55 C 226.6 210.73 226.1 210.87 225.5 210.88 C 225.07 210.82 224.63 210.84 224.21 210.95 C 223.86 211.08 223.46 211.01 223.17 210.78 C 223.1 210.64 222.96 210.55 222.81 210.54 C 222.65 210.53 222.5 210.61 222.42 210.74 C 222.34 210.87 222.34 211.04 222.41 211.18 C 222.55 211.42 222.83 211.56 223.1 211.51 C 223.3 211.4 223.56 211.35 223.81 211.38 C 223.96 211.41 224.09 211.5 224.14 211.61 C 224.23 211.69 224.4 211.74 224.62 211.77 C 224.83 211.79 225.07 211.79 225.27 211.75 C 225.6 211.65 226.02 211.59 226.47 211.58 C 226.78 211.55 227.08 211.51 227.33 211.44 C 227.58 211.26 227.89 211.16 228.2 211.18 C 228.37 211.14 228.51 211.09 228.6 211.04 C 228.72 210.95 228.87 210.9 229.02 210.91 C 229.1 210.97 229.13 211.07 229.09 211.15 C 228.99 211.29 228.86 211.42 228.73 211.52 C 230.61 210.71 232.19 209.32 233.25 207.56 Z" fill="#266792" stroke="none" pointer-events="all"/&gt;&lt;ellipse cx="224.21" cy="198.24" rx="7.114164213280995" ry="4.923087196038061" fill-opacity="0.3" fill="#ffffff" stroke="none" pointer-events="all"/&gt;&lt;ellipse cx="220.96" cy="197.31" rx="2.0608439646712466" ry="1.5018034611318236" fill-opacity="0.4" fill="#ffffff" stroke="none" pointer-events="all"/&gt;&lt;rect x="195" y="165.22" width="0" height="0" fill="none" stroke="none" pointer-events="all"/&gt;&lt;ellipse cx="224.81" cy="202.43" rx="9.839712136081127" ry="9.846174392076122" fill="none" stroke="#000000" stroke-width="0.25" pointer-events="all"/&gt;&lt;rect x="195" y="165.22" width="0" height="0" fill="none" stroke="none" pointer-events="all"/&gt;&lt;path d="M 219.46 209.2 L 219.46 200.52 L 221.53 199.95 L 221.53 193.72 L 222.48 193.41 L 227.82 195.04 L 227.82 200.96 L 229.64 201.46 L 229.64 210.39 L 226 211.27 Z M 223.29 199.57 L 226.12 200.45 L 226.12 195.86 L 223.29 195.04 Z" fill="#a3acbd" stroke="none" pointer-events="all"/&gt;&lt;path d="M 229.64 201.46 L 226.06 202.34 L 219.46 200.52 L 222.98 199.51 Z" fill="#b2b9ca" stroke="none" pointer-events="all"/&gt;&lt;path d="M 229.64 210.39 L 226.06 211.27 L 226.06 202.34 L 229.64 201.46 Z" fill="#5b6369" stroke="none" pointer-events="all"/&gt;&lt;path d="M 226.06 210.71 L 219.46 208.7 L 219.46 207.88 L 226.06 209.83 L 229.64 208.95 L 229.64 209.83 Z" fill-opacity="0.7" fill="#0378b2" stroke="none" pointer-events="all"/&gt;&lt;rect x="195" y="165.22" width="0" height="0" fill="none" stroke="none" pointer-events="all"/&gt;&lt;path d="M 221.97 205.74 C 221.72 205.54 221.6 205.26 221.66 204.98 C 221.8 204.73 222.02 204.64 222.22 204.76 C 222.47 204.83 222.68 205.07 222.77 205.39 C 222.79 205.57 222.72 205.75 222.56 205.86 L 222.67 207.44 C 222.67 207.54 222.63 207.63 222.56 207.7 C 222.48 207.78 222.39 207.82 222.29 207.82 C 222.12 207.81 221.96 207.75 221.85 207.63 C 221.74 207.51 221.69 207.34 221.72 207.18 Z" fill="#3b393b" stroke="none" pointer-events="all"/&gt;&lt;path d="M 227.82 195.04 L 226.88 195.36 L 221.53 193.79 L 222.48 193.41 Z" fill="#d9dde6" stroke="none" pointer-events="all"/&gt;&lt;path d="M 226.06 203.52 L 219.46 201.65 L 219.46 200.82 L 226.06 202.64 L 229.64 201.76 L 229.64 202.64 Z" fill-opacity="0.7" fill="#0378b2" stroke="none" pointer-events="all"/&gt;&lt;path d="M 220.09 200.71 C 220.45 200.51 220.83 200.37 221.22 200.27 L 223.61 199.69 L 228.39 201.1 C 228.59 201.24 228.76 201.42 228.89 201.62 C 228.97 202.05 228.98 202.48 228.91 202.91 C 228.87 203.97 228.56 205 228.01 205.9 C 227.5 206.44 226.85 206.82 226.12 207 C 225.36 207.3 224.55 207.45 223.73 207.44 C 222.97 207.41 222.23 207.06 221.67 206.43 C 221.09 205.88 220.61 205.21 220.28 204.48 C 220.01 203.82 219.88 203.12 219.9 202.41 C 219.89 201.83 219.95 201.26 220.09 200.71 Z" fill-opacity="0.3" fill="#ffffff" stroke="none" pointer-events="all"/&gt;&lt;rect x="195" y="165.22" width="0" height="0" fill="none" stroke="none" pointer-events="all"/&gt;&lt;path d="M 221.53 193.79 L 226.88 195.36 L 226.88 201.9 L 226.12 201.71 L 226.12 195.86 L 222.41 194.73 L 222.41 200.52 L 221.53 200.27 Z" fill="#9ba5b6" stroke="none" pointer-events="all"/&gt;&lt;path d="M 227.82 195.04 L 227.82 201.65 L 226.88 201.9 L 226.88 195.36 Z" fill="#60686f" stroke="none" pointer-events="all"/&gt;&lt;path d="M 223.29 195.03 L 223.29 200.27 L 222.41 200.52 L 222.41 194.73 Z" fill="#5c6369" stroke="none" pointer-events="all"/&gt;&lt;path d="M 219.46 209.2 L 219.46 200.52 L 221.53 199.95 L 221.53 193.72 L 222.48 193.41 L 227.82 195.04 L 227.82 200.96 L 229.64 201.46 L 229.64 210.39 L 226 211.27 Z M 223.29 199.57 L 226.12 200.45 L 226.12 195.86 L 223.29 195.04 Z" fill="none" stroke="#000000" stroke-width="0.15" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 219px; margin-left: 215px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"&gt;SOCKS5 Proxy&lt;br /&gt;by SSH&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="215" y="231" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;SOCKS5&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="115" y="153.75" width="42.55" height="30" fill="none" stroke="none" pointer-events="all"/&gt;&lt;path d="M 115.06 172.69 L 123.57 172.69 L 123.57 170.76 L 115.06 170.76 Z M 115.06 166.74 L 125.27 166.74 L 125.27 164.81 L 115.06 164.81 Z M 115.06 160.78 L 126.97 160.78 L 126.97 158.85 L 115.06 158.85 Z M 146.63 170.76 L 133.31 170.76 L 134.53 165.89 L 147.85 165.89 Z M 133.02 163.96 L 130.84 172.69 L 148.14 172.69 L 150.32 163.96 Z M 150.07 181.52 C 150.03 181.69 149.88 181.82 149.7 181.82 L 126.09 181.82 C 125.93 181.82 125.83 181.73 125.79 181.68 C 125.74 181.62 125.68 181.51 125.71 181.35 L 130.08 160.74 L 154.48 160.74 Z M 131.47 155.68 L 155.08 155.68 C 155.24 155.68 155.33 155.77 155.38 155.82 C 155.42 155.88 155.49 155.99 155.45 156.15 L 154.89 158.81 L 130.49 158.81 L 131.09 155.99 C 131.13 155.81 131.29 155.68 131.47 155.68 Z M 156.87 154.61 C 156.43 154.06 155.78 153.75 155.08 153.75 L 131.47 153.75 C 130.38 153.75 129.43 154.52 129.2 155.59 L 123.82 180.96 C 123.68 181.64 123.85 182.35 124.29 182.89 C 124.73 183.44 125.38 183.75 126.09 183.75 L 149.7 183.75 C 150.78 183.75 151.73 182.98 151.96 181.92 L 157.34 156.55 C 157.49 155.86 157.32 155.15 156.87 154.61 Z" fill="#b0084d" stroke="none" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 191px; margin-left: 136px;"&gt;&lt;div data-drawio-colors="color: #232F3E; " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(35, 47, 62); line-height: 1.2; pointer-events: all; white-space: nowrap;"&gt;kubectl&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="136" y="203" fill="#232F3E" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;kubectl&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="115" y="240" width="42.55" height="30" fill="none" stroke="none" pointer-events="all"/&gt;&lt;path d="M 115.06 258.94 L 123.57 258.94 L 123.57 257.01 L 115.06 257.01 Z M 115.06 252.99 L 125.27 252.99 L 125.27 251.06 L 115.06 251.06 Z M 115.06 247.03 L 126.97 247.03 L 126.97 245.1 L 115.06 245.1 Z M 146.63 257.01 L 133.31 257.01 L 134.53 252.14 L 147.85 252.14 Z M 133.02 250.21 L 130.84 258.94 L 148.14 258.94 L 150.32 250.21 Z M 150.07 267.77 C 150.03 267.94 149.88 268.07 149.7 268.07 L 126.09 268.07 C 125.93 268.07 125.83 267.98 125.79 267.93 C 125.74 267.87 125.68 267.76 125.71 267.6 L 130.08 246.99 L 154.48 246.99 Z M 131.47 241.93 L 155.08 241.93 C 155.24 241.93 155.33 242.02 155.38 242.07 C 155.42 242.13 155.49 242.24 155.45 242.4 L 154.89 245.06 L 130.49 245.06 L 131.09 242.24 C 131.13 242.06 131.29 241.93 131.47 241.93 Z M 156.87 240.86 C 156.43 240.31 155.78 240 155.08 240 L 131.47 240 C 130.38 240 129.43 240.77 129.2 241.84 L 123.82 267.21 C 123.68 267.89 123.85 268.6 124.29 269.14 C 124.73 269.69 125.38 270 126.09 270 L 149.7 270 C 150.78 270 151.73 269.23 151.96 268.17 L 157.34 242.8 C 157.49 242.11 157.32 241.4 156.87 240.86 Z" fill="#b0084d" stroke="none" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 277px; margin-left: 136px;"&gt;&lt;div data-drawio-colors="color: #232F3E; " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(35, 47, 62); line-height: 1.2; pointer-events: all; white-space: nowrap;"&gt;aws cli&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="136" y="289" fill="#232F3E" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;aws cli&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 545 183.75 L 688.63 183.75" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/&gt;&lt;path d="M 693.88 183.75 L 686.88 187.25 L 688.63 183.75 L 686.88 180.25 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;path d="M 480.7 72.67 L 489.28 72.67 L 489.28 67.89 C 489.28 66.64 488.46 64.69 486.66 64.69 L 483.25 64.69 C 482 64.69 480.7 65.98 480.7 67.89 Z M 475 90 L 475 72.67 L 477.83 72.67 L 477.83 65.36 C 477.83 62.48 479.81 60 482.05 60 L 487.91 60 C 490.18 60 492.13 62.43 492.13 65.49 L 492.13 72.67 L 495 72.67 L 495 90 Z" fill="#d9a741" stroke="none" pointer-events="all"/&gt;&lt;path d="M 489.28 67.89 C 489.28 66.64 488.46 64.69 486.66 64.69 L 483.25 64.69 C 482 64.69 480.7 65.99 480.7 67.89 L 480.7 66.87 C 480.7 65.2 481.77 63.63 483.26 63.63 L 486.75 63.63 C 488.02 63.63 489.28 65.03 489.28 66.82 Z M 475 90 L 475 88.98 L 495 88.98 L 495 90 Z" fill-opacity="0.3" fill="#000000" stroke="none" pointer-events="all"/&gt;&lt;path d="M 47.26 100.88 C 45.95 100.88 45 99.85 45 98.69 L 45 61.03 C 45 59.99 45.83 58.88 47.12 58.88 L 72.84 58.88 C 73.96 58.88 75 59.79 75 61.08 L 75 98.94 C 75 99.94 74.01 100.88 72.82 100.88 Z" fill="#7d7c7c" stroke="none" pointer-events="all"/&gt;&lt;path d="M 75 96.78 L 75 98.94 C 75 99.94 74.01 100.88 72.82 100.88 L 47.26 100.88 C 45.95 100.88 45 99.84 45 98.69 L 45 97.04 C 45 98.19 46.1 99.01 47.09 99.01 L 72.78 99.01 C 73.96 99.01 75 98.07 75 96.78 Z" fill-opacity="0.3" fill="#000000" stroke="none" pointer-events="all"/&gt;&lt;rect x="45" y="58.88" width="0" height="0" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/&gt;&lt;path d="M 54.63 66.43 L 48.56 66.43 L 48.56 63.97 L 54.63 63.97 Z M 62.98 66.43 L 56.91 66.43 L 56.91 63.97 L 62.98 63.97 Z M 71.34 66.43 L 65.26 66.43 L 65.26 63.97 L 71.34 63.97 Z M 54.63 70.73 L 48.56 70.73 L 48.56 68.27 L 54.63 68.27 Z M 62.98 70.73 L 56.91 70.73 L 56.91 68.27 L 62.98 68.27 Z M 71.34 70.73 L 65.26 70.73 L 65.26 68.27 L 71.34 68.27 Z M 54.63 75.04 L 48.56 75.04 L 48.56 72.58 L 54.63 72.58 Z M 62.98 75.04 L 56.91 75.04 L 56.91 72.58 L 62.98 72.58 Z M 71.34 75.04 L 65.26 75.04 L 65.26 72.58 L 71.34 72.58 Z M 54.63 79.34 L 48.56 79.34 L 48.56 76.88 L 54.63 76.88 Z M 62.98 79.34 L 56.91 79.34 L 56.91 76.88 L 62.98 76.88 Z M 71.34 79.34 L 65.26 79.34 L 65.26 76.88 L 71.34 76.88 Z M 54.63 83.65 L 48.56 83.65 L 48.56 81.19 L 54.63 81.19 Z M 62.98 83.65 L 56.91 83.65 L 56.91 81.19 L 62.98 81.19 Z M 71.34 83.65 L 65.26 83.65 L 65.26 81.19 L 71.34 81.19 Z M 54.63 87.95 L 48.56 87.95 L 48.56 85.49 L 54.63 85.49 Z M 62.98 87.95 L 56.91 87.95 L 56.91 85.49 L 62.98 85.49 Z M 71.34 87.95 L 65.26 87.95 L 65.26 85.49 L 71.34 85.49 Z" fill="#ffffff" stroke="none" pointer-events="all"/&gt;&lt;path d="M 745.96 76 C 740.09 76 735.55 71.43 735.55 67.19 L 735.55 65.43 C 735.09 60.07 739.29 55.87 742.21 55.04 C 742.04 51.25 743.66 46.93 747.09 44.04 C 752.05 40 757.87 40.62 761.39 42.53 C 763.87 43.81 766.1 46.07 767.39 49.06 C 770.04 47.23 772.87 47.78 774.49 48.73 C 776.67 50.01 777.84 52.28 777.87 54.5 C 780.12 54.75 782.79 55.78 785.11 58.85 C 786.32 60.5 787.06 63.42 787.09 65.17 L 787.09 66.98 C 787.09 71.56 782.32 76 776.7 76 Z" fill="#f58536" stroke="none" pointer-events="all"/&gt;&lt;path d="M 787.09 65.17 L 787.09 66.98 C 787.09 71.55 782.32 76 776.7 76 L 745.96 76 C 740.09 76 735.55 71.42 735.55 67.19 L 735.55 65.43 C 735.55 69.28 739.85 74.11 745.88 74.11 L 776.24 74.11 C 782.68 74.11 787.09 69.52 787.09 65.17 Z" fill-opacity="0.3" fill="#000000" stroke="none" pointer-events="all"/&gt;&lt;rect x="735.09" y="40" width="0" height="0" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/&gt;&lt;path d="M 748.15 64.72 L 750.99 64.72 L 749.61 58.59 Z M 750.92 56.94 L 754.14 69.34 L 752.09 69.34 L 751.36 66.32 L 747.85 66.32 L 747.04 69.34 L 744.99 69.34 L 748.43 56.94 Z M 766.29 56.94 L 763.88 69.34 L 761.6 69.34 L 760.03 59.73 L 758.47 69.34 L 756.26 69.34 L 753.92 56.94 L 755.82 56.94 L 757.47 66.81 L 759.04 56.94 L 761.09 56.94 L 762.74 66.88 L 764.32 56.94 Z M 774.58 60.11 L 772.67 60.11 C 772.71 59.17 772.47 58.55 771.87 58.25 C 771.5 58.07 770.71 57.92 770.1 58.29 C 769.77 58.5 769.36 58.89 769.37 59.92 C 769.39 61.23 770.33 61.72 771.25 62.09 C 772.37 62.45 773.36 62.76 774.09 63.47 C 775.22 64.55 775.11 66.27 774.79 67.31 C 774.35 68.59 773.35 69.21 772 69.42 C 770.8 69.56 769.51 69.53 768.56 68.81 C 767.49 67.95 767.29 66.68 767.32 65.41 L 769.23 65.41 C 769.2 66.25 769.31 66.91 769.65 67.33 C 770.17 67.99 771.07 68.09 771.85 67.88 C 772.8 67.58 773.05 66.69 773.02 66.12 C 773.04 65.06 772.51 64.38 771.57 64.06 C 770.04 63.52 768.88 63.28 768.05 62.3 C 767.63 61.82 767.22 60.83 767.46 59.28 C 767.67 57.98 768.53 57.22 769.31 56.9 C 770.4 56.39 772.17 56.46 773.12 56.94 C 774.09 57.39 774.65 58.38 774.58 60.11 Z" fill="#ffffff" stroke="none" pointer-events="all"/&gt;&lt;path d="M 695 163.71 L 735.09 163.71 L 735.09 203.8 L 695 203.8 Z" fill="url(#mx-gradient-f78e04-1-d05c17-1-s-0)" stroke="none" pointer-events="all"/&gt;&lt;path d="M 718.61 179.1 L 714.77 183.55 L 718.95 188.43 L 717.39 188.43 L 713.64 184.05 L 713.64 188.55 L 712.52 188.55 L 712.52 178.99 L 713.64 178.99 L 713.64 182.92 L 717.11 179.1 Z M 728.26 188.12 L 723.76 185.42 L 723.76 178.99 C 723.76 178.79 723.65 178.6 723.48 178.5 L 717.01 174.73 L 717.01 169.29 L 728.26 175.94 Z M 729.11 175.13 L 716.74 167.82 C 716.56 167.72 716.35 167.72 716.17 167.82 C 716 167.92 715.89 168.11 715.89 168.31 L 715.89 175.05 C 715.89 175.25 715.99 175.44 716.17 175.54 L 722.63 179.31 L 722.63 185.74 C 722.63 185.93 722.74 186.12 722.91 186.22 L 728.53 189.59 C 728.62 189.64 728.72 189.67 728.82 189.67 C 728.91 189.67 729.01 189.65 729.1 189.6 C 729.27 189.5 729.38 189.31 729.38 189.11 L 729.38 175.62 C 729.38 175.42 729.28 175.23 729.11 175.13 Z M 715.01 198.59 L 701.83 191.58 L 701.83 175.94 L 713.08 169.29 L 713.08 174.74 L 707.15 178.51 C 706.99 178.62 706.89 178.8 706.89 178.99 L 706.89 188.55 C 706.89 188.76 707.01 188.95 707.2 189.05 L 714.76 192.98 C 714.92 193.07 715.11 193.07 715.28 192.98 L 722.61 189.19 L 727.13 191.9 Z M 728.55 191.44 L 722.92 188.06 C 722.76 187.96 722.55 187.96 722.38 188.05 L 715.02 191.85 L 708.02 188.21 L 708.02 179.3 L 713.94 175.53 C 714.1 175.42 714.2 175.25 714.2 175.05 L 714.2 168.31 C 714.2 168.11 714.09 167.92 713.92 167.82 C 713.74 167.72 713.53 167.72 713.35 167.82 L 700.98 175.13 C 700.81 175.23 700.71 175.42 700.71 175.62 L 700.71 191.92 C 700.71 192.13 700.82 192.32 701.01 192.42 L 714.75 199.73 C 714.84 199.77 714.93 199.79 715.02 199.79 C 715.11 199.79 715.21 199.77 715.29 199.72 L 728.53 192.41 C 728.71 192.31 728.82 192.13 728.82 191.93 C 728.82 191.73 728.72 191.54 728.55 191.44 Z" fill="#ffffff" stroke="none" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 1px; height: 1px; padding-top: 184px; margin-left: 737px;"&gt;&lt;div data-drawio-colors="color: #232F3E; " style="box-sizing: border-box; font-size: 0px; text-align: left;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(35, 47, 62); line-height: 1.2; pointer-events: all; white-space: nowrap;"&gt;EKS&lt;br /&gt;Cluster&lt;br /&gt;Endpoint&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="737" y="187" fill="#232F3E" font-family="Helvetica" font-size="12px"&gt;EKS&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 525.02 456 C 511.25 456 500 444.6 500 431.53 L 500 428.52 C 500 415.94 510.46 404 524.91 404 C 539.69 404 550 415.94 550 428.72 L 550 431.14 C 550 444.73 538.98 456 525.02 456 Z" fill="#f58534" stroke="none" pointer-events="all"/&gt;&lt;path d="M 500 428.52 C 500 443.8 512.18 453.86 524.95 453.86 C 539.44 453.86 550 442.07 550 428.72 L 550 431.14 C 550 444.76 538.98 456 525.02 456 C 511.14 456 500 444.59 500 431.53 Z" fill-opacity="0.3" fill="#000000" stroke="none" pointer-events="all"/&gt;&lt;rect x="500" y="404" width="0" height="0" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/&gt;&lt;path d="M 513.25 429.26 C 515.12 436.4 519.07 442.04 525 444.99 C 528.79 443.32 531.86 439.82 533.52 437.03 C 536.51 432.03 537.91 426.02 537.97 419.67 C 536.39 419.48 534.76 418.95 533.83 418.06 C 533 417.31 532.14 415.84 531.81 414 C 529.38 413.22 526.9 412.74 524.75 412.78 C 522.25 412.87 520.14 413.42 518.33 414 C 518.08 415.61 517.25 417.28 516.28 418.08 C 515.03 419.12 513.52 419.53 512.01 419.74 C 512.02 421.85 512.25 424.14 512.62 426.3 L 524.75 426.3 L 524.75 421.46 L 532.48 427.86 L 524.75 434.18 L 524.75 429.26 Z M 504.85 429.26 L 504.85 426.3 L 510.15 426.3 C 509.67 423.41 509.5 420.39 509.54 417.44 C 511.74 417.55 513.73 417.13 514.61 416.23 C 515.54 415.24 515.82 413.79 515.95 412.36 C 518.5 411.29 521.71 410.43 524.64 410.4 C 527.82 410.32 530.93 411.13 534.05 412.19 C 534.21 414.49 534.9 415.95 535.94 416.49 C 537.29 417.12 538.95 417.22 540.45 417.27 C 540.45 425.99 539.22 431.56 536 437.45 C 533.77 441.47 530.08 445.42 524.99 447.55 C 520.99 446.01 517.2 442.74 514.59 438.57 C 512.83 435.81 511.5 432.53 510.75 429.26 Z" fill="#ffffff" stroke="none" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 463px; margin-left: 525px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"&gt;AWS Service Endpoint&lt;br /&gt;https://eks.us-west-2.amazonaws.com&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="525" y="475" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;AWS Serv&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 157.49 255 L 230 255 L 230 430 L 493.63 430" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/&gt;&lt;path d="M 498.88 430 L 491.88 433.5 L 493.63 430 L 491.88 426.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;path d="M 157.49 174.14 L 188.83 182.1" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/&gt;&lt;path d="M 193.92 183.39 L 186.27 185.06 L 188.83 182.1 L 187.99 178.28 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;path d="M 290 410 C 266 410 260 430 279.2 434 C 260 442.8 281.6 462 297.2 454 C 308 470 344 470 356 454 C 380 454 380 438 365 430 C 380 414 356 398 335 406 C 320 394 296 394 290 410 Z" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 430px; margin-left: 261px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Internet&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="320" y="434" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Internet&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="0" y="390" width="210" height="110" fill="none" stroke="none" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 208px; height: 1px; padding-top: 445px; margin-left: 2px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left;"&gt;&lt;div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Note: kubectl calls aws-cli for authentication. So make sure that aws-cli uses the right profile and assumes the right role, if applicable.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="2" y="449" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="14px"&gt;Note: kubectl calls aws-cli fo&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 115.06 168.81 L 50 169 L 52.43 383.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="8 8" pointer-events="stroke"/&gt;&lt;path d="M 52.49 388.88 L 48.91 381.92 L 52.43 383.63 L 55.91 381.84 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;path d="M 356.25 193.75 L 359.36 333.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="8 8" pointer-events="stroke"/&gt;&lt;path d="M 359.48 338.88 L 355.82 331.96 L 359.36 333.63 L 362.82 331.81 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;rect x="286" y="340" width="294" height="40" fill="none" stroke="none" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 292px; height: 1px; padding-top: 360px; margin-left: 288px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left;"&gt;&lt;div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;The SSH Tunnel is established on top of a proxy command using SSM session manager or EC2 Instance Connect with EIC Endpoint&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="288" y="364" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="14px"&gt;The SSH Tunnel is established on top of a&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 215.45 165.22 L 217.38 65.25" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/&gt;&lt;path d="M 217.48 60 L 220.84 67.06 L 217.38 65.25 L 213.84 66.93 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;rect x="150" y="8.88" width="270" height="50" fill="none" stroke="none" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 268px; height: 1px; padding-top: 34px; margin-left: 152px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left;"&gt;&lt;div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Tell kubectl to use SOCKS5 proxy by the HTTPS_PROXY environment variable or by the proxy-url attribute in .kube/config&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="152" y="38" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="14px"&gt;Tell kubectl to use SOCKS5 proxy by th&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;switch&gt;&lt;g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/&gt;&lt;a transform="translate(0,-5)" xlink:href="https://www.drawio.com/doc/faq/svg-export-text-problems" target="_blank" rel="noopener"&gt;&lt;text text-anchor="middle" font-size="10px" x="50%" y="100%"&gt;Text is not SVG &amp;#8211; cannot display&lt;/text&gt;&lt;/a&gt;&lt;/switch&gt;&lt;/svg&gt;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To put this in practice, I first created a VPC stack with a bastion host using terraform template from my &lt;a href="https://github.com/digihunch/vpc-base/tree/main"&gt;vpc-base&lt;/a&gt; project. The terraform output will give the next set of commands to run to create a private cluster, using a manifest rendered from the file &lt;a href="https://github.com/digihunch/vpc-base/blob/main/template/eksctl.tpl"&gt;private-cluster.yaml.tmpl&lt;/a&gt;:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# cd aws_vpc&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# terraform init&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# terraform plan&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# terraform apply&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# ... run the given command ...&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# envsubst &amp;lt; private-cluster.yaml.tmpl | tee | eksctl create cluster -f -&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Run this from a remote host without access to cluster endpoint.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Run terraform apply and terraform output contains the variables needed for the next steps&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# the command below may take 15 minutes to create a private cluster&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;eksctl create cluster -f private-cluster.yaml &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;aws eks update-kubeconfig --name private-cluster&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;At this point, the kubeconfig file has been updated, but kubectl (from Internet or on-prem) is unable to connect to cluster endpoint (on private network). In order to &lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;BASTION_SECURITY_GROUP_ID&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;terraform output -raw bastion_sg_id&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CLUSTER_SECURITY_GROUP_ID&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;aws eks describe-cluster --name private-cluster --query &lt;span style="color:#e6db74"&gt;&amp;#34;cluster.resourcesVpcConfig.clusterSecurityGroupId&amp;#34;&lt;/span&gt; --output text&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# In Cluster Endpoint&amp;#39;s security group, open up port 443 to Bastion host&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;aws ec2 authorize-security-group-ingress --group-id $CLUSTER_SECURITY_GROUP_ID --source-group $BASTION_SECURITY_GROUP_ID --protocol tcp --port &lt;span style="color:#ae81ff"&gt;443&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Test with connecting to Bastion host with ssh i-0750643179667a5b6, assuming .ssh/config file is configured as above. From the bastion host, you can test:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# curl -k https://EC5405EE1846F19F9F61ED28FB12A6A9.sk1.us-west-2.eks.amazonaws.com/api &lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# if you get an HTTP response, even an error code 403, the bastion host has TCP connectivity to cluster endpoint&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# then we can start an SSH session as a SOCKS5 proxy on the remote host&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ssh -D &lt;span style="color:#ae81ff"&gt;1080&lt;/span&gt; -q -N i-0750643179667a5b6&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# add &amp;gt; /dev/null 2&amp;gt;&amp;amp;1 &amp;amp; to push it to background, or use ctrl+z after running the command&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# to validate that the SOCKS5 proxy is working, you can run the same curl command with a proxy parameter:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# curl -k https://EC5405EE1846F19F9F61ED28FB12A6A9.sk1.us-west-2.eks.amazonaws.com/api --proxy socks5://localhost:1080&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# you can instruct kubectl to use the SOCKS5 proxy with the following environment variable&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export HTTPS_PROXY&lt;span style="color:#f92672"&gt;=&lt;/span&gt;socks5://localhost:1080&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl get node&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# alternatively, add &amp;#34;proxy-url: socks5://localhost:1080&amp;#34; below server attribute in ~/.kube/config file.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;There are some pitfalls to watch for. On the remote host both ssh command and kubectl command implicitly uses AWS CLI. Therefore, make sure the profile and IAM role are correctly configured. For example, if SSM agent requires one IAM role, and kubectl is created with another IAM role, then make sure AWS CLI &lt;a href="https://repost.aws/knowledge-center/iam-assume-role-cli"&gt;assumes the correct IAM role&lt;/a&gt; using environment variables, and use &amp;#8220;aws sts get-caller-identity&amp;#8221; to validate the IAM identity being used.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;What about AKS in Azure&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I touched on this in my &lt;a href="https://www.digihunch.com/2021/10/notes-on-azure/"&gt;Azure notes&lt;/a&gt; in 2021 and did a research again. Unfortunately, options are still fairly limited. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The first option is to use a managed service called &amp;#8220;Azure Bastion&amp;#8221;, which requires public IP and a dedicated subnet with the exact name of AzureBastionSubnet, as well as some &lt;a href="https://learn.microsoft.com/en-us/azure/bastion/configuration-settings#subnet"&gt;additional requirement&lt;/a&gt;. I&amp;#8217;m not impressed with these requirement because it is meant to be a managed service. The other option, is essentially to DIY a JumpBox. The idea is the same: put the jumpbox in a public subnet, which is routable to private subnets. When you need to connect to private VMs, get to the jumpbox first.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Apart from having to put the bastion VM on a public subnet, the pattern that we discussed above involving SOCKS5 proxy still works. Exposing a bastion host isn&amp;#8217;t ideal but it still reduces attack surface significantly, comparing to exposing the cluster endpoints of all Kubernetes API servers.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Summary&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Many immature Kubernetes configurations exposes private endpoint publicly. Having cluster endpoint in private subnet greatly improves security posture. In my opinion, there are very few situations where cluster endpoint must exposed publicly. Having private endpoint should be mandatory for all Kubernetes cluster. In the next &lt;a href="https://www.digihunch.com/2023/06/kubernetes-paas-and-red-hat-openshift/"&gt;post&lt;/a&gt;, I also cover how to create a ROSA cluster with private endpoint.&lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://www.digihunch.com/2023/05/kubernetes-with-multiple-cpu-architectures/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Kubernetes with Multiple CPU Architectures 2 of 2 – Node and Workload&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://www.digihunch.com/2023/06/kubernetes-paas-and-red-hat-openshift/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Kubernetes Platform as a Service and Red Hat OpenShift&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>IPVS, iptables and kube-proxy</title><link>https://www.digihunch.com/2020/11/ipvs-iptables-and-kube-proxy/</link><pubDate>Tue, 24 Nov 2020 13:17:00 -0400</pubDate><guid>https://www.digihunch.com/2020/11/ipvs-iptables-and-kube-proxy/</guid><description>&lt;p class="wp-block-paragraph"&gt;This is an overview of the underlying technologies that drives load balancing. It covers LVS, Netfilter, iptables, IPVS and eventually kube-proxy.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-lvs-linux-virtual-server"&gt;LVS (Linux Virtual Server)&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;One of the ways to implement software load balancing is via LVS (Linux Virtual Server), as &lt;a href="https://www.digihunch.com/2020/01/several-ways-to-ensure-high-availability/" class="rank-math-link"&gt;previously discussed&lt;/a&gt;. The diagram below shows the LVS &lt;a href="http://www.linuxvirtualserver.org/about.html" class="rank-math-link"&gt;framework&lt;/a&gt;, with IPVS as the fundamental technology:&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-large"&gt;&lt;img loading="lazy" decoding="async" width="304" height="340" src="https://www.digihunch.com/wp-content/uploads/2021/05/lvs.jpeg" alt="" class="wp-image-2262"/&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The major work of the LVS project is to develop advanced IP load balancing software (IPVS), application-level load balancing software (KTCPVS), cluster management components. &lt;a href="http://www.linuxvirtualserver.org/software/ktcpvs/ktcpvs.html" class="rank-math-link"&gt;KTCPVS &lt;/a&gt;implements application-level load balancing inside the Linux kernel (still under development). &lt;a href="http://www.linuxvirtualserver.org/software/ipvs.html" class="rank-math-link"&gt;IPVS &lt;/a&gt;is an advanced IP load balancing software implemented inside the Linux kernel. The IPVS code was already included into the standard Linux kernel 2.4 and 2.6.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-netfilter"&gt;Netfilter&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Both IPVS and iptables (the technology behind Linux firewall, discussed &lt;a href="https://www.digihunch.com/2018/10/redhat-firewall-configuration-firewalld-vs-iptables/" class="rank-math-link"&gt;here&lt;/a&gt;) are based on &lt;strong&gt;netfilter&lt;/strong&gt;, a &lt;span style="text-decoration: underline;"&gt;packet-filtering framework&lt;/span&gt; provided by the Linux kernel. In this section, we will discuss them all together, starting with Netfilter and then discuss how iptables and IPVS uses netfilter. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Netfilter allows various networking-related operations to be implemented in the form of customized handlers, by offers various functions and operations for &lt;span style="text-decoration: underline;"&gt;packet filtering&lt;/span&gt;, &lt;span style="text-decoration: underline;"&gt;network address translation&lt;/span&gt;, and &lt;span style="text-decoration: underline;"&gt;port translation&lt;/span&gt;, which provide the functionality required for directing packets through a network and prohibiting packets from reaching sensitive locations within a network. Netfilter represents a set of &lt;strong&gt;hooks&lt;/strong&gt; inside the Linux kernel, allowing specific kernel modules to register &lt;strong&gt;callback&lt;/strong&gt; functions with the kernel&amp;#8217;s networking stack. Those functions, usually applied to the traffic in the form of filtering and modification rules, are called for every packet that traverses the respective hook within the networking stack.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-iptables"&gt;Iptables&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The kernel modules named &lt;strong&gt;ip_tables&lt;/strong&gt;, &lt;strong&gt;ip6_tables&lt;/strong&gt;, &lt;strong&gt;arp_tables &lt;/strong&gt;(the underscore is part of the name), and &lt;strong&gt;ebtables &lt;/strong&gt;comprise the &lt;span style="text-decoration: underline;"&gt;legacy packet filtering portion of the Netfilter hook system&lt;/span&gt;. They provide a table-based system for defining firewall rules that can filter or transform packets. The tables can be administered through the &lt;span style="text-decoration: underline;"&gt;user-space tools&lt;/span&gt; &lt;strong&gt;iptables&lt;/strong&gt;, &lt;strong&gt;ip6tables&lt;/strong&gt;, &lt;strong&gt;arptables&lt;/strong&gt;, and &lt;strong&gt;ebtables&lt;/strong&gt;. &lt;strong&gt;Notice&lt;/strong&gt; that although both the &lt;span style="text-decoration: underline;"&gt;kernel modules&lt;/span&gt; and &lt;span style="text-decoration: underline;"&gt;userspace utilities&lt;/span&gt; have similar names, each of them is a different entity with different functionality.&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-full"&gt;&lt;img loading="lazy" decoding="async" width="1024" height="306" src="https://www.digihunch.com/wp-content/uploads/2023/01/iptables.jpeg" alt="" class="wp-image-7749" srcset="https://www.digihunch.com/wp-content/uploads/2023/01/iptables.jpeg 1024w, https://www.digihunch.com/wp-content/uploads/2023/01/iptables-300x90.jpeg 300w, https://www.digihunch.com/wp-content/uploads/2023/01/iptables-768x230.jpeg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;When a network packet is received on a network device, it first passes through the &lt;strong&gt;&lt;em&gt;Prerouting &lt;/em&gt;&lt;/strong&gt;hook. This is where the routing decision takes place. The kernel decides whether the packet is destined for a local process (e.g., a listening socket on a server in this system) or whether to forward it (system operates as a router). In the first case, the packet passes the &lt;strong&gt;&lt;em&gt;Input &lt;/em&gt;&lt;/strong&gt;hook and is then handed over to the local process.  If the packet is destined to be forwarded, it traverses the &lt;strong&gt;&lt;em&gt;Forward &lt;/em&gt;&lt;/strong&gt;hook and then a final &lt;strong&gt;&lt;em&gt;Postrouting &lt;/em&gt;&lt;/strong&gt;hook before being sent out on a network device. For packets that are generated locally (e.g., by a client or server process that likes sending things out), they must first pass the &lt;strong&gt;&lt;em&gt;Output &lt;/em&gt;&lt;/strong&gt;hook and then the  &lt;strong&gt;&lt;em&gt;Postrouting &lt;/em&gt;&lt;/strong&gt;hook before being sent out on a network device.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The aforementioned hooks &amp;nbsp;exist independently for the IPv4 and IPv6 protocols. Thus, IPv4 and IPv6 packets each traverse their own hooks. There are also other hooks for ARP packets and for Bridging. And all the &amp;nbsp;hooks exist independently within each network namespace. Additionally, there is an&amp;nbsp;&lt;strong&gt;&lt;em&gt;ingress&amp;nbsp;&lt;/em&gt;&lt;/strong&gt;hook for each network device. The list goes on… More explanations are from &lt;a href="https://www.teldat.com/blog/en/nftables-and-netfilter-hooks-via-linux-kernel/" class="rank-math-link"&gt;here&lt;/a&gt; and &lt;a href="https://www.digitalocean.com/community/tutorials/a-deep-dive-into-iptables-and-netfilter-architecture#iptables-rules" class="rank-math-link"&gt;here&lt;/a&gt;.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-ipvs"&gt;IPVS&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In LVS, IPVS is also based on netfilter framework, but works only on INPUT chain, by registering ip_vs_in hook function, to process request. IPVS (aka layer-4 switching) runs on a host at the front of a cluster of real servers. It directs requests for TCP/UDP based servers to the real server, while ensuring the resonse from (one or several) real server appears to the client as if they were all from a virtual service on a sigle IP address. It is based on in-kernel hash tables. The userspace utility is ipvsadm.&lt;/p&gt;&#10;&lt;figure class="wp-block-image"&gt;&lt;img decoding="async" src="https://i.imgur.com/i60QKw4.png" alt=""/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;When the client request reaches the kernel space of load balancer, it arrives at PREROUTING chain. Route will determine whether the request packet is for the local host or not, based on the destination address of the packet. The packet is sent to INPUT chain if it is. The ip_vs_in function is hooked to LOCAL_IN and will examine the packet. If it finds a matching IPVS rule, it will (bypass INPUT chain) directly trigger POSTROUTING chain, &lt;strong&gt;skipping &lt;/strong&gt;iptables rules.vThis is discussed in detail &lt;a href="http://www.austintek.com/LVS/LVS-HOWTO/HOWTO/LVS-HOWTO.filter_rules.html" class="rank-math-link"&gt;here&lt;/a&gt;. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;IPVS supports 8 load balancing algorithms (round robin, weighted round robin, least-connection, weighted least connection, locality-based least-connection, locality-based least-connection with replication, destination-hashing, and source-hashing) and 3 packet-forwarding methods (NAT, tunneling and direct routing).&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The main difference between iptables and IPVS, is &lt;a href="https://www.thegeekstuff.com/2011/01/iptables-fundamentals/"&gt;iptables&lt;/a&gt; includes a number of tables, each with a number of chains, each further involves a number of rules. The total number of rules is large. The packet is assessed against many of such rules. For the same reason, the order of the rule matters. IPVS on the other hand, leverages hash table, with a complexity of O(1), or O(n) in the worst case scenarios. They vary significantly in the efficiency of packet filtering and forwarding, especially when the rules gets complicated. Iptable also presents more latency when adding or removing rules as more rules are involved. This &lt;a href="https://www.slideshare.net/LCChina/scale-kubernetes-to-support-50000-services" class="rank-math-link"&gt;presentation &lt;/a&gt;includes some quantitative comparison.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-kubeproxy"&gt;KubeProxy&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In Kubernetes architecture, &lt;a class="rank-math-link" href="https://kubernetes.io/docs/reference/command-line-tools-reference/kube-proxy/"&gt;KubeProxy &lt;/a&gt;takes care of load balancing. Kube-proxy can run in three modes: userspace, iptables and IPVS. &lt;/p&gt;&#10;&lt;figure class="wp-block-image is-resized"&gt;&lt;img loading="lazy" decoding="async" src="https://d33wubrfki0l68.cloudfront.net/e351b830334b8622a700a8da6568cb081c464a9b/13020/images/docs/services-userspace-overview.svg" alt="Services overview diagram for userspace proxy" width="826" height="464"/&gt;&lt;figcaption class="wp-element-caption"&gt;userspace proxy mode&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The userspace mode is old and inefficient. The packet is compared against iptables rule and then forwarded to a pod named kube-Proxy, which operates as an application to forward packet to backend pods.&lt;/p&gt;&#10;&lt;figure class="wp-block-image is-resized"&gt;&lt;img loading="lazy" decoding="async" src="https://d33wubrfki0l68.cloudfront.net/27b2978647a8d7bdc2a96b213f0c0d3242ef9ce0/e8c9b/images/docs/services-iptables-overview.svg" alt="Services overview diagram for iptables proxy" width="810" height="601"/&gt;&lt;figcaption class="wp-element-caption"&gt;iptables proxy mode&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The iptables mode is better since it uses the kernel feature of iptables, which is fairly mature. kube-proxy manages iptables rule based on the service yaml of Kubernetes.&lt;/p&gt;&#10;&lt;figure class="wp-block-image is-resized"&gt;&lt;img loading="lazy" decoding="async" src="https://d33wubrfki0l68.cloudfront.net/2d3d2b521cf7f9ff83238218dac1c019c270b1ed/9ac5c/images/docs/services-ipvs-overview.svg" alt="Services overview diagram for IPVS proxy" width="810" height="601"/&gt;&lt;figcaption class="wp-element-caption"&gt;IPVS proxy mode&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;With the comparison between iptables and IPVS earlier, we can expect that iptables operations slow down dramatically in large scale cluster. Therefore IPVS based kubeproxy was &lt;a class="rank-math-link" href="https://github.com/kubernetes/kubernetes/issues/17470"&gt;brought up&lt;/a&gt;. This &lt;a class="rank-math-link" href="https://speakerdeck.com/sufuf3/ipvs-based-kube-proxy-for-scaled-kubernetes-load-balancing"&gt;presentation &lt;/a&gt;illustrated the differences.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In this post we discussed load balancing technologies from ipvs to iptables and then to kube-proxy, which is used in Kubernetes nodes.&lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://www.digihunch.com/2020/11/how-imaging-devices-talk-to-each-other-tip-in-dicom/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;How imaging devices talk to each other (in DICOM)&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://www.digihunch.com/2020/12/instance-initialization-with-aws-cdk-in-python/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;AWS CDK example in Python – provision Kubernetes Nodes&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Redhat Firewall configuration: from iptables to firewalld</title><link>https://www.digihunch.com/2018/10/redhat-firewall-configuration-firewalld-vs-iptables/</link><pubDate>Fri, 12 Oct 2018 17:56:00 -0400</pubDate><guid>https://www.digihunch.com/2018/10/redhat-firewall-configuration-firewalld-vs-iptables/</guid><description>&lt;h3 class="wp-block-heading"&gt;Tools to manage firewall&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Packet filter rules in Linux Kernel is managed by an user-space application named iptables in CentOS and RedHat. Since CentOS 7, &lt;a href="https://en.wikipedia.org/wiki/Firewalld"&gt;firewalld&lt;/a&gt; is introduced as an alternative to iptables. Firewalld can be installed and executed as a systemd service, and it is supposed to replace iptables. This &lt;a href="https://www.tecmint.com/firewalld-vs-iptables-and-control-network-traffic-in-firewall/"&gt;article&lt;/a&gt; describes how to configure both. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;There are several advantages in firewalld. One is is the support of &lt;a href="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/security_guide/sec-using_zones_to_manage_incoming_traffic_depending_on_source"&gt;zones&lt;/a&gt;. &lt;a href="https://www.digitalocean.com/community/tutorials/how-to-set-up-a-firewall-using-firewalld-on-centos-7"&gt;Here&lt;/a&gt; are some useful information. Also, iptables involves three different services for IPv4(iptables), IPv6(ip6tables), and software bridging (ebtables), whereas firewalld only involves a single service to manage all three. Firewalld allows user to add or remove rules/ports from running firewall, without restarting firewall. Unless you have specific reason to use iptables, always use firewalld service to manage firewall. Here is an instruction to firewalld service. In this posting however, we will be focusing on iptables to understand firewall managment. We also go through an example of opening a TCP port. &lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;How does iptables work&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;When working with iptables, it is important to understand that its related concepts (&lt;strong&gt;tables-&amp;gt;chains-&amp;gt;rules-&amp;gt;criteria and targets&lt;/strong&gt;) and how the &lt;strong&gt;order of rules&lt;/strong&gt; plays a factor. There are five independent &lt;strong&gt;&lt;span style="text-decoration: underline;"&gt;tables&lt;/span&gt;&lt;/strong&gt;, each contains a number of &lt;strong&gt;&lt;span style="text-decoration: underline;"&gt;chains&lt;/span&gt;&lt;/strong&gt;, either &lt;em&gt;built-in&lt;/em&gt; or &lt;em&gt;user-defined&lt;/em&gt;. Administrators mostly deals with &lt;em&gt;&lt;span style="text-decoration: underline;"&gt;built-in chains&lt;/span&gt;&lt;/em&gt; in &lt;em&gt;&lt;span style="text-decoration: underline;"&gt;filter&lt;/span&gt;&lt;/em&gt; and &lt;em&gt;&lt;span style="text-decoration: underline;"&gt;nat&lt;/span&gt;&lt;/em&gt; tables. The five tables are:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;&lt;strong&gt;filter&lt;/strong&gt;: If -t isn&amp;#8217;t specified, this is the default table. It contains built-in chains:&lt;ul&gt;&lt;li&gt;&lt;strong&gt;INPUT&lt;/strong&gt;: for packet destined to local sockets&lt;/li&gt;&lt;li&gt;&lt;strong&gt;FORWARD&lt;/strong&gt;: for packets being routed through the box&lt;/li&gt;&lt;li&gt;&lt;strong&gt;OUTPUT&lt;/strong&gt;: for locally-generated packets&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;nat&lt;/strong&gt;: this table is consulted when a packet that creates a new connection is encountered. It has three built-in chains:&lt;ul&gt;&lt;li&gt;&lt;strong&gt;PREROUTING&lt;/strong&gt;: for altering packets as soon as they come in&lt;/li&gt;&lt;li&gt;&lt;strong&gt;OUTPUT&lt;/strong&gt;: for altering locally generated packets before routing&lt;/li&gt;&lt;li&gt;&lt;strong&gt;POSTROUTING&lt;/strong&gt;: for altering packets as they are about to go out&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;mangle&lt;/strong&gt;: this table is used for specialized packet alternation, with five built-in chains (since kernel 2.4.18): PREROUTING and OUTPUT, INPUT, FORWARD, and POSTROUTING&lt;/li&gt;&lt;li&gt;&lt;strong&gt;raw&lt;/strong&gt;: this table is mainly for configuring exceptions from connection tracking with two built-in chains: PREROUTING and OUTPUT&lt;/li&gt;&lt;li&gt;&lt;strong&gt;security&lt;/strong&gt;: for Mandatory Access Control (MAC) networking rules, with three built-in chains: INPUT, OUTPUT, and FORWARD.&lt;/li&gt;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Under the table (e.g. filter, nat), each chain (e.g. INPUT, OUTPUT, etc) consists of list of &lt;span style="text-decoration: underline;"&gt;&lt;strong&gt;firewall rules&lt;/strong&gt;&lt;/span&gt;. Each rule is made up of two parts defined for the packets:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;&lt;strong&gt;Criteria&lt;/strong&gt;: if the packet does not match the criteria, the next rule in the chain is examined; if it does match, then the next rule is specified by the value of the target.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Target&lt;/strong&gt;: what to do if criteria is met. The target can be:&lt;ul&gt;&lt;li&gt;user-defined chain, &lt;/li&gt;&lt;li&gt;one of the target described in iptables-extensions, or &lt;/li&gt;&lt;li&gt;in most cases, one of the special values ACCEPT, DROP or RETURN&lt;ul&gt;&lt;li&gt;&lt;strong&gt;ACCEPT&lt;/strong&gt; &amp;#8211; let the packet through&lt;/li&gt;&lt;li&gt;&lt;strong&gt;DROP&lt;/strong&gt; &amp;#8211; drop the packet on the floor&lt;/li&gt;&lt;li&gt;&lt;strong&gt;RETURN&lt;/strong&gt; &amp;#8211; stop traversing this chain, and resume at &lt;span style="text-decoration: underline;"&gt;next rule in the previous (calling) chain&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The rules, defined in each chain under their tables, can be found in file /etc/sysconfig/iptables. You can find tables (prefix with asterisk *), chains (prefix with colon :), rules under their chains and a statement COMMIT after each table. The iptables process flow illustrates how a packet interact with all these rules under different chains and tables defined in this file: &lt;/p&gt;&#10;&lt;figure class="wp-block-image"&gt;&lt;img decoding="async" src="https://miro.medium.com/max/1000/1*OIoNQkH4RTSm-eY2lUMBcQ.jpeg" alt="IPTables and Docker. In this post I will be talking about… | by Edouard Buschini | Medium"/&gt;&lt;figcaption&gt;iptables Process Flow&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Although this big picture looks formidable, an administrator commonly only deals with the green and purple blocks (filter and nat), with the big picture in mind. Here is an example of /etc/sysconfig/iptables file from a newly installed system:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Generated by iptables-save v1.4.21 on Fri Sep 11 23:15:32 2017&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;*filter&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;:INPUT ACCEPT &lt;span style="color:#f92672"&gt;[&lt;/span&gt;0:0&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;:FORWARD ACCEPT &lt;span style="color:#f92672"&gt;[&lt;/span&gt;0:0&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;:OUTPUT ACCEPT &lt;span style="color:#f92672"&gt;[&lt;/span&gt;132:17200&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -p icmp -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -i lo -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -p tcp -m state --state NEW -m tcp --dport &lt;span style="color:#ae81ff"&gt;22&lt;/span&gt; -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -j REJECT --reject-with icmp-host-prohibited&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A FORWARD -j REJECT --reject-with icmp-host-prohibited&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;COMMIT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Completed on Fri Sep 11 23:15:32 2017&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The rule simply allows SSH traffic. This file will be loaded up on every reboot (specifically, restart of iptables service). So if you have made some changes to rules and you want the change picked up on reboot. The rules should be saved to this file:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo iptables-save &amp;gt; /etc/sysconfig/iptables&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Other than saving rule for reboot, if you simply want to edit the rules (e.g. order of rules is incorrect), you can save the rules to file, modify the file and restore the rule from file:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo iptables-save &amp;gt; ~/iptables.txt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo vi ~/iptables.txt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo iptables-restore &amp;amp;lt; ~/iptables.txt&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://www.digitalocean.com/community/tutorials/a-deep-dive-into-iptables-and-netfilter-architecture"&gt;Here&lt;/a&gt; is some further reading about iptables architecture.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Anatomy of a rule&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The man page for iptables species the following synopsis:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;iptables [-t table] {-A|-C|-D} chain rule-specification&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rule-specification = [matches...] [target]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;match = -m matchname [per-match-options]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;target = -j targetname [per-target-options]&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;So when you append (-A), delete (-D), insert (-I) or replace (-R) a rule, you need to specify rule specification. The man page further explains that the following parameters make up a rule specification:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;&lt;strong&gt;protocol (-p)&lt;/strong&gt;: the protocol of the rule of the packet to check. value can be tcp, udp, icmp, all or any name defined in /etc/protocols.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;match (-m)&lt;/strong&gt;: specifies the name of a match to use and is followed by match options. The match refers to an extension module that tests for a specific property. Those extension modules are documented in the man page of &lt;a href="https://ipset.netfilter.org/iptables-extensions.man.html"&gt;iptables-extensions&lt;/a&gt;. You may specify -m multiple times for different match names, which together make up the condition under which a target is invoked. Matches are evaluated first to last as specified. We often use extensions &lt;em&gt;tcp&lt;/em&gt; and &lt;em&gt;state&lt;/em&gt;. According to iptables-extensions man page, we can specify &amp;#8211;dport followed by port number for the &lt;em&gt;tcp&lt;/em&gt; extension, and &amp;#8211;state followed by value such as NEW or ESTABLISHED for the &lt;em&gt;state&lt;/em&gt; extension.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;jump (-j)&lt;/strong&gt;: specifies the target of the rule, such as ACCEPT, REJECT or DROP.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;source and destination (-s and -d)&lt;/strong&gt;: source and destination IP address or masks. Hostname will work but not recommended since resolution is needed.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;inbound and outbound interface (-i and -o)&lt;/strong&gt;: name of interface via which the packet was received and is going to be sent.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;goto (-g)&lt;/strong&gt;: processing should continue in a user specified chain&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Other&lt;/strong&gt; parameters: -4/&amp;#8211;ipv4, -6/&amp;#8211;ipv6, -c/&amp;#8211;set-counters, -f/&amp;#8211;fragment&lt;/li&gt;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;When we run iptables command to view rules, we need to specify the table (e.g. filter, nat, etc) followed by -S or &amp;#8211;list-rules:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ iptables -t nat -S&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;If you do not specify -t switch, the default (-t filter) is applied. Be aware that in this case, you&amp;#8217;re only seeing rules under filter table, and not all rules under tall tables!&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In the result, for example one line from command &amp;#8220;iptables -S&amp;#8221; may say:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -p tcp -m state --state NEW -m tcp --dport &lt;span style="color:#ae81ff"&gt;9200&lt;/span&gt; -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The interpretation: appending a rule to INPUT chain of filter table (implicitly specified). The protocol is tcp. The first match extension is state, and the state value shall be NEW. The second match extension is tcp, and the dport value shall be 9200. If the packet is a match, then the target (action) is ACCEPT.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Managing rules&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;As mentioned earlier, rules can be dumped to any file or /etc/sysconfig/iptables, in which the rules are assessed in order. Below is a real life iptables file with a nat table as well. &lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Generated by iptables-save v1.4.21 on Wed Jan 15 13:58:39 2017&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;*filter&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;:INPUT DROP [0:0]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;:FORWARD DROP [0:0]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;:OUTPUT ACCEPT [4:208]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -p icmp -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -i lo -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -s 10.100.160.56/32 -p tcp -m state --state NEW -m tcp --dport 7000:7001 -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -s 10.100.160.56/32 -p tcp -m state --state NEW -m tcp --dport 7199 -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -s 10.100.160.56/32 -p tcp -m state --state NEW -m tcp --dport 9042 -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -s 10.100.160.56/32 -p tcp -m state --state NEW -m tcp --dport 9160 -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -p tcp -m state --state NEW -m tcp --dport 8080 -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -p udp -m state --state NEW -m udp --dport 161 -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -p udp -m state --state NEW -m udp --dport 162 -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -j REJECT --reject-with icmp-host-prohibited&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A FORWARD -j REJECT --reject-with icmp-host-prohibited&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;COMMIT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;*nat&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;:PREROUTING ACCEPT [1:328]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;:INPUT ACCEPT [0:0]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;:OUTPUT ACCEPT [0:0]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;:POSTROUTING ACCEPT [0:0]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A PREROUTING -p tcp -m tcp --dport 2392 -j REDIRECT --to-ports 2398&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A PREROUTING -p tcp -m tcp --dport 2393 -j REDIRECT --to-ports 2398&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A OUTPUT -o lo -p tcp -m tcp --dport 2392 -j REDIRECT --to-ports 2398&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A OUTPUT -o lo -p tcp -m tcp --dport 2393 -j REDIRECT --to-ports 2398&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;COMMIT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Completed on Wed Jan 15 13:58:39 2017&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;In this example, the nat table defines traffic forwarding: traffic arriving at TCP port 2392 and 2393 are forwarded to port 2398; outgoing traffic to port 2392 and 2393 are also redirected to port 2398. These rules do not overlap each other so the rules probably don&amp;#8217;t matter.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;On the other hand, the tcp filter table lists the rules to open certain TCP and UDP ports. Its block starts with a couple accepting rules and ends with a couple reject rules (regardless of protocols or ports). This is a good way to close a chain of rules with security. However, if you need to add additional rules to open more TCP ports, the new rule should not be appended after the reject rules at the bottom since the order matter here!&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Correct way to open a TCP port&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;It&amp;#8217;s a common task for developers to open a TCP port simply for the purpose of bring up a web service and make it accessible to client. If we simply add a new rule to existing list, for example:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 9870 -j ACCEPT&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# iptables -S&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-P INPUT ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-P FORWARD ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-P OUTPUT ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -p icmp -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -i lo -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -p tcp -m state --state NEW -m tcp --dport &lt;span style="color:#ae81ff"&gt;22&lt;/span&gt; -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -j REJECT --reject-with icmp-host-prohibited&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -p tcp -m state --state NEW -m tcp --dport &lt;span style="color:#ae81ff"&gt;9870&lt;/span&gt; -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A FORWARD -j REJECT --reject-with icmp-host-prohibited&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# systemctl reload iptables&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;You will notice that the rule is appended to the end of INPUT block, below the INPUT REJECT rule, which will never take effect.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To address this, you can use iptables-save and iptables-restore to export, edit to correct order and reload the rule, as illustrated above, instead of using iptables command to modify the rule directly. &lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# iptables-save &amp;gt; /tmp/rule.list&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# vi /tmp/rule.list&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# iptables-restore &amp;lt; /tmp/rule.list&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# iptables -S&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-P INPUT ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-P FORWARD ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-P OUTPUT ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -p icmp -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -i lo -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -p tcp -m state --state NEW -m tcp --dport &lt;span style="color:#ae81ff"&gt;22&lt;/span&gt; -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -p tcp -m state --state NEW -m tcp --dport &lt;span style="color:#ae81ff"&gt;9870&lt;/span&gt; -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -j REJECT --reject-with icmp-host-prohibited&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A FORWARD -j REJECT --reject-with icmp-host-prohibited&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Alternatively, you could use some advanced iptables command switches to add the new rule to certain line number with &amp;#8211;line-number switch. &lt;a href="https://www.osetc.com/en/linux-iptables-insert-rule-at-a-specific-position-prepend-firewall-rule.html"&gt;Here&lt;/a&gt; is more information.&lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://www.digihunch.com/2018/09/log-shipping-through-elk/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Log shipping through ELK&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://www.digihunch.com/2018/11/the-java-confusions/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Java version confusions&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item></channel></rss>