<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ali Naqvi</title>
    <description>The latest articles on DEV Community by Ali Naqvi (@naqvis).</description>
    <link>https://dev.to/naqvis</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F785096%2F9d240025-398f-4c49-a6ae-c474c2f9a958.jpeg</url>
      <title>DEV Community: Ali Naqvi</title>
      <link>https://dev.to/naqvis</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/naqvis"/>
    <language>en</language>
    <item>
      <title>Pipy proxy: Creating HTTP Tunnel with 10 lines of code</title>
      <dc:creator>Ali Naqvi</dc:creator>
      <pubDate>Tue, 27 Dec 2022 12:21:54 +0000</pubDate>
      <link>https://dev.to/naqvis/pipy-proxy-creating-http-tunnel-with-10-lines-of-code-2d62</link>
      <guid>https://dev.to/naqvis/pipy-proxy-creating-http-tunnel-with-10-lines-of-code-2d62</guid>
      <description>&lt;p&gt;&lt;strong&gt;Pipy&lt;/strong&gt; is an &lt;a href="https://github.com/flomesh-io/pipy" rel="noopener noreferrer"&gt;open-source&lt;/a&gt;, lightweight, high-performance, modular, programmable, cloud-native network stream processor that is ideal for a variety of use cases ranging from (but not limited to) edge routers, load balancers &amp;amp; proxy solutions, API gateways, static HTTP servers, service mesh sidecars, and other applications. Previously we have covered several use cases, and in this blog post will continue our learning of Pipy by implementing an &lt;strong&gt;HTTP Tunnel&lt;/strong&gt; functionality by only using the &lt;strong&gt;PipyJS&lt;/strong&gt; scripting language.&lt;/p&gt;

&lt;p&gt;HTTP tunneling is a technique used to transmit data over the internet through a network that does not support the desired data transfer protocol. It involves encapsulating the data in a way that allows it to be transmitted over the internet using the HTTP protocol, which is widely supported by web servers and clients.&lt;/p&gt;

&lt;p&gt;There are several reasons why HTTP tunneling might be used. For example, it can be used to bypass firewalls or other network security measures that block certain types of data transfer. It can also be used to access resources on a private network from a remote location or to connect to a network that uses a proprietary protocol not supported by the client.&lt;/p&gt;

&lt;p&gt;To use HTTP tunneling, a client sends a request to a server using the HTTP protocol, with the desired data included in the request body. The server then sends a response back to the client using the HTTP protocol, with the data included in the response body. This allows the data to be transmitted over the internet using the HTTP protocol, bypassing any restrictions or limitations on the network.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuinq2lbxv9p30dnvi403.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuinq2lbxv9p30dnvi403.png" alt="http-only-network"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Suppose we have two devices communicating with each other using a private protocol based on TCP, and the firewall only allows HTTP communication. The server is listening on an internal IP and port 8081. Here we use Pipy to simulate a TCP server that responds with "Hi, TCP!" (mimicking the private protocol) when it receives a request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;pipy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;127.0.0.1:8081&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replaceData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hi, TCP!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we need a proxy on the DMZ side to provide HTTP tunneling. The client establishes an HTTP connection with the proxy (using the &lt;a href="https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_methods" rel="noopener noreferrer"&gt;HTTP CONNECT&lt;/a&gt; method). When the connection is successful, the proxy establishes a connection with the destination server as requested by the client, connecting the client and server. The proxy then forwards the TCP stream sent by the client to the server and sends the server's response back to the client.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fph12h8lw76d8waec5rpa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fph12h8lw76d8waec5rpa.png" alt="http-tunnel"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  PipyJS script
&lt;/h2&gt;

&lt;p&gt;The scripting part is simple. We have a proxy listening on port 80 that checks if the request header is an &lt;code&gt;HTTP CONNECT&lt;/code&gt; request. If it is, the proxy retrieves the address and port of the destination server from the path in the request header and establishes a connection with the destination server. If it is not an HTTP CONNECT request, it is treated as a regular HTTP request and we return a &lt;code&gt;404 Not Found!&lt;/code&gt; here without implementing it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;pipy&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;_isTunnel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;_target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="c1"&gt;//http tunnel&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;demuxHTTP&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handleMessageStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CONNECT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_isTunnel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;branch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;_isTunnel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;$&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;acceptHTTPTunnel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nx"&gt;_target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;$&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;_target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="c1"&gt;//common HTTP request&lt;/span&gt;
      &lt;span class="nx"&gt;$&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replaceMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Not Found!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we have a special filter called &lt;a href="https://flomesh.io/pipy/docs/en/reference/api/Configuration/acceptHTTPTunnel" rel="noopener noreferrer"&gt;&lt;code&gt;acceptHTTPTunnel&lt;/code&gt; Filter&lt;/a&gt; that implements HTTP tunneling on the server side (there is another filter called &lt;a href="https://flomesh.io/pipy/docs/en/reference/api/Configuration/connectHTTPTunnel" rel="noopener noreferrer"&gt;&lt;code&gt;connectHTTPTunnel&lt;/code&gt; Filter&lt;/a&gt; on the client side, which we will talk about later). It redirects the TCP stream after the &lt;code&gt;HTTP CONNECT&lt;/code&gt; to a child pipeline (&lt;a href="https://flomesh.io/pipy/docs/en/reference/api/Configuration/to" rel="noopener noreferrer"&gt;&lt;code&gt;to&lt;/code&gt; filter&lt;/a&gt; in the above code).&lt;/p&gt;

&lt;p&gt;Compared to a regular HTTP proxy, there is only the additional &lt;code&gt;acceptHTTPTunnel&lt;/code&gt; filter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;Our proxy and server are running on host &lt;code&gt;192.168.1.110&lt;/code&gt;, and the client &lt;code&gt;curl&lt;/code&gt; is running on host &lt;code&gt;192.168.1.11&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nt"&gt;-x&lt;/span&gt; http://192.168.1.110:80 telnet://127.0.0.1:8081
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;curl&lt;/code&gt; uses the &lt;code&gt;-x&lt;/code&gt; (&lt;code&gt;--proxy&lt;/code&gt;) option to specify the proxy server and the &lt;code&gt;-p&lt;/code&gt; (&lt;code&gt;--proxytunnel&lt;/code&gt;) option to use the proxy HTTP tunnel.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What could be done next?
&lt;/h2&gt;

&lt;p&gt;This time, our client &lt;code&gt;curl&lt;/code&gt; happens to support using HTTP tunnels. What if the client doesn't support it? That's where &lt;code&gt;connectHTTPTunnel&lt;/code&gt;, which we mentioned earlier, comes in. This filter provides HTTP tunneling functionality on the client side: first, it sends an &lt;code&gt;HTTP CONNECT&lt;/code&gt; request to establish the tunnel, then it sends the TCP stream through the tunnel, as shown in the following figure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkw27nqbwyi641cn48sok.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkw27nqbwyi641cn48sok.png" alt="double-proxy-http-tunnel"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Interested readers can practice their PipyJS skills by trying to implement this and let us know by posting comments. &lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;We used about 10 lines of code to add tunneling capabilities to an HTTP proxy. This article briefly introduced the implementation of tunneling, but the function of tunneling is not just to solve connectivity problems. High-level HTTP tunnels can also provide features that lower-level protocols cannot, such as various security authentications to enhance security.&lt;/p&gt;

&lt;p&gt;The egress gateway in the service mesh &lt;a href="https://flomesh.io/osm-edge" rel="noopener noreferrer"&gt;osm-edge&lt;/a&gt; provides HTTP tunneling functionality, using an HTTP tunnel to provide governance functions at the high-level protocol between the sidecar and the egress gateway. We will explain this in more detail when we introduce the egress gateway.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>pipy</category>
      <category>proxy</category>
    </item>
    <item>
      <title>Writing a DNS proxy with Pipy</title>
      <dc:creator>Ali Naqvi</dc:creator>
      <pubDate>Mon, 19 Dec 2022 13:22:11 +0000</pubDate>
      <link>https://dev.to/naqvis/writing-a-dns-proxy-with-pipy-39j6</link>
      <guid>https://dev.to/naqvis/writing-a-dns-proxy-with-pipy-39j6</guid>
      <description>&lt;p&gt;&lt;a href="https://flomesh.io/pipy" rel="noopener noreferrer"&gt;Pipy&lt;/a&gt; is a programmable proxy that has previously been used for TCP/HTTP proxy, MQTT proxy, Dubbo proxy, Redis proxy, and Thrift proxy. Recently we were asked if Pipy can be used to program a DNS proxy? and our answer was super simple yes, and via this post we will demonstrate how Pipy can help you build DNS proxy with simple scripting knowledge.&lt;/p&gt;

&lt;p&gt;By reading this article, you will learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Basic introduction to DNS and the process of DNS handling&lt;/li&gt;
&lt;li&gt;Implementation of a DNS proxy using coding&lt;/li&gt;
&lt;li&gt;Adding intelligent route resolution functionality to the proxy&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  DNS Introduction
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;The Domain Name System (DNS) is a hierarchical and distributed naming system for computers, services, and other resources in the Internet or other Internet Protocol (IP) networks. It associates various information with domain names assigned to each of the associated entities. Most prominently, it translates readily memorized domain names to the numerical IP addresses needed for locating and identifying computer services and devices with the underlying network protocols.[1] The Domain Name System has been an essential component of the functionality of the Internet since 1985. &lt;/p&gt;

&lt;p&gt;-- excerpt from &lt;a href="https://en.wikipedia.org/wiki/Domain_Name_System" rel="noopener noreferrer"&gt;Wikipedia&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Falc1vguo56zxjhbfn7vk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Falc1vguo56zxjhbfn7vk.png" alt="dns procedure" width="682" height="326"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Simplified version of the DNS processing flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A DNS client (such as a browser, application or device) sends a query request for the domain name &lt;code&gt;example.com&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The DNS resolver receives the request, queries the local cache, and returns the local record if it is available and has not expired.&lt;/li&gt;
&lt;li&gt;If the local cache is not hit, the DNS resolver will start at the DNS root server and work its way down, starting with the Top Level Domain (TLD) DNS server (in this case &lt;code&gt;.com&lt;/code&gt;) and working its way down to the server that can resolve &lt;code&gt;example.com&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;The server that can resolve &lt;code&gt;example.com&lt;/code&gt; becomes the Authoritative DNS name server, which the resolver accesses and receives the IP address and other related information, and then returns it to the client. Resolution is completed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;During past or recently you might have encounter the need to change DNS records to update the domain name's true direction, such as switching running environments, traffic interception, and DNS is also often used as one of the means of service discovery. Usually, the DNS server is either maintained by the service provider or the company's internal network team, which makes it inconvenient to modify DNS resolution records. Moreover, due to the cache design of DNS, each record has a TTL setting, which will not be updated again before the cache expires. Both a long and a short TTL are not appropriate.&lt;/p&gt;

&lt;p&gt;The introduction of DNS proxies can solve this problem while enabling more functionality.&lt;/p&gt;

&lt;p&gt;Next, we will demonstrate how to use Pipy to implement a DNS proxy (more accurately, a combination of a proxy and a server) that returns DNS query requests from custom records. At the same time, we will also add a feature to return different DNS records based on the client IP address to achieve intelligent route resolution. The scripts used in the demonstration can be downloaded from &lt;a href="https://github.com/flomesh-io/pipy-demos/tree/main/pipy-dns-demo" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F70a99z1rmsr8rro10tsb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F70a99z1rmsr8rro10tsb.png" alt="dns-proxy" width="640" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As shown in the above figure, the DNS proxy provides similar functionality to the original resolver. However, when the cache expires or fails to hit, it will query custom resolution records. If there is a custom record, it will return the custom record; if not, it will query the DNS server as per the original process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;Before starting, let's use the wireshark network packet capture to look at the format of DNS messages. The format of DNS query and response messages is the same and includes the following four parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Header: Contains the ID, flag, number of query entries, number of response entries, number of authority resource entries, and number of additional resource entries.&lt;/li&gt;
&lt;li&gt;Flag part: This part identifies the message type, whether the name server is authoritative, whether the query is recursive, whether the request has been truncated, and the status.&lt;/li&gt;
&lt;li&gt;Request part: Contains the domain name being/needing to be resolved and the record type (A, AAAA, MX, TXT, etc.). Each label in the domain name is prefixed with its length.&lt;/li&gt;
&lt;li&gt;Response part: Contains resource records for the queried domain name.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faceq59mf83kzwd53woap.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faceq59mf83kzwd53woap.png" alt="dns-message-format" width="800" height="675"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In previous announcement &lt;a href="https://dev.to/flomesh/pipy-0700-is-released-13mj"&gt;Pipy 0.70.0 is released!&lt;/a&gt;, it was highlighted that Pipy 0.70.0 comes bundled with &lt;code&gt;DNS&lt;/code&gt; encoder/decoder. And we will be using Pipy to decode the DNS packet into above mentioned parts.&lt;/p&gt;

&lt;h3&gt;
  
  
  PipyJS Code
&lt;/h3&gt;

&lt;p&gt;The script logic is very simple. For ease of reading, it is divided into several modules according to function, and implements the parsing of several common types of records, including A, AAAA, CNAME, MX, TXT, and NS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── cache.js #Cache
├── main.js #main entry script
├── records.js #Logic for customizing records
├── records.json #Custom record content
├── smart-line.js #Logic for smart line parsing
└── smart-line.json #Configuration of smart-line parsing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is a part of the core code of &lt;a href="https://github.com/flomesh-io/pipy-demos/blob/main/pipy-dns-demo/main.js" rel="noopener noreferrer"&gt;&lt;code&gt;main.js&lt;/code&gt;&lt;/a&gt; with annotations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First, use DNS.decode() to decode the data stream&lt;/li&gt;
&lt;li&gt;Then find the queried domain name and type from the result&lt;/li&gt;
&lt;li&gt;Query the cache&lt;/li&gt;
&lt;li&gt;If the cache fails to hit, query custom records&lt;/li&gt;
&lt;li&gt;Intelligent route resolution&lt;/li&gt;
&lt;li&gt;Return the response&lt;/li&gt;
&lt;li&gt;If 3 and 4 are both unsuccessful, it will request the upstream DNS server and then cache and return the response.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;udp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replaceMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;record&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;DNS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;//1&lt;/span&gt;
      &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="p"&gt;?.[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]?.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="p"&gt;?.[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]?.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="c1"&gt;//2&lt;/span&gt;
        &lt;span class="nx"&gt;record&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getDNS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;//3&lt;/span&gt;
        &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;//4&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nx"&gt;record&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;record&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__inbound&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;remoteAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;record&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;//5&lt;/span&gt;
        &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;qr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ra&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aa&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;question&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;
        &lt;span class="p"&gt;}],&lt;/span&gt;
        &lt;span class="nx"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;deny&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rcode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REFUSED&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;answer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rr&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DNS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;//6&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;_forward&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;msg&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)()&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;branch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;_forward&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;upstreamDNSServer&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:53`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;udp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="c1"&gt;//7&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handleMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;DNS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="p"&gt;?.[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]?.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="p"&gt;?.[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]?.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
          &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;rcode&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nf"&gt;setDNS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;rr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rcode&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REFUSED&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;deny&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
              &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;)()&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nx"&gt;$&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Custom Record
&lt;/h3&gt;

&lt;p&gt;Below is the content of the custom record, which is similar to the format of a DNS response. In order to support intelligent route resolution, some records have added label information: &lt;code&gt;"labels"&lt;/code&gt;: &lt;code&gt;["line1"]&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"A"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ttl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"rdata"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"192.168.139.10"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"labels"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"line1"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"A"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ttl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"rdata"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"192.168.139.11"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"labels"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"line2"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MX"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ttl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"rdata"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"preference"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"exchange"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mail2.example.com"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"TXT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ttl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"rdata"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"hi.pipy!"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NS"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ttl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"rdata"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ns1.example.com"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Intelligent Route Resolution
&lt;/h3&gt;

&lt;p&gt;The logic of intelligent route resolution is relatively simple. Set different route labels for different IP ranges, and return only records with the corresponding label in the response if the record has a label.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"line1"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"192.168.1.110/32"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"line2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"127.0.0.1/32"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;Start the proxy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;pipy main.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As shown in the above configuration, &lt;code&gt;127.0.0.1&lt;/code&gt; is the address of the local loopback network card, and &lt;code&gt;192.168.1.110&lt;/code&gt; is the address of the local Ethernet network card, and the proxy listens on port &lt;code&gt;5300&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;First, access the proxy using &lt;code&gt;localhost&lt;/code&gt;, so that the client IP address obtained by the proxy is &lt;code&gt;127.0.0.1&lt;/code&gt;. When querying the records for example.com, it directly returns the record &lt;code&gt;192.168.139.11&lt;/code&gt; corresponding to the route &lt;code&gt;line2&lt;/code&gt; of the local address.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;dig @localhost &lt;span class="nt"&gt;-p&lt;/span&gt; 5300 a example.com

&lt;span class="p"&gt;;&lt;/span&gt; &amp;lt;&amp;lt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; DiG 9.10.6 &amp;lt;&amp;lt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; @localhost &lt;span class="nt"&gt;-p&lt;/span&gt; 5300 a example.com
&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;2 servers found&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;;;&lt;/span&gt; global options: +cmd
&lt;span class="p"&gt;;;&lt;/span&gt; Got answer:
&lt;span class="p"&gt;;;&lt;/span&gt; -&amp;gt;&amp;gt;HEADER&lt;span class="o"&gt;&amp;lt;&amp;lt;-&lt;/span&gt; &lt;span class="no"&gt;opcode&lt;/span&gt;&lt;span class="sh"&gt;: QUERY, status: NOERROR, id: 25868
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;example.com.           IN  A

;; ANSWER SECTION:
example.com.        60  IN  A   192.168.139.11

;; Query time: 0 msec
;; SERVER: 127.0.0.1#5300(127.0.0.1)
;; WHEN: Tue Dec 13 21:09:38 CST 2022
;; MSG SIZE  rcvd: 56
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then access the proxy using &lt;code&gt;192.168.1.110&lt;/code&gt;, this time the client's address is &lt;code&gt;192.168.1.110&lt;/code&gt;, and the record returned is &lt;code&gt;192.168.139.10&lt;/code&gt; of route &lt;code&gt;line1&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;dig @192.168.1.110 &lt;span class="nt"&gt;-p&lt;/span&gt; 5300 a example.com

&lt;span class="p"&gt;;&lt;/span&gt; &amp;lt;&amp;lt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; DiG 9.10.6 &amp;lt;&amp;lt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; @192.168.1.110 &lt;span class="nt"&gt;-p&lt;/span&gt; 5300 a example.com
&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;1 server found&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;;;&lt;/span&gt; global options: +cmd
&lt;span class="p"&gt;;;&lt;/span&gt; Got answer:
&lt;span class="p"&gt;;;&lt;/span&gt; -&amp;gt;&amp;gt;HEADER&lt;span class="o"&gt;&amp;lt;&amp;lt;-&lt;/span&gt; &lt;span class="no"&gt;opcode&lt;/span&gt;&lt;span class="sh"&gt;: QUERY, status: NOERROR, id: 54165
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;example.com.           IN  A

;; ANSWER SECTION:
example.com.        60  IN  A   192.168.139.10

;; Query time: 0 msec
;; SERVER: 192.168.1.110#5300(192.168.1.110)
;; WHEN: Tue Dec 13 21:12:37 CST 2022
;; MSG SIZE  rcvd: 56
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If I access from another machine, because no route is set, it will return two records.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;dig @192.168.1.110 &lt;span class="nt"&gt;-p&lt;/span&gt; 5300 a example.com

&lt;span class="p"&gt;;&lt;/span&gt; &amp;lt;&amp;lt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; DiG 9.16.1-Ubuntu &amp;lt;&amp;lt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; @192.168.1.110 &lt;span class="nt"&gt;-p&lt;/span&gt; 5300 a example.com
&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;1 server found&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;;;&lt;/span&gt; global options: +cmd
&lt;span class="p"&gt;;;&lt;/span&gt; Got answer:
&lt;span class="p"&gt;;;&lt;/span&gt; -&amp;gt;&amp;gt;HEADER&lt;span class="o"&gt;&amp;lt;&amp;lt;-&lt;/span&gt; &lt;span class="no"&gt;opcode&lt;/span&gt;&lt;span class="sh"&gt;: QUERY, status: NOERROR, id: 64873
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;example.com.           IN  A

;; ANSWER SECTION:
example.com.        60  IN  A   192.168.139.10
example.com.        60  IN  A   192.168.139.11

;; Query time: 0 msec
;; SERVER: 192.168.1.110#5300(192.168.1.110)
;; WHEN: Tue Dec 13 13:15:24 UTC 2022
;; MSG SIZE  rcvd: 83
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because only the route of the &lt;strong&gt;A record&lt;/strong&gt; is set, other types of records are not affected.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ $dig&lt;/span&gt; @localhost &lt;span class="nt"&gt;-p&lt;/span&gt; 5300 mx example.com

&lt;span class="p"&gt;;&lt;/span&gt; &amp;lt;&amp;lt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; DiG 9.10.6 &amp;lt;&amp;lt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; @localhost &lt;span class="nt"&gt;-p&lt;/span&gt; 5300 mx example.com
&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;2 servers found&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;;;&lt;/span&gt; global options: +cmd
&lt;span class="p"&gt;;;&lt;/span&gt; Got answer:
&lt;span class="p"&gt;;;&lt;/span&gt; -&amp;gt;&amp;gt;HEADER&lt;span class="o"&gt;&amp;lt;&amp;lt;-&lt;/span&gt; &lt;span class="no"&gt;opcode&lt;/span&gt;&lt;span class="sh"&gt;: QUERY, status: NOERROR, id: 33492
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;example.com.           IN  MX

;; ANSWER SECTION:
example.com.        600 IN  MX  10 mail1.example.com.
example.com.        600 IN  MX  10 mail2.example.com.

;; Query time: 0 msec
;; SERVER: 127.0.0.1#5300(127.0.0.1)
;; WHEN: Tue Dec 13 21:18:27 CST 2022
;; MSG SIZE  rcvd: 117
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Going Further
&lt;/h2&gt;

&lt;p&gt;Those who have some understanding of Pipy may know the &lt;a href="https://flomesh.io/pipy/docs/en/operating/repo/0-intro" rel="noopener noreferrer"&gt;Repo mode&lt;/a&gt;, and those who are interested can refer to previously published articles on &lt;a href="https://blog.flomesh.io" rel="noopener noreferrer"&gt;Pipy Blog&lt;/a&gt; and &lt;a href="https://flomesh.io/pipy/docs" rel="noopener noreferrer"&gt;Pipy Reference Documentation&lt;/a&gt;. Using the Repo mode, all proxies (or DNS servers) on the host real-timely obtain updates of custom records from the Repo and refresh the cache.&lt;/p&gt;

&lt;p&gt;Due to space constraints, it will not be discussed in depth here. Those interested can give it a try to implement and learn Pipy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;With this, Pipy has added another type of proxy. DNS is everywhere, and it is precisely because of this that problems can be solved at the DNS level.&lt;/p&gt;

&lt;p&gt;If you have been following us and might have gone through previous &lt;strong&gt;Multi-cluster&lt;/strong&gt; related blog posts, and in &lt;a href="https://dev.to/naqvis/kubernetes-multi-cluster-communication-with-flomesh-service-mesh-part-2-1kbj"&gt;Kubernetes: Multi-cluster communication with Flomesh Service Mesh (Demo)&lt;/a&gt; we demonstrated cross cluster service communication, and there we easily scheduled request traffic to other clusters for processing. In this demo we demonstrated how to access service located on another Kubernetes cluster, but to caller it was transparently forwarded to respective cluster, how was that done?&lt;/p&gt;

&lt;p&gt;Here, a small trick was used. When setting iptables rules to intercept traffic in the initialization container of the mesh, DNS traffic was also intercepted by the DNS proxy implemented by the sidecar (listening on &lt;code&gt;127.0.0.153:5300&lt;/code&gt;), and business traffic was intercepted through custom DNS records.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fprbr1a8vaifeh8ijp8of.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fprbr1a8vaifeh8ijp8of.png" alt="fsm-multi-cluster" width="800" height="524"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Kubernetes: Cross-cluster traffic scheduling - Access control</title>
      <dc:creator>Ali Naqvi</dc:creator>
      <pubDate>Sun, 11 Dec 2022 13:14:40 +0000</pubDate>
      <link>https://dev.to/naqvis/kubernetes-cross-cluster-traffic-scheduling-access-control-40k</link>
      <guid>https://dev.to/naqvis/kubernetes-cross-cluster-traffic-scheduling-access-control-40k</guid>
      <description>&lt;p&gt;Flomesh open source service mesh &lt;a href="https://github.com/flomesh-io/osm-edge"&gt;osm-edge&lt;/a&gt; is based on an implementation of the SMI (Service Mesh Interface) standard. SMI defines specifications for traffic identification, access control, telemetry, and management. In the previous article &lt;a href="https://dev.to/naqvis/kubernetes-multi-cluster-communication-with-flomesh-service-mesh-123f"&gt;Kubernetes: Multi-cluster communication with Flomesh Service Mesh&lt;/a&gt; we covered the background, motivations, and goals of Kubernetes multi-cluster and part 2 &lt;a href="https://dev.to/naqvis/kubernetes-multi-cluster-communication-with-flomesh-service-mesh-part-2-1kbj"&gt;Kubernetes: Multi-cluster communication with Flomesh Service Mesh (Demo)&lt;/a&gt; we demonstrated a detailed demo of how to use FSM in a multi-cluster environment and how to schedule policies for traffics.&lt;/p&gt;

&lt;p&gt;This article will expand on the knowledge we covered before and demonstrate how to configure and enable cross-cluster access control based on SMI. With osm-edge support for multi-clusters, users can define and enforce fine-grained access policies for services running across multiple Kubernetes clusters. This allows users to easily and securely manage access to services and resources, ensuring that only authorized users and applications have access to the appropriate services and resources.&lt;/p&gt;

&lt;p&gt;Before we start, let's review the &lt;a href="https://github.com/servicemeshinterface/smi-spec/blob/main/apis/traffic-access/v1alpha3/traffic-access.md"&gt;SMI Access Control Specification&lt;/a&gt;. There are two forms of &lt;a href="https://osm-edge-docs.flomesh.io/docs/getting_started/traffic_policies/"&gt;traffic policies in osm-edge&lt;/a&gt;: &lt;strong&gt;Permissive Mode&lt;/strong&gt; and &lt;strong&gt;Traffic Policy Mode&lt;/strong&gt;. The former allows services in the mesh to access each other, while the latter requires the provision of the appropriate traffic policy to be accessible.&lt;/p&gt;

&lt;h2&gt;
  
  
  SMI Access Control Policy
&lt;/h2&gt;

&lt;p&gt;In traffic policy mode, SMI defines &lt;code&gt;ServiceAccount&lt;/code&gt;-based access control through the Kubernetes Custom Resource Definition(CRD) &lt;code&gt;TrafficTarget&lt;/code&gt;, which defines traffic sources (&lt;code&gt;sources&lt;/code&gt;), destinations (&lt;code&gt;destinations&lt;/code&gt;), and rules (&lt;code&gt;rules&lt;/code&gt;). What is expressed is that applications that use the &lt;code&gt;ServiceAccount&lt;/code&gt; specified in &lt;code&gt;sources&lt;/code&gt; can access applications that have the &lt;code&gt;ServiceAccount&lt;/code&gt; specified in &lt;code&gt;destinations&lt;/code&gt;, and the accessible traffic is specified by &lt;code&gt;rules&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example, the following example represents a load running with &lt;code&gt;ServiceAccount&lt;/code&gt; &lt;code&gt;promethues&lt;/code&gt; sending a &lt;code&gt;GET&lt;/code&gt; request to the &lt;code&gt;/metrics&lt;/code&gt; endpoint of a load running with &lt;code&gt;ServiceAccount&lt;/code&gt; &lt;code&gt;service-a&lt;/code&gt;. The &lt;code&gt;HTTPRouteGroup&lt;/code&gt; defines the identity of the traffic: i.e. the &lt;code&gt;GET&lt;/code&gt; request to access the endpoint &lt;code&gt;/metrics&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HTTPRouteGroup&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;the-routes&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;matches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;metrics&lt;/span&gt;
    &lt;span class="na"&gt;pathRegex&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/metrics"&lt;/span&gt;
    &lt;span class="na"&gt;methods&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;GET&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TrafficTarget&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;path-specific&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ServiceAccount&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service-a&lt;/span&gt;
    &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HTTPRouteGroup&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;the-routes&lt;/span&gt;
    &lt;span class="na"&gt;matches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;metrics&lt;/span&gt;
  &lt;span class="na"&gt;sources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ServiceAccount&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;prometheus&lt;/span&gt;
    &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So how does access control perform in a multi-cluster?&lt;/p&gt;

&lt;h3&gt;
  
  
  FSM's &lt;code&gt;ServiceExport&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;FSM's &lt;code&gt;ServiceExport&lt;/code&gt; is used to export services to other clusters, which is the process of service registration. The field &lt;code&gt;spec.serviceAccountName&lt;/code&gt; of &lt;code&gt;ServiceExport&lt;/code&gt; can be used to specify the &lt;code&gt;ServiceAccount&lt;/code&gt; used for the service load.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flomesh.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ServiceExport&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;httpbin&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;httpbin&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;serviceAccountName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;portNumber&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
      &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/cluster-1/httpbin-mesh"&lt;/span&gt;
      &lt;span class="na"&gt;pathType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Prefix&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we start the demonstration based on the last environment. Those who haven't read the previous article can refer to the &lt;a href="https://medium.com/flomesh/kubernetes-multi-cluster-communication-with-flomesh-service-mesh-demo-d06ef8f69822"&gt;previous article&lt;/a&gt; to set up the demo environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy the application
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VzUcBBMk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ddjxksof46we4d2hkw74.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VzUcBBMk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ddjxksof46we4d2hkw74.png" alt="mcs-access-control" width="880" height="530"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploy the sample application
&lt;/h3&gt;

&lt;p&gt;Deploy the &lt;code&gt;httpbin&lt;/code&gt; application under the &lt;code&gt;httpbin&lt;/code&gt; namespace (managed by the mesh, which injects sidecar) in clusters &lt;code&gt;cluster-1&lt;/code&gt; and &lt;code&gt;cluster-3&lt;/code&gt;. Here we specify &lt;code&gt;ServiceAccount&lt;/code&gt; as &lt;code&gt;httpbin&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;httpbin
&lt;span class="k"&gt;for &lt;/span&gt;CLUSTER_NAME &lt;span class="k"&gt;in &lt;/span&gt;cluster-1 cluster-3
&lt;span class="k"&gt;do
  &lt;/span&gt;kubectx k3d-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
  kubectl create namespace &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
  osm namespace add &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
  kubectl apply &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
apiVersion: v1
kind: ServiceAccount
metadata:
  name: httpbin
---  
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpbin
  labels:
    app: pipy
spec:
  replicas: 1
  selector:
    matchLabels:
      app: pipy
  template:
    metadata:
      labels:
        app: pipy
    spec:
      serviceAccountName: httpbin
      containers:
        - name: pipy
          image: flomesh/pipy:latest
          ports:
            - containerPort: 8080
          command:
            - pipy
            - -e
            - |
              pipy()
              .listen(8080)
              .serveHTTP(new Message('Hi, I am from &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt; and controlled by mesh!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;'))
---
apiVersion: v1
kind: Service
metadata:
  name: httpbin
spec:
  ports:
    - port: 8080
      targetPort: 8080
      protocol: TCP
  selector:
    app: pipy
---
apiVersion: v1
kind: Service
metadata:
  name: httpbin-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;
spec:
  ports:
    - port: 8080
      targetPort: 8080
      protocol: TCP
  selector:
    app: pipy
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;  &lt;span class="nb"&gt;sleep &lt;/span&gt;3
  kubectl &lt;span class="nb"&gt;wait&lt;/span&gt; &lt;span class="nt"&gt;--for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;condition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ready pod &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;--all&lt;/span&gt; &lt;span class="nt"&gt;--timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;60s
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deploy the &lt;code&gt;httpbin&lt;/code&gt; application under the &lt;code&gt;cluster-2&lt;/code&gt; namespace &lt;code&gt;httpbin&lt;/code&gt;, but do not specify a &lt;code&gt;ServiceAccount&lt;/code&gt; and use the default &lt;code&gt;ServiceAccount&lt;/code&gt; &lt;code&gt;default&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;httpbin
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;cluster-2

kubectx k3d-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
kubectl create namespace &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
osm namespace add &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
kubectl apply &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpbin
  labels:
    app: pipy
spec:
  replicas: 1
  selector:
    matchLabels:
      app: pipy
  template:
    metadata:
      labels:
        app: pipy
    spec:
      containers:
        - name: pipy
          image: flomesh/pipy:latest
          ports:
            - containerPort: 8080
          command:
            - pipy
            - -e
            - |
              pipy()
              .listen(8080)
              .serveHTTP(new Message('Hi, I am from &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;! and controlled by mesh!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;'))
---
apiVersion: v1
kind: Service
metadata:
  name: httpbin
spec:
  ports:
    - port: 8080
      targetPort: 8080
      protocol: TCP
  selector:
    app: pipy
---
apiVersion: v1
kind: Service
metadata:
  name: httpbin-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;
spec:
  ports:
    - port: 8080
      targetPort: 8080
      protocol: TCP
  selector:
    app: pipy
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="nb"&gt;sleep &lt;/span&gt;3
kubectl &lt;span class="nb"&gt;wait&lt;/span&gt; &lt;span class="nt"&gt;--for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;condition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ready pod &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;--all&lt;/span&gt; &lt;span class="nt"&gt;--timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;60s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deploy the &lt;code&gt;curl&lt;/code&gt; application under the namespace &lt;code&gt;curl&lt;/code&gt; in cluster &lt;code&gt;cluster-2&lt;/code&gt;, which is managed by the mesh, and the injected sidecar will be fully traffic dispatched across the cluster. Specify here to use &lt;code&gt;ServiceAccout&lt;/code&gt; &lt;code&gt;curl&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;curl
kubectx k3d-cluster-2
kubectl create namespace &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
osm namespace add &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
kubectl apply &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
apiVersion: v1
kind: ServiceAccount
metadata:
  name: curl
---
apiVersion: v1
kind: Service
metadata:
  name: curl
  labels:
    app: curl
    service: curl
spec:
  ports:
    - name: http
      port: 80
  selector:
    app: curl
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: curl
spec:
  replicas: 1
  selector:
    matchLabels:
      app: curl
  template:
    metadata:
      labels:
        app: curl
    spec:
      serviceAccountName: curl
      containers:
      - image: curlimages/curl
        imagePullPolicy: IfNotPresent
        name: curl
        command: ["sleep", "365d"]
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="nb"&gt;sleep &lt;/span&gt;3
kubectl &lt;span class="nb"&gt;wait&lt;/span&gt; &lt;span class="nt"&gt;--for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;condition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ready pod &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;--all&lt;/span&gt; &lt;span class="nt"&gt;--timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;60s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Export service
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE_MESH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;httpbin
&lt;span class="k"&gt;for &lt;/span&gt;CLUSTER_NAME &lt;span class="k"&gt;in &lt;/span&gt;cluster-1 cluster-3
&lt;span class="k"&gt;do
  &lt;/span&gt;kubectx k3d-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
  kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
apiVersion: flomesh.io/v1alpha1
kind: ServiceExport
metadata:
  namespace: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE_MESH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;
  name: httpbin
spec:
  serviceAccountName: "httpbin"
  rules:
    - portNumber: 8080
      path: "/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;/httpbin-mesh"
      pathType: Prefix
---
apiVersion: flomesh.io/v1alpha1
kind: ServiceExport
metadata:
  namespace: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE_MESH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;
  name: httpbin-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;
spec:
  serviceAccountName: "httpbin"
  rules:
    - portNumber: 8080
      path: "/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;/httpbin-mesh-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"
      pathType: Prefix
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;span class="nb"&gt;sleep &lt;/span&gt;1
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Test
&lt;/h3&gt;

&lt;p&gt;We switch back to the cluster &lt;code&gt;cluster-2&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectx k3d-cluster-2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The default route type is &lt;code&gt;Locality&lt;/code&gt; and we need to create an &lt;code&gt;ActiveActive&lt;/code&gt; policy to allow requests to be processed using service instances from other clusters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-n&lt;/span&gt; httpbin &lt;span class="nt"&gt;-f&lt;/span&gt;  - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
apiVersion: flomesh.io/v1alpha1
kind: GlobalTrafficPolicy
metadata:
  name: httpbin
spec:
  lbType: ActiveActive
  targets:
    - clusterKey: default/default/default/cluster-1
    - clusterKey: default/default/default/cluster-3
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;curl&lt;/code&gt; application of the &lt;code&gt;cluster-2&lt;/code&gt; cluster, we send a request to &lt;code&gt;httpbin.httpbin&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;curl_client&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get pod &lt;span class="nt"&gt;-n&lt;/span&gt; curl &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;curl &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.items[0].metadata.name}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;curl_client&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; curl &lt;span class="nt"&gt;-c&lt;/span&gt; curl &lt;span class="nt"&gt;--&lt;/span&gt; curl &lt;span class="nt"&gt;-s&lt;/span&gt; http://httpbin.httpbin:8080/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few more requests will see the following response.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Hi, I am from cluster-1 and controlled by mesh!
Hi, I am from cluster-2 and controlled by mesh!
Hi, I am from cluster-3 and controlled by mesh!
Hi, I am from cluster-1 and controlled by mesh!
Hi, I am from cluster-2 and controlled by mesh!
Hi, I am from cluster-3 and controlled by mesh!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Adjusting the traffic policy mode
&lt;/h3&gt;

&lt;p&gt;Let's adjust the traffic policy mode of cluster &lt;code&gt;cluster-2&lt;/code&gt; so that the traffic policy can be applied.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectx k3d-cluster-2
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;osm_namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;osm-system
kubectl patch meshconfig osm-mesh-config &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$osm_namespace&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s1"&gt;'{"spec":{"traffic":{"enablePermissiveTrafficPolicyMode":false}}}'&lt;/span&gt; &lt;span class="nt"&gt;--type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;merge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, if you try to send the request again, you will find that the request fails. This is because in traffic policy mode, inter-application access is prohibited if no policy is configured.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;curl_client&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; curl &lt;span class="nt"&gt;-c&lt;/span&gt; curl &lt;span class="nt"&gt;--&lt;/span&gt; curl &lt;span class="nt"&gt;-s&lt;/span&gt; http://httpbin.httpbin:8080/
&lt;span class="nb"&gt;command &lt;/span&gt;terminated with &lt;span class="nb"&gt;exit &lt;/span&gt;code 52
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Application Access Control Policy
&lt;/h3&gt;

&lt;p&gt;The access control policy of SMI is based on &lt;code&gt;ServiceAccount&lt;/code&gt; as mentioned at the beginning of the article, that's why our deployed &lt;code&gt;httpbin&lt;/code&gt; service uses different &lt;code&gt;ServiceAccount&lt;/code&gt; in cluster &lt;code&gt;cluster-1&lt;/code&gt;, &lt;code&gt;cluster-3&lt;/code&gt;, and cluster &lt;code&gt;cluster-2&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cluster-1：&lt;code&gt;httpbin&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;cluster-2：&lt;code&gt;default&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;cluster-3：&lt;code&gt;httpbin&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next, we will set different access control policies &lt;code&gt;TrafficTarget&lt;/code&gt; for in-cluster and out-of-cluster services, differentiated by the &lt;code&gt;ServiceAccount&lt;/code&gt; of the target load in &lt;code&gt;TrafficTarget&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZTVujkat--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9cg6q7k3v94tsoruuaaz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZTVujkat--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9cg6q7k3v94tsoruuaaz.png" alt="fsm-multi-cluster-with-policy" width="880" height="627"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Execute the following command to create a traffic policy &lt;code&gt;curl-to-httpbin&lt;/code&gt; that allows &lt;code&gt;curl&lt;/code&gt; to access loads under the namespace &lt;code&gt;httpbin&lt;/code&gt; that uses &lt;code&gt;ServiceAccount&lt;/code&gt; &lt;code&gt;default&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-n&lt;/span&gt; httpbin &lt;span class="nt"&gt;-f&lt;/span&gt; - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
apiVersion: specs.smi-spec.io/v1alpha4
kind: HTTPRouteGroup
metadata:
  name: httpbin-route
spec:
  matches:
  - name: all
    pathRegex: "/"
    methods:
    - GET
---
kind: TrafficTarget
apiVersion: access.smi-spec.io/v1alpha3
metadata:
  name: curl-to-httpbin
spec:
  destination:
    kind: ServiceAccount
    name: default
    namespace: httpbin
  rules:
  - kind: HTTPRouteGroup
    name: httpbin-route
    matches:
    - all
  sources:
  - kind: ServiceAccount
    name: curl
    namespace: curl
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Multiple request attempts are sent and the service of cluster &lt;code&gt;cluster-2&lt;/code&gt; responds, while clusters &lt;code&gt;cluster-1&lt;/code&gt; and &lt;code&gt;cluster-3&lt;/code&gt; will not participate in the service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Hi, I am from cluster-2 and controlled by mesh!
Hi, I am from cluster-2 and controlled by mesh!
Hi, I am from cluster-2 and controlled by mesh!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Execute the following command to check &lt;code&gt;ServiceImports&lt;/code&gt; and you can see that &lt;code&gt;cluster-1&lt;/code&gt; and &lt;code&gt;cluster-3&lt;/code&gt; export services using &lt;code&gt;ServiceAccount&lt;/code&gt; &lt;code&gt;httpbin&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get serviceimports httpbin &lt;span class="nt"&gt;-n&lt;/span&gt; httpbin &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.spec}'&lt;/span&gt; | jq

&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"ports"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;"endpoints"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
        &lt;span class="o"&gt;{&lt;/span&gt;
          &lt;span class="s2"&gt;"clusterKey"&lt;/span&gt;: &lt;span class="s2"&gt;"default/default/default/cluster-1"&lt;/span&gt;,
          &lt;span class="s2"&gt;"target"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"host"&lt;/span&gt;: &lt;span class="s2"&gt;"192.168.1.110"&lt;/span&gt;,
            &lt;span class="s2"&gt;"ip"&lt;/span&gt;: &lt;span class="s2"&gt;"192.168.1.110"&lt;/span&gt;,
            &lt;span class="s2"&gt;"path"&lt;/span&gt;: &lt;span class="s2"&gt;"/cluster-1/httpbin-mesh"&lt;/span&gt;,
            &lt;span class="s2"&gt;"port"&lt;/span&gt;: 81
          &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;,
        &lt;span class="o"&gt;{&lt;/span&gt;
          &lt;span class="s2"&gt;"clusterKey"&lt;/span&gt;: &lt;span class="s2"&gt;"default/default/default/cluster-3"&lt;/span&gt;,
          &lt;span class="s2"&gt;"target"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"host"&lt;/span&gt;: &lt;span class="s2"&gt;"192.168.1.110"&lt;/span&gt;,
            &lt;span class="s2"&gt;"ip"&lt;/span&gt;: &lt;span class="s2"&gt;"192.168.1.110"&lt;/span&gt;,
            &lt;span class="s2"&gt;"path"&lt;/span&gt;: &lt;span class="s2"&gt;"/cluster-3/httpbin-mesh"&lt;/span&gt;,
            &lt;span class="s2"&gt;"port"&lt;/span&gt;: 83
          &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;]&lt;/span&gt;,
      &lt;span class="s2"&gt;"port"&lt;/span&gt;: 8080,
      &lt;span class="s2"&gt;"protocol"&lt;/span&gt;: &lt;span class="s2"&gt;"TCP"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;]&lt;/span&gt;,
  &lt;span class="s2"&gt;"serviceAccountName"&lt;/span&gt;: &lt;span class="s2"&gt;"httpbin"&lt;/span&gt;,
  &lt;span class="s2"&gt;"type"&lt;/span&gt;: &lt;span class="s2"&gt;"ClusterSetIP"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, we create another &lt;code&gt;TrafficTarget&lt;/code&gt; &lt;code&gt;curl-to-ext-httpbin&lt;/code&gt; that allows &lt;code&gt;curl&lt;/code&gt; to access the load using &lt;code&gt;ServiceAccount&lt;/code&gt; &lt;code&gt;httpbin&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-n&lt;/span&gt; httpbin &lt;span class="nt"&gt;-f&lt;/span&gt; - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
kind: TrafficTarget
apiVersion: access.smi-spec.io/v1alpha3
metadata:
  name: curl-to-ext-httpbin
spec:
  destination:
    kind: ServiceAccount
    name: httpbin
    namespace: httpbin
  rules:
  - kind: HTTPRouteGroup
    name: httpbin-route
    matches:
    - all
  sources:
  - kind: ServiceAccount
    name: curl
    namespace: curl
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After applying the policy, test it again and all requests are successful.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Hi, I am from cluster-2 and controlled by mesh!
Hi, I am from cluster-1 and controlled by mesh!
Hi, I am from cluster-3 and controlled by mesh!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Kubernetes multi-cluster service access control is an important feature for users who want to easily and securely manage access to services and resources across multiple Kubernetes clusters. By leveraging this feature, users can easily and securely scale their applications and services across multiple clusters, without having to worry about managing access control policies manually.&lt;/p&gt;

&lt;p&gt;The goal of the MCS (Multi-cluster Service) API implementation is to be able to use services from other clusters as if they were services running inside the same cluster. While there is still a long way to go in the Kubernetes implementation itself, the SMI standard implementation of Service Mesh can be treated as a Service.&lt;/p&gt;

&lt;p&gt;As with access control in this article, SMI traffic splitting can also support multi-cluster services. In the following article, we will introduce traffic splitting for multicluster services.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>multicluster</category>
      <category>flomesh</category>
      <category>servicemesh</category>
    </item>
    <item>
      <title>Kubernetes: Multi-cluster communication with Flomesh Service Mesh (Part 2)</title>
      <dc:creator>Ali Naqvi</dc:creator>
      <pubDate>Fri, 02 Dec 2022 12:43:31 +0000</pubDate>
      <link>https://dev.to/naqvis/kubernetes-multi-cluster-communication-with-flomesh-service-mesh-part-2-1kbj</link>
      <guid>https://dev.to/naqvis/kubernetes-multi-cluster-communication-with-flomesh-service-mesh-part-2-1kbj</guid>
      <description>&lt;p&gt;In &lt;a href="https://dev.to/naqvis/kubernetes-multi-cluster-communication-with-flomesh-service-mesh-123f"&gt;Part 1&lt;/a&gt; we covered the motives, goals, and architecture of &lt;a href="https://github.com/flomesh-io/fsm" rel="noopener noreferrer"&gt;Flomesh Service Mesh&lt;/a&gt; and in this blog post we are going to demonstrate how to use FSM and lightweight SMI-compatible Service Mesh &lt;a href="https://flomesh.io/osm-edge" rel="noopener noreferrer"&gt;osm-edge&lt;/a&gt; to achieve multi-cluster service discovery &amp;amp; communication.&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/naqvis" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F785096%2F9d240025-398f-4c49-a6ae-c474c2f9a958.jpeg" alt="naqvis"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/naqvis/kubernetes-multi-cluster-communication-with-flomesh-service-mesh-123f" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Kubernetes: Multi-cluster communication with Flomesh Service Mesh&lt;/h2&gt;
      &lt;h3&gt;Ali Naqvi ・ Nov 28 '22&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#kubernetes&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#multicluster&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#flomesh&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Demo Architecture
&lt;/h2&gt;

&lt;p&gt;For demonstration purposes we will be creating 4 Kubernetes clusters and high-level architecture will look something like the below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2d2oqfewq1jl1nhnt4ab.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2d2oqfewq1jl1nhnt4ab.png" alt="Demo architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As a convention and for this demo we will be creating a separate stand-alone cluster to serve as a &lt;strong&gt;control plane&lt;/strong&gt; cluster, but that isn't strictly required as a separate cluster and it could be one of any existing cluster.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Demo Pre-requisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;kubectx&lt;/code&gt;: for switching between multiple &lt;code&gt;kubeconfig contexts&lt;/code&gt; (clusters)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;k3d&lt;/code&gt;: for creating multiple &lt;code&gt;k3s&lt;/code&gt; clusters locally using containers&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;helm&lt;/code&gt;: for deploying &lt;code&gt;FSM&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker&lt;/code&gt;: required to run &lt;code&gt;k3d&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Demo clusters &amp;amp; environment setup
&lt;/h3&gt;

&lt;p&gt;In this demo, we will be using &lt;a href="https://k3d.io/" rel="noopener noreferrer"&gt;k3d&lt;/a&gt; a lightweight wrapper to run &lt;a href="https://github.com/rancher/k3s" rel="noopener noreferrer"&gt;k3s&lt;/a&gt; (Rancher Lab’s minimal Kubernetes distribution) in docker, to create 4 separate clusters named &lt;code&gt;control-plane&lt;/code&gt;, &lt;code&gt;cluster-1&lt;/code&gt;, &lt;code&gt;cluster-2&lt;/code&gt;, and &lt;code&gt;cluster-3&lt;/code&gt; respectively.&lt;/p&gt;

&lt;p&gt;We will be using the HOST machine IP address and separate ports during the installation, for us to easily access the individual clusters. My demo host machine IP address is &lt;code&gt;192.168.1.110&lt;/code&gt; (it might be different for your machine).&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;cluster&lt;/th&gt;
&lt;th&gt;cluster ip&lt;/th&gt;
&lt;th&gt;api-server port&lt;/th&gt;
&lt;th&gt;LB external-port&lt;/th&gt;
&lt;th&gt;description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;control-plane&lt;/td&gt;
&lt;td&gt;HOST_IP(192.168.1.110)&lt;/td&gt;
&lt;td&gt;6444&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;control-plane cluster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cluster-1&lt;/td&gt;
&lt;td&gt;HOST_IP(192.168.1.110)&lt;/td&gt;
&lt;td&gt;6445&lt;/td&gt;
&lt;td&gt;81&lt;/td&gt;
&lt;td&gt;application-cluster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cluster-2&lt;/td&gt;
&lt;td&gt;HOST_IP(192.168.1.110)&lt;/td&gt;
&lt;td&gt;6446&lt;/td&gt;
&lt;td&gt;82&lt;/td&gt;
&lt;td&gt;Application Cluster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cluster-3&lt;/td&gt;
&lt;td&gt;HOST_IP(192.168.1.110)&lt;/td&gt;
&lt;td&gt;6447&lt;/td&gt;
&lt;td&gt;83&lt;/td&gt;
&lt;td&gt;Application Cluster&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Network
&lt;/h3&gt;

&lt;p&gt;Creates a docker &lt;code&gt;bridge&lt;/code&gt; type network named &lt;code&gt;multi-clusters&lt;/code&gt;, which run all containers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker network create multi-clusters
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Find your machine host IP address, mine is &lt;code&gt;192.168.1.110&lt;/code&gt;, and export that as an environment variable to be used later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;HOST_IP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;192.168.1.110
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Cluster creation
&lt;/h3&gt;

&lt;p&gt;We are going to use &lt;code&gt;k3d&lt;/code&gt; to create 4 clusters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;API_PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;6444 &lt;span class="c"&gt;#6444 6445 6446 6447&lt;/span&gt;
&lt;span class="nv"&gt;PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;80 &lt;span class="c"&gt;#81 82 83&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;CLUSTER_NAME &lt;span class="k"&gt;in &lt;/span&gt;control-plane cluster-1 cluster-2 cluster-3
&lt;span class="k"&gt;do
  &lt;/span&gt;k3d cluster create &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--image&lt;/span&gt; docker.io/rancher/k3s:v1.23.8-k3s2 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--api-port&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HOST_IP&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;API_PORT&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--port&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;API_PORT&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:6443@server:0"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--port&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PORT&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:80@server:0"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--servers-memory&lt;/span&gt; 4g &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--k3s-arg&lt;/span&gt; &lt;span class="s2"&gt;"--disable=traefik@server:0"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--network&lt;/span&gt; multi-clusters &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--timeout&lt;/span&gt; 120s &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--wait&lt;/span&gt;
    &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;API_PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;API_PORT+1&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;PORT+1&lt;span class="o"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install FSM
&lt;/h3&gt;

&lt;p&gt;Install FSM to newly created 4 clusters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm repo update
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;FSM_NAMESPACE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;flomesh
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;FSM_VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.2.0-alpha.9
&lt;span class="k"&gt;for &lt;/span&gt;CLUSTER_NAME &lt;span class="k"&gt;in &lt;/span&gt;control-plane cluster-1 cluster-2 cluster-3
&lt;span class="k"&gt;do 
  &lt;/span&gt;kubectx k3d-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
  &lt;span class="nb"&gt;sleep &lt;/span&gt;1
  helm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--namespace&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;FSM_NAMESPACE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;--create-namespace&lt;/span&gt; &lt;span class="nt"&gt;--version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;FSM_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;--set&lt;/span&gt; fsm.logLevel&lt;span class="o"&gt;=&lt;/span&gt;5 fsm fsm/fsm
  &lt;span class="nb"&gt;sleep &lt;/span&gt;1
  kubectl &lt;span class="nb"&gt;wait&lt;/span&gt; &lt;span class="nt"&gt;--for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;condition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ready pod &lt;span class="nt"&gt;--all&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$FSM_NAMESPACE&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have our clusters ready, now we need to federate them together, but before we do that, let's first understand the mechanics on how FSM is configured.&lt;/p&gt;

&lt;p&gt;In Part 1 of this series, we stated that FSM provides a set of Kubernetes custom resources (CRD) for cluster connectors, and makes use of &lt;a href="https://github.com/kubernetes/enhancements/tree/master/keps/sig-multicluster/1645-multi-cluster-services-api" rel="noopener noreferrer"&gt;KEP-1645&lt;/a&gt; &lt;code&gt;ServiceExport&lt;/code&gt; and &lt;code&gt;ServiceImport&lt;/code&gt; API for exporting and importing services. So let's take a quick look at them&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;Cluster&lt;/code&gt; CRD
&lt;/h3&gt;

&lt;p&gt;When registering a cluster, we provide the following information.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The address (e.g. &lt;code&gt;gatewayHost: cluster-A.host&lt;/code&gt;) and port (e.g. &lt;code&gt;gatewayPort: 80&lt;/code&gt;) of the cluster&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kubeconfig&lt;/code&gt; to access the cluster, containing the api-server address and information such as the certificate and secret key
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flomesh.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Cluster&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cluster-A&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;gatewayHost&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cluster-A.host&lt;/span&gt;
  &lt;span class="na"&gt;gatewayPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
  &lt;span class="na"&gt;kubeconfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|+&lt;/span&gt;
    &lt;span class="s"&gt;---&lt;/span&gt;
    &lt;span class="s"&gt;apiVersion: v1&lt;/span&gt;
    &lt;span class="s"&gt;clusters:&lt;/span&gt;
    &lt;span class="s"&gt;- cluster:&lt;/span&gt;
        &lt;span class="s"&gt;certificate-authority-data:&lt;/span&gt;
        &lt;span class="s"&gt;server: https://cluster-A.host:6443&lt;/span&gt;
      &lt;span class="s"&gt;name: cluster-A&lt;/span&gt;
    &lt;span class="s"&gt;contexts:&lt;/span&gt;
    &lt;span class="s"&gt;- context:&lt;/span&gt;
        &lt;span class="s"&gt;cluster: cluster-A&lt;/span&gt;
        &lt;span class="s"&gt;user: admin@cluster-A&lt;/span&gt;
      &lt;span class="s"&gt;name: cluster-A&lt;/span&gt;
    &lt;span class="s"&gt;current-context: cluster-A&lt;/span&gt;
    &lt;span class="s"&gt;kind: Config&lt;/span&gt;
    &lt;span class="s"&gt;preferences: {}&lt;/span&gt;
    &lt;span class="s"&gt;users:&lt;/span&gt;
    &lt;span class="s"&gt;- name: admin@cluster-A&lt;/span&gt;
      &lt;span class="s"&gt;user:&lt;/span&gt;
        &lt;span class="s"&gt;client-certificate-data:&lt;/span&gt;
        &lt;span class="s"&gt;client-key-data:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;ServiceExport&lt;/code&gt; and &lt;code&gt;ServiceImport&lt;/code&gt; CRD
&lt;/h3&gt;

&lt;p&gt;For cross-cluster service registration, FSM provides the &lt;code&gt;ServiceExport&lt;/code&gt; and &lt;code&gt;ServiceImport&lt;/code&gt; CRDs from &lt;a href="https://github.com/kubernetes/enhancements/tree/master/keps/sig-multicluster/1645-multi-cluster-services-api" rel="noopener noreferrer"&gt;KEP-1645: Multi-Cluster Services API&lt;/a&gt; for &lt;code&gt;ServiceExports.flomesh.io&lt;/code&gt; and &lt;code&gt;ServiceImports.flomesh.io&lt;/code&gt;. The former is used to register services with the control plane and declare that the application can provide services across clusters, while the latter is used to reference services from other clusters. &lt;/p&gt;

&lt;p&gt;For clusters &lt;code&gt;cluster-A&lt;/code&gt; and &lt;code&gt;cluster-B&lt;/code&gt; that join the cluster federation, a &lt;code&gt;Service&lt;/code&gt; named &lt;code&gt;foo&lt;/code&gt; exists under the namespace &lt;code&gt;bar&lt;/code&gt; of cluster &lt;code&gt;cluster-A&lt;/code&gt; and a &lt;code&gt;ServiceExport&lt;/code&gt; &lt;code&gt;foo&lt;/code&gt; of the same name is created under the same namespace. A &lt;code&gt;ServiceImport&lt;/code&gt; resource with the same name is automatically created under the namespace &lt;code&gt;bar&lt;/code&gt; of cluster &lt;code&gt;cluster-B&lt;/code&gt; (if it does not exist, it is automatically created).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;// in cluster-A&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;foo&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bar&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;foo&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flomesh.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ServiceExport&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;foo&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bar&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="s"&gt;// in cluster-B&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flomesh.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ServiceImport&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;foo&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bar&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The YAML snippet above shows how to register the &lt;code&gt;foo&lt;/code&gt; service to the control plane of a multi-cluster. In the following, we will walk through a slightly more complex scenario of cross-cluster service registration and traffic scheduling.&lt;/p&gt;

&lt;p&gt;Okay that was a quick introduction to the CRDs, so let's continue with our demo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Federate clusters
&lt;/h3&gt;

&lt;p&gt;We will enroll clusters &lt;code&gt;cluster-1&lt;/code&gt;, &lt;code&gt;cluster-2&lt;/code&gt;, and &lt;code&gt;cluster-3&lt;/code&gt; into the management of  &lt;code&gt;control-plane&lt;/code&gt; cluster.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;HOST_IP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;192.168.1.110
kubectx k3d-control-plane
&lt;span class="nb"&gt;sleep &lt;/span&gt;1
&lt;span class="nv"&gt;PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;81
&lt;span class="k"&gt;for &lt;/span&gt;CLUSTER_NAME &lt;span class="k"&gt;in &lt;/span&gt;cluster-1 cluster-2 cluster-3
&lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
apiVersion: flomesh.io/v1alpha1
kind: Cluster
metadata:
  name: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;
spec:
  gatewayHost: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HOST_IP&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;
  gatewayPort: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PORT&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;
  kubeconfig: |+
`k3d kubeconfig get &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt; | sed 's|^|    |g' | sed "s|0.0.0.0|&lt;/span&gt;&lt;span class="nv"&gt;$HOST_IP&lt;/span&gt;&lt;span class="sh"&gt;|g"`
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;PORT+1&lt;span class="o"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install osm-edge Service Mesh
&lt;/h3&gt;

&lt;p&gt;Download osm CLI&lt;/p&gt;

&lt;p&gt;Install the service mesh osm-edge to the clusters &lt;code&gt;cluster-1&lt;/code&gt;, &lt;code&gt;cluster-2&lt;/code&gt;, and &lt;code&gt;cluster-3&lt;/code&gt;. The control plane does not handle application traffic and does not need to be installed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OSM_NAMESPACE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;osm-system
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OSM_MESH_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;osm
&lt;span class="k"&gt;for &lt;/span&gt;CLUSTER_NAME &lt;span class="k"&gt;in &lt;/span&gt;cluster-1 cluster-2 cluster-3
&lt;span class="k"&gt;do
  &lt;/span&gt;kubectx k3d-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
  &lt;span class="nv"&gt;DNS_SVC_IP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get svc &lt;span class="nt"&gt;-n&lt;/span&gt; kube-system &lt;span class="nt"&gt;-l&lt;/span&gt; k8s-app&lt;span class="o"&gt;=&lt;/span&gt;kube-dns &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.items[0].spec.clusterIP}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
osm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--mesh-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OSM_MESH_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--osm-namespace&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OSM_NAMESPACE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--set&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;osm.certificateProvider.kind&lt;span class="o"&gt;=&lt;/span&gt;tresor &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--set&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;osm.image.pullPolicy&lt;span class="o"&gt;=&lt;/span&gt;Always &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--set&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;osm.sidecarLogLevel&lt;span class="o"&gt;=&lt;/span&gt;error &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--set&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;osm.controllerLogLevel&lt;span class="o"&gt;=&lt;/span&gt;warn &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;900s &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--set&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;osm.localDNSProxy.enable&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--set&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;osm.localDNSProxy.primaryUpstreamDNSServerIPAddr&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DNS_SVC_IP&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deploy Demo application
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Deploying mesh-managed applications
&lt;/h3&gt;

&lt;p&gt;Deploy the &lt;code&gt;httpbin&lt;/code&gt; application under the &lt;code&gt;httpbin&lt;/code&gt; namespace of clusters &lt;code&gt;cluster-1&lt;/code&gt; and &lt;code&gt;cluster-3&lt;/code&gt; (which are managed by the mesh and will inject sidecar). Here the &lt;code&gt;httpbin&lt;/code&gt; application is implemented by &lt;a href="https://flomesh.io/pipy" rel="noopener noreferrer"&gt;Pipy&lt;/a&gt; and will return the current cluster name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;httpbin
&lt;span class="k"&gt;for &lt;/span&gt;CLUSTER_NAME &lt;span class="k"&gt;in &lt;/span&gt;cluster-1 cluster-3
&lt;span class="k"&gt;do
  &lt;/span&gt;kubectx k3d-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
  kubectl create namespace &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
  osm namespace add &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
  kubectl apply &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpbin
  labels:
    app: pipy
spec:
  replicas: 1
  selector:
    matchLabels:
      app: pipy
  template:
    metadata:
      labels:
        app: pipy
    spec:
      containers:
        - name: pipy
          image: flomesh/pipy:latest
          ports:
            - containerPort: 8080
          command:
            - pipy
            - -e
            - |
              pipy()
              .listen(8080)
              .serveHTTP(new Message('Hi, I am from &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt; and controlled by mesh!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;'))
---
apiVersion: v1
kind: Service
metadata:
  name: httpbin
spec:
  ports:
    - port: 8080
      targetPort: 8080
      protocol: TCP
  selector:
    app: pipy
---
apiVersion: v1
kind: Service
metadata:
  name: httpbin-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;
spec:
  ports:
    - port: 8080
      targetPort: 8080
      protocol: TCP
  selector:
    app: pipy
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;  &lt;span class="nb"&gt;sleep &lt;/span&gt;3
  kubectl &lt;span class="nb"&gt;wait&lt;/span&gt; &lt;span class="nt"&gt;--for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;condition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ready pod &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;--all&lt;/span&gt; &lt;span class="nt"&gt;--timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;60s
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deploy the &lt;code&gt;curl&lt;/code&gt; application under the namespace &lt;code&gt;curl&lt;/code&gt; in cluster &lt;code&gt;cluster-2&lt;/code&gt;, which is managed by the mesh.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;curl
kubectx k3d-cluster-2
kubectl create namespace &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
osm namespace add &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
kubectl apply &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
apiVersion: v1
kind: ServiceAccount
metadata:
  name: curl
---
apiVersion: v1
kind: Service
metadata:
  name: curl
  labels:
    app: curl
    service: curl
spec:
  ports:
    - name: http
      port: 80
  selector:
    app: curl
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: curl
spec:
  replicas: 1
  selector:
    matchLabels:
      app: curl
  template:
    metadata:
      labels:
        app: curl
    spec:
      serviceAccountName: curl
      containers:
      - image: curlimages/curl
        imagePullPolicy: IfNotPresent
        name: curl
        command: ["sleep", "365d"]
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="nb"&gt;sleep &lt;/span&gt;3
kubectl &lt;span class="nb"&gt;wait&lt;/span&gt; &lt;span class="nt"&gt;--for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;condition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ready pod &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;--all&lt;/span&gt; &lt;span class="nt"&gt;--timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;60s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Export Service
&lt;/h3&gt;

&lt;p&gt;Let's export services in &lt;code&gt;cluster-1&lt;/code&gt; and &lt;code&gt;cluster-3&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE_MESH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;httpbin
&lt;span class="k"&gt;for &lt;/span&gt;CLUSTER_NAME &lt;span class="k"&gt;in &lt;/span&gt;cluster-1 cluster-3
&lt;span class="k"&gt;do
  &lt;/span&gt;kubectx k3d-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
  kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
apiVersion: flomesh.io/v1alpha1
kind: ServiceExport
metadata:
  namespace: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE_MESH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;
  name: httpbin
spec:
  serviceAccountName: "*"
  rules:
    - portNumber: 8080
      path: "/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;/httpbin-mesh"
      pathType: Prefix
---
apiVersion: flomesh.io/v1alpha1
kind: ServiceExport
metadata:
  namespace: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE_MESH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;
  name: httpbin-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;
spec:
  serviceAccountName: "*"
  rules:
    - portNumber: 8080
      path: "/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;/httpbin-mesh-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"
      pathType: Prefix
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;span class="nb"&gt;sleep &lt;/span&gt;1
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After exporting the services, FSM will automatically create Ingress rules for them, and with the rules, you can access these services through Ingress.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
&lt;span class="k"&gt;for &lt;/span&gt;CLUSTER_NAME_INDEX &lt;span class="k"&gt;in &lt;/span&gt;1 3
&lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;cluster-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME_INDEX&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;80+CLUSTER_NAME_INDEX&lt;span class="o"&gt;))&lt;/span&gt;
  kubectx k3d-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Getting service exported in cluster &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'-----------------------------------'&lt;/span&gt;
  kubectl get serviceexports.flomesh.io &lt;span class="nt"&gt;-A&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'-----------------------------------'&lt;/span&gt;
  curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"http://&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HOST_IP&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PORT&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/httpbin-mesh"&lt;/span&gt;
  curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"http://&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HOST_IP&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PORT&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/httpbin-mesh-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'-----------------------------------'&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To view one of the &lt;code&gt;ServiceExports&lt;/code&gt; resources.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get serviceexports httpbin &lt;span class="nt"&gt;-n&lt;/span&gt; httpbin &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.spec}'&lt;/span&gt; | jq

&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"loadBalancer"&lt;/span&gt;: &lt;span class="s2"&gt;"RoundRobinLoadBalancer"&lt;/span&gt;,
  &lt;span class="s2"&gt;"rules"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;"path"&lt;/span&gt;: &lt;span class="s2"&gt;"/cluster-3/httpbin-mesh"&lt;/span&gt;,
      &lt;span class="s2"&gt;"pathType"&lt;/span&gt;: &lt;span class="s2"&gt;"Prefix"&lt;/span&gt;,
      &lt;span class="s2"&gt;"portNumber"&lt;/span&gt;: 8080
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;]&lt;/span&gt;,
  &lt;span class="s2"&gt;"serviceAccountName"&lt;/span&gt;: &lt;span class="s2"&gt;"*"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exported services can be imported into other managed clusters. For example, if we look at the cluster &lt;code&gt;cluster-2&lt;/code&gt;, we can have multiple services imported.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectx k3d-cluster-2
kubectl get serviceimports &lt;span class="nt"&gt;-A&lt;/span&gt;

NAMESPACE   NAME                AGE
httpbin     httpbin-cluster-1   13m
httpbin     httpbin-cluster-3   13m
httpbin     httpbin             13m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Testing
&lt;/h3&gt;

&lt;p&gt;Staying in the &lt;code&gt;cluster-2&lt;/code&gt; cluster (&lt;code&gt;kubectx k3d-cluster-2&lt;/code&gt;), we test if we can access these imported services from the &lt;code&gt;curl&lt;/code&gt; application in the mesh.&lt;/p&gt;

&lt;p&gt;Get the pod of the &lt;code&gt;curl&lt;/code&gt; application, from which we will later launch requests to simulate service access.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;curl_client&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get pod &lt;span class="nt"&gt;-n&lt;/span&gt; curl &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;curl &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.items[0].metadata.name}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point you will find that it is not accessible.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;curl_client&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; curl &lt;span class="nt"&gt;-c&lt;/span&gt; curl &lt;span class="nt"&gt;--&lt;/span&gt; curl &lt;span class="nt"&gt;-s&lt;/span&gt; http://httpbin.httpbin:8080/

&lt;span class="nb"&gt;command &lt;/span&gt;terminated with &lt;span class="nb"&gt;exit &lt;/span&gt;code 7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that this is normal, by default no other cluster instance will be used to respond to requests, which means no calls to other clusters will be made by default. So how to access it, then we need to be clear about the global traffic policy &lt;code&gt;GlobalTrafficPolicy&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Global Traffic Policy
&lt;/h2&gt;

&lt;p&gt;Note that all global traffic policies are set on the user's side, so this demo is about setting global traffic policies on the cluster &lt;code&gt;cluster-2&lt;/code&gt; side. So before you start, switch to cluster &lt;code&gt;cluster-2&lt;/code&gt;: &lt;code&gt;kubectx k3d-cluster-2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The global traffic policy is set via CRD &lt;code&gt;GlobalTrafficPolicy&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;GlobalTrafficPolicy&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
   &lt;span class="n"&gt;metav1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TypeMeta&lt;/span&gt;   &lt;span class="s"&gt;`json:",inline"`&lt;/span&gt;  
   &lt;span class="n"&gt;metav1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ObjectMeta&lt;/span&gt; &lt;span class="s"&gt;`json:"metadata,omitempty"`&lt;/span&gt;  

   &lt;span class="n"&gt;Spec&lt;/span&gt;   &lt;span class="n"&gt;GlobalTrafficPolicySpec&lt;/span&gt;   &lt;span class="s"&gt;`json:"spec,omitempty"`&lt;/span&gt;  
   &lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="n"&gt;GlobalTrafficPolicyStatus&lt;/span&gt; &lt;span class="s"&gt;`json:"status,omitempty"`&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;GlobalTrafficPolicySpec&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
   &lt;span class="n"&gt;LbType&lt;/span&gt; &lt;span class="n"&gt;LoadBalancerType&lt;/span&gt; &lt;span class="s"&gt;`json:"lbType"`&lt;/span&gt;  
   &lt;span class="n"&gt;LoadBalanceTarget&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;TrafficTarget&lt;/span&gt; &lt;span class="s"&gt;`json:"targets"`&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Global load balancing types &lt;code&gt;.spec.lbType&lt;/code&gt; There are three types.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Locality&lt;/code&gt;: uses only the services of this cluster, and is also the default type. This is why accessing the &lt;code&gt;httpbin&lt;/code&gt; application fails when we don't provide any global policy, because there is no such service in cluster &lt;code&gt;cluster-2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;FailOver&lt;/code&gt;: proxies to other clusters only when access to this cluster fails, which is often referred to as failover, similar to primary backup.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ActiveActive&lt;/code&gt;: Proxy to other clusters under normal conditions, similar to multi-live.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;FailOver&lt;/code&gt; and &lt;code&gt;ActiveActive&lt;/code&gt; policies are used with the &lt;em&gt;targets&lt;/em&gt; field to specify the id of the standby cluster, which is the cluster that can be routed to in case of failure or load balancing. ** For example, if you look at the import service &lt;code&gt;httpbin/httpbin&lt;/code&gt; in cluster &lt;code&gt;cluster-2&lt;/code&gt;, you can see that it has two &lt;code&gt;endpoints&lt;/code&gt; for the outer cluster, note that &lt;code&gt;endpoints&lt;/code&gt; here is a different concept than the native &lt;code&gt;endpoints.v1&lt;/code&gt; and will contain more information. In addition, there is the cluster id &lt;code&gt;clusterKey&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get serviceimports httpbin &lt;span class="nt"&gt;-n&lt;/span&gt; httpbin &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.spec}'&lt;/span&gt; | jq

&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"ports"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;"endpoints"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
        &lt;span class="o"&gt;{&lt;/span&gt;
          &lt;span class="s2"&gt;"clusterKey"&lt;/span&gt;: &lt;span class="s2"&gt;"default/default/default/cluster-1"&lt;/span&gt;,
          &lt;span class="s2"&gt;"target"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"host"&lt;/span&gt;: &lt;span class="s2"&gt;"192.168.1.110"&lt;/span&gt;,
            &lt;span class="s2"&gt;"ip"&lt;/span&gt;: &lt;span class="s2"&gt;"192.168.1.110"&lt;/span&gt;,
            &lt;span class="s2"&gt;"path"&lt;/span&gt;: &lt;span class="s2"&gt;"/cluster-1/httpbin-mesh"&lt;/span&gt;,
            &lt;span class="s2"&gt;"port"&lt;/span&gt;: 81
          &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;,
        &lt;span class="o"&gt;{&lt;/span&gt;
          &lt;span class="s2"&gt;"clusterKey"&lt;/span&gt;: &lt;span class="s2"&gt;"default/default/default/cluster-3"&lt;/span&gt;,
          &lt;span class="s2"&gt;"target"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"host"&lt;/span&gt;: &lt;span class="s2"&gt;"192.168.1.110"&lt;/span&gt;,
            &lt;span class="s2"&gt;"ip"&lt;/span&gt;: &lt;span class="s2"&gt;"192.168.1.110"&lt;/span&gt;,
            &lt;span class="s2"&gt;"path"&lt;/span&gt;: &lt;span class="s2"&gt;"/cluster-3/httpbin-mesh"&lt;/span&gt;,
            &lt;span class="s2"&gt;"port"&lt;/span&gt;: 83
          &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;]&lt;/span&gt;,
      &lt;span class="s2"&gt;"port"&lt;/span&gt;: 8080,
      &lt;span class="s2"&gt;"protocol"&lt;/span&gt;: &lt;span class="s2"&gt;"TCP"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;]&lt;/span&gt;,
  &lt;span class="s2"&gt;"serviceAccountName"&lt;/span&gt;: &lt;span class="s2"&gt;"*"&lt;/span&gt;,
  &lt;span class="s2"&gt;"type"&lt;/span&gt;: &lt;span class="s2"&gt;"ClusterSetIP"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Routing Type - &lt;code&gt;Locality&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The default routing type is &lt;code&gt;Locality&lt;/code&gt;, and as tested above, traffic cannot be dispatched to other clusters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;curl_client&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; curl &lt;span class="nt"&gt;-c&lt;/span&gt; curl &lt;span class="nt"&gt;--&lt;/span&gt; curl &lt;span class="nt"&gt;-s&lt;/span&gt; http://httpbin.httpbin:8080/
&lt;span class="nb"&gt;command &lt;/span&gt;terminated with &lt;span class="nb"&gt;exit &lt;/span&gt;code 7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Routing Type - &lt;code&gt;FailOver&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Since setting a global traffic policy for causes access failure, we start by enabling &lt;code&gt;FailOver&lt;/code&gt; mode. &lt;strong&gt;Note that the global policy traffic, to be consistent with the target service name and namespace.&lt;/strong&gt; For example, if we want to access &lt;code&gt;http://httpbin.httpbin:8080/&lt;/code&gt;, we need to create &lt;code&gt;GlobalTrafficPolicy&lt;/code&gt; resource named &lt;code&gt;httpbin&lt;/code&gt; under the namespace &lt;code&gt;httpbin&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-n&lt;/span&gt; httpbin &lt;span class="nt"&gt;-f&lt;/span&gt;  - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
apiVersion: flomesh.io/v1alpha1
kind: GlobalTrafficPolicy
metadata:
  name: httpbin
spec:
  lbType: FailOver
  targets:
    - clusterKey: default/default/default/cluster-1
    - clusterKey: default/default/default/cluster-3
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After setting the policy, let's try it again by requesting.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;curl_client&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; curl &lt;span class="nt"&gt;-c&lt;/span&gt; curl &lt;span class="nt"&gt;--&lt;/span&gt; curl &lt;span class="nt"&gt;-s&lt;/span&gt; http://httpbin.httpbin:8080/
Hi, I am from cluster-1!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The request is successful and the request is proxied to the service in cluster &lt;code&gt;cluster-1&lt;/code&gt;. Another request is made, and it is proxied to cluster &lt;code&gt;cluster-3&lt;/code&gt;, as expected for load balancing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;curl_client&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; curl &lt;span class="nt"&gt;-c&lt;/span&gt; curl &lt;span class="nt"&gt;--&lt;/span&gt; curl &lt;span class="nt"&gt;-s&lt;/span&gt; http://httpbin.httpbin:8080/
Hi, I am from cluster-3!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What will happen if we deploy the application &lt;code&gt;httpbin&lt;/code&gt; in the namespace &lt;code&gt;httpbin&lt;/code&gt; of the cluster &lt;code&gt;cluster-2&lt;/code&gt;?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;httpbin
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;cluster-2

kubectx k3d-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
kubectl create namespace &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
osm namespace add &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
kubectl apply &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpbin
  labels:
    app: pipy
spec:
  replicas: 1
  selector:
    matchLabels:
      app: pipy
  template:
    metadata:
      labels:
        app: pipy
    spec:
      containers:
        - name: pipy
          image: flomesh/pipy:latest
          ports:
            - containerPort: 8080
          command:
            - pipy
            - -e
            - |
              pipy()
              .listen(8080)
              .serveHTTP(new Message('Hi, I am from &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;'))
---
apiVersion: v1
kind: Service
metadata:
  name: httpbin
spec:
  ports:
    - port: 8080
      targetPort: 8080
      protocol: TCP
  selector:
    app: pipy
---
apiVersion: v1
kind: Service
metadata:
  name: httpbin-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;
spec:
  ports:
    - port: 8080
      targetPort: 8080
      protocol: TCP
  selector:
    app: pipy
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="nb"&gt;sleep &lt;/span&gt;3
kubectl &lt;span class="nb"&gt;wait&lt;/span&gt; &lt;span class="nt"&gt;--for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;condition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ready pod &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAMESPACE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;--all&lt;/span&gt; &lt;span class="nt"&gt;--timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;60s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the application is running normally, this time we send the request to test again. From the results, it looks like the request is processed in the current cluster.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;curl_client&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; curl &lt;span class="nt"&gt;-c&lt;/span&gt; curl &lt;span class="nt"&gt;--&lt;/span&gt; curl &lt;span class="nt"&gt;-s&lt;/span&gt; http://httpbin.httpbin:8080/ 
Hi, I am from cluster-2!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even if the request is repeated multiple times, it will always return &lt;code&gt;Hi, I am from cluster-2!&lt;/code&gt;, which indicates that the services of same cluster are used in preference to the services imported from other clusters.&lt;/p&gt;

&lt;p&gt;In some cases, we also want other clusters to participate in the service as well, because the resources of other clusters are wasted if only the services of this cluster are used. This is where the &lt;code&gt;ActiveActive&lt;/code&gt; routing type comes into play.&lt;/p&gt;

&lt;h3&gt;
  
  
  Routing Type - &lt;code&gt;ActiveActive&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Moving on from the status above, let's test the &lt;code&gt;ActiveActive&lt;/code&gt; type by modifying the policy created earlier and updating it to &lt;code&gt;ActiveActive&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-n&lt;/span&gt; httpbin &lt;span class="nt"&gt;-f&lt;/span&gt;  - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
apiVersion: flomesh.io/v1alpha1
kind: GlobalTrafficPolicy
metadata:
  name: httpbin
spec:
  lbType: ActiveActive
  targets:
    - clusterKey: default/default/default/cluster-1
    - clusterKey: default/default/default/cluster-3
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Multiple requests will show that &lt;code&gt;httpbin&lt;/code&gt; from all three clusters will participate in the service. This indicates that the load is being proxied to multiple clusters in a balanced manner.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;curl_client&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; curl &lt;span class="nt"&gt;-c&lt;/span&gt; curl &lt;span class="nt"&gt;--&lt;/span&gt; curl &lt;span class="nt"&gt;-s&lt;/span&gt; http://httpbin.httpbin:8080/
Hi, I am from cluster-1 and controlled by mesh!
kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;curl_client&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; curl &lt;span class="nt"&gt;-c&lt;/span&gt; curl &lt;span class="nt"&gt;--&lt;/span&gt; curl &lt;span class="nt"&gt;-s&lt;/span&gt; http://httpbin.httpbin:8080/
Hi, I am from cluster-2!
kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;curl_client&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; curl &lt;span class="nt"&gt;-c&lt;/span&gt; curl &lt;span class="nt"&gt;--&lt;/span&gt; curl &lt;span class="nt"&gt;-s&lt;/span&gt; http://httpbin.httpbin:8080/
Hi, I am from cluster-3 and controlled by mesh!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;This concludes our series of introductions to Flomesh Service Mesh, an open-source solution from &lt;a href="https://flomesh.io" rel="noopener noreferrer"&gt;Flomesh&lt;/a&gt; to help you achieve Kubernetes multi-cluster services discovery and communication.&lt;/p&gt;

&lt;p&gt;In part 1 of this series, we briefly touched on the use cases for multi-cluster requirements and talked about the motivation and goals of &lt;a href="https://github.com/flomesh-io/fsm" rel="noopener noreferrer"&gt;FSM&lt;/a&gt; and its architecture. In this part of the series we demonstrated how to implement cross-cluster traffic scheduling and load balancing of services, and try three different global traffic policies: local cluster scheduling only, failover, and global load balancing.&lt;/p&gt;

&lt;p&gt;If you are interested in learning more about SMI-compatible Service Mesh, FSM, and Programmable Proxy, visit our website &lt;a href="https://flomesh.io" rel="noopener noreferrer"&gt;Flomesh.io&lt;/a&gt; for more detailed documentation, tutorials, and use cases.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>multicluster</category>
      <category>servicemesh</category>
      <category>pipyproxy</category>
    </item>
    <item>
      <title>Kubernetes: Multi-cluster communication with Flomesh Service Mesh</title>
      <dc:creator>Ali Naqvi</dc:creator>
      <pubDate>Mon, 28 Nov 2022 13:22:22 +0000</pubDate>
      <link>https://dev.to/naqvis/kubernetes-multi-cluster-communication-with-flomesh-service-mesh-123f</link>
      <guid>https://dev.to/naqvis/kubernetes-multi-cluster-communication-with-flomesh-service-mesh-123f</guid>
      <description>&lt;p&gt;Kubernetes has been quite successful in popularizing the idea of ​​container clusters. Deployments have reached a point where many users are running multiple clusters and struggling to keep them running smoothly. Organizations need to run multiple Kubernetes clusters might fall into one of the below reasons (not an exhaustive list):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Location

&lt;ul&gt;
&lt;li&gt;Latency (run the application as close to customers as possible)&lt;/li&gt;
&lt;li&gt;Jurisdiction (e.g. required to keep user data in-country)&lt;/li&gt;
&lt;li&gt;Data gravity (e.g. data exists in one provider)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Isolation

&lt;ul&gt;
&lt;li&gt;Environment (e.g. development, testing, staging, prod, etc)&lt;/li&gt;
&lt;li&gt;Performance isolation (teams don't want to feel each other)&lt;/li&gt;
&lt;li&gt;Security isolation (sensitive data or untrusted code)&lt;/li&gt;
&lt;li&gt;Organizational isolation (teams have different management domains)&lt;/li&gt;
&lt;li&gt;Cost isolation (teams want to get different bills)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Reliability

&lt;ul&gt;
&lt;li&gt;Blast radius (an infra or app problem in one cluster doesn't kill the whole system)&lt;/li&gt;
&lt;li&gt;Infrastructure diversity (an underlying zone, region, or provider outages does not bring down the whole system)&lt;/li&gt;
&lt;li&gt;Scale (the app is too big to fit in a single cluster)&lt;/li&gt;
&lt;li&gt;Upgrade scope (upgrade infra for some parts of your app but not all of it; avoid the need for in-place cluster upgrades)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;There is currently no standard way to connect or even think about Kubernetes services beyond the single cluster boundary, and Kubernetes Multicluster SIG has put together a proposal &lt;a href="https://github.com/kubernetes/enhancements/tree/master/keps/sig-multicluster/1645-multi-cluster-services-api" rel="noopener noreferrer"&gt;KEP-1645&lt;/a&gt; to extend Kubernetes Service concepts across multiple clusters.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://flomesh.io" rel="noopener noreferrer"&gt;Flomesh&lt;/a&gt; team has been spending time tackling the challenge of multicluster communication, integrating north-south traffic management capabilities into &lt;a href="https://flomesh.io/osm-edge" rel="noopener noreferrer"&gt;osm-edge&lt;/a&gt; SMI compatible service mesh, and contributing back to the Open Source community.&lt;/p&gt;

&lt;p&gt;In this part of the series, we will be looking into motivation, goals, architecture of &lt;a href="https://github.com/flomesh-io/fsm" rel="noopener noreferrer"&gt;FSM&lt;/a&gt; multi-cluster support, its components, and how it integrates with &lt;a href="https://flomesh.io/osm-edge" rel="noopener noreferrer"&gt;osm-edge&lt;/a&gt; full-fledged, lightweight, SMI-compatible service mesh suitable for cloud-native and edge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Flomesh Service Mesh
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/flomesh-io/fsm" rel="noopener noreferrer"&gt;FSM&lt;/a&gt; is an open-source product from &lt;a href="https://flomesh.io" rel="noopener noreferrer"&gt;Flomesh&lt;/a&gt; for Kubernetes north-south traffic, gateway API controller, and multi-cluster management. FSM uses &lt;a href="https://flomesh.io" rel="noopener noreferrer"&gt;Pipy&lt;/a&gt;, a programmable proxy at its core, and provides an Ingress controller, &lt;em&gt;Gateway API&lt;/em&gt; controller, load balancer, cross-cluster service registration discovery, and more.&lt;/p&gt;

&lt;h3&gt;
  
  
  Motivation
&lt;/h3&gt;

&lt;p&gt;During our consultancy and support to the community, commercial clients, and enterprises we have seen multiple requests and desires (a few of which are cited above) on why they want to split their deployments across multiple clusters while maintaining mutual dependencies between workloads operating in those clusters. Currently, the cluster is a hard boundary, and service is opaque to a distant K8s consumer who may otherwise use metadata (e.g. endpoint topology) to better direct traffic. Users may want to use services distributed across clusters to support failover or temporarily during migration, however, this needs non-trivial customized solutions today.&lt;/p&gt;

&lt;p&gt;Flomesh team aims to help the community by providing solutions to these problems.&lt;/p&gt;

&lt;h3&gt;
  
  
  Goals
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Define a minimal API to support service discovery and consumption across clusters.

&lt;ul&gt;
&lt;li&gt;Consume a service in another cluster.&lt;/li&gt;
&lt;li&gt;Consume a service deployed in multiple clusters as a single service.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;When a service is consumed from another cluster its behavior should be predictable and consistent with how it would be consumed within its cluster.&lt;/li&gt;

&lt;li&gt;Allow gradual rollout of changes in a multi-cluster environment.&lt;/li&gt;

&lt;li&gt;Provide a stand-alone implementation that can be used without any coupling to any product and/or solution.&lt;/li&gt;

&lt;li&gt;Transparent integration with &lt;a href="https://flomesh.io/osm-edge" rel="noopener noreferrer"&gt;osm-edge&lt;/a&gt; service mesh, for users who want to have multi-cluster support with service mesh functionality.&lt;/li&gt;

&lt;li&gt;Fully open source and welcomes the community to participate and contribute.&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Architecture
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Control plane&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb23f372mxr207x3znqhg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb23f372mxr207x3znqhg.png" alt="FSM control plane" width="800" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;osm-edge integration (managed cluster)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqfim9hcwctf0j53sgjtm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqfim9hcwctf0j53sgjtm.png" alt="FSM running with osm-edge" width="800" height="617"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;FSM provides a set of Kubernetes custom resources (CRD) for cluster connector, and make use of &lt;a href="https://github.com/kubernetes/enhancements/tree/master/keps/sig-multicluster/1645-multi-cluster-services-api" rel="noopener noreferrer"&gt;KEP-1645&lt;/a&gt; &lt;code&gt;ServiceExport&lt;/code&gt; and &lt;code&gt;ServiceImport&lt;/code&gt; API for exporting and importing services.&lt;/p&gt;

&lt;p&gt;FSM multi-cluster support is already in the alpha stage and is available on &lt;a href="https://github.com/flomesh-io/fsm" rel="noopener noreferrer"&gt;FSM Github&lt;/a&gt;, you are welcome to give it a try.&lt;/p&gt;

&lt;p&gt;In the upcoming part of this series, we will be exploring FSM multi-cluster functionality via hands-on tutorial and demo, so stay tuned.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Kubernetes is no longer constrained to a single boundary, and use cases of having multiple Kubernetes clusters are becoming quite common. There wasn't a typical or standard way of connecting numerous clusters and providing a transparent means to access services across boundaries. Kubernetes multi-cluster special interest group is working on proposals to provide a common set of APIs that can be implemented by vendors and provide a consistent way for k8s users to access services within or across boundaries.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/flomesh-io/fsm" rel="noopener noreferrer"&gt;Flomesh Service Mesh(FSM)&lt;/a&gt; from &lt;a href="https://flomesh.io" rel="noopener noreferrer"&gt;Flomesh&lt;/a&gt; is a Kubernetes North-South traffic manager, that provides Ingress controllers, Gateway API, Load Balancer, and cross-cluster service registration and service discovery. FSM uses &lt;a href="https://github.com/flomesh-io/pipy" rel="noopener noreferrer"&gt;Pipy&lt;/a&gt; - a programmable network proxy, as its data plane and is suitable for cloud, edge, and IoT.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>github</category>
      <category>webdev</category>
      <category>discuss</category>
    </item>
    <item>
      <title>osm-edge: Using access control policies to access services with the service mesh</title>
      <dc:creator>Ali Naqvi</dc:creator>
      <pubDate>Tue, 08 Nov 2022 06:46:19 +0000</pubDate>
      <link>https://dev.to/flomesh/osm-edge-using-access-control-policies-to-access-services-with-the-service-mesh-5hel</link>
      <guid>https://dev.to/flomesh/osm-edge-using-access-control-policies-to-access-services-with-the-service-mesh-5hel</guid>
      <description>&lt;p&gt;Deploying a service mesh in a complex brownfield environment is a lengthy and gradual process requiring upfront planning, or there may exist use cases where you have a specific set of services that either aren't yet ready for migration or for some reason can not be migrated to service mesh.&lt;/p&gt;

&lt;p&gt;This blog post will talk about the approaches which can be used to enable services outside of the service mesh to communicate with services within the &lt;a href="https://flomesh.io/osm-edge"&gt;osm-edge&lt;/a&gt; service mesh.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/flomesh-io/osm-edge/"&gt;osm-edge&lt;/a&gt; forked from &lt;a href="https://github.com/openservicemesh/osm"&gt;Open Service Mesh&lt;/a&gt; is a lightweight, extensible, cloud-native, SMI-compatible service mesh built purposely for Edge computing. osm-edge uses lightweight programmable proxy &lt;a href="https://flomesh.io/pipy"&gt;Pipy&lt;/a&gt; as a sidecar proxy.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jcZDy-4f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c9jtgh3t12dmfoadxdcr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jcZDy-4f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c9jtgh3t12dmfoadxdcr.png" alt="Accessing services within service mesh" width="880" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;osm-edge offers two ways to allow accessing services within the service mesh:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;via Ingress

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/flomesh-io/fsm"&gt;FSM&lt;/a&gt; Ingress controller&lt;/li&gt;
&lt;li&gt;Nginx Ingress controller&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Access Control

&lt;ul&gt;
&lt;li&gt;Service&lt;/li&gt;
&lt;li&gt;IPRange&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first method to access the services in the service mesh is via Ingress controller, and treat the services outside the mesh as the services inside the cluster. The advantage of this approach is that the setup is simple and straightforward and the disadvantages are also apparent, as you cannot achieve fine-grained access control, and all services outside the mesh can access services within the mesh.&lt;/p&gt;

&lt;p&gt;This article will focus on the second approach, which allows support for fine-grained access control on who can access services within the service mesh. This feature is newly added and available in release 1.2.0 &lt;a href="https://github.com/flomesh-io/osm-edge/releases/tag/v1.2.0"&gt;osm-edge v1.2.0&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Access Control can be configured via two resource types: Service and IP range. In terms of data transmission, it supports plaintext transmission and mTLS-encrypted traffic.&lt;/p&gt;

&lt;p&gt;Let's get started with a demo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo environment preparation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Kubernetes cluster
&lt;/h3&gt;

&lt;p&gt;Using the minimalist Kubernetes distribution &lt;a href="https://getk8e.com"&gt;k8e&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sfL&lt;/span&gt; https://getk8e.com/install.sh | &lt;span class="nv"&gt;K8E_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;k8e-mesh &lt;span class="nv"&gt;INSTALL_K8E_EXEC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"server --cluster-init --write-kubeconfig-mode 644 --write-kubeconfig ~/.kube/config"&lt;/span&gt; sh -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  osm-edge CLI
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;system&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;:upper:] &lt;span class="o"&gt;[&lt;/span&gt;:lower:]&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;arch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;dpkg &lt;span class="nt"&gt;--print-architecture&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;release&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;v1.2.0
curl &lt;span class="nt"&gt;-L&lt;/span&gt; https://github.com/flomesh-io/osm-edge/releases/download/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;release&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/osm-edge-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;release&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;system&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;arch&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;.tar.gz | &lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-vxzf&lt;/span&gt; -
./&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;system&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;arch&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/osm version
&lt;span class="nb"&gt;cp&lt;/span&gt; ./&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;system&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;arch&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/osm /usr/local/bin/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install osm-edge
&lt;/h3&gt;

&lt;p&gt;Execute the following commands to install the related components of osm-edge.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;osm_namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;osm-system
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;osm_mesh_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;osm

osm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;--mesh-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$osm_mesh_name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;--osm-namespace&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$osm_namespace&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;--set&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;osm.image.pullPolicy&lt;span class="o"&gt;=&lt;/span&gt;Always
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check to make sure all pods are up and running properly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploy the sample application
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#Mock target service&lt;/span&gt;
kubectl create namespace httpbin
osm namespace add httpbin
kubectl apply &lt;span class="nt"&gt;-n&lt;/span&gt; httpbin &lt;span class="nt"&gt;-f&lt;/span&gt; https://raw.githubusercontent.com/flomesh-io/osm-edge-docs/main/manifests/samples/httpbin/httpbin.yaml

&lt;span class="c"&gt;#Mock external service&lt;/span&gt;
kubectl create namespace curl
kubectl apply &lt;span class="nt"&gt;-n&lt;/span&gt; curl &lt;span class="nt"&gt;-f&lt;/span&gt; https://raw.githubusercontent.com/flomesh-io/osm-edge-docs/main/manifests/samples/curl/curl.yaml

&lt;span class="c"&gt;#Wait for the dependent POD to start normally&lt;/span&gt;
kubectl &lt;span class="nb"&gt;wait&lt;/span&gt; &lt;span class="nt"&gt;--for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;condition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ready pod &lt;span class="nt"&gt;-n&lt;/span&gt; httpbin &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;httpbin &lt;span class="nt"&gt;--timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;180s
kubectl &lt;span class="nb"&gt;wait&lt;/span&gt; &lt;span class="nt"&gt;--for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;condition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ready pod &lt;span class="nt"&gt;-n&lt;/span&gt; curl &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;curl &lt;span class="nt"&gt;--timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;180s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;At this point, we send a request from service  &lt;code&gt;curl&lt;/code&gt; to target service &lt;code&gt;httpbin&lt;/code&gt; by executing the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get pod &lt;span class="nt"&gt;-n&lt;/span&gt; curl &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;curl &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.items..metadata.name}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; curl &lt;span class="nt"&gt;--&lt;/span&gt; curl &lt;span class="nt"&gt;-sI&lt;/span&gt; http://httpbin.httpbin:14001/get
&lt;span class="nb"&gt;command &lt;/span&gt;terminated with &lt;span class="nb"&gt;exit &lt;/span&gt;code 56
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The access fails because by default the services outside the mesh cannot access the services inside the mesh and we need to apply an access control policy.&lt;/p&gt;

&lt;p&gt;Before applying the policy, you need to enable the access control feature, which is disabled by default.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl patch meshconfig osm-mesh-config &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$osm_namespace&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s1"&gt;'{"spec":{"featureFlags":{"enableAccessControlPolicy":true}}}'&lt;/span&gt; &lt;span class="nt"&gt;--type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; merge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Plaintext transfer
&lt;/h3&gt;

&lt;p&gt;Data can be transferred in plaintext or with two-way TLS encryption. Plaintext transfer is relatively simple, so let's demonstrate the plaintext transfer scenario first.&lt;/p&gt;

&lt;h4&gt;
  
  
  Service-based access control
&lt;/h4&gt;

&lt;p&gt;First, create a &lt;code&gt;Service&lt;/code&gt; for service &lt;code&gt;curl&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-n&lt;/span&gt; curl &lt;span class="nt"&gt;-f&lt;/span&gt; - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
apiVersion: v1
kind: Service
metadata:
  name: curl
  labels:
    app: curl
    service: curl
spec:
  ports:
    - name: http
      port: 80
  selector:
    app: curl
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, create an access control policy with the source &lt;code&gt;Service&lt;/code&gt; &lt;code&gt;curl&lt;/code&gt; and the target service &lt;code&gt;httpbin&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
kind: AccessControl
apiVersion: policy.openservicemesh.io/v1alpha1
metadata:
  name: httpbin
  namespace: httpbin
spec:
  backends:
  - name: httpbin
    port:
      number: 14001 # targetPort of httpbin service
      protocol: http
  sources:
  - kind: Service
    namespace: curl
    name: curl
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Execute the command again to send the authentication request, and you can see that this time an &lt;code&gt;HTTP 200&lt;/code&gt; response is received.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get pod &lt;span class="nt"&gt;-n&lt;/span&gt; curl &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;curl &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.items..metadata.name}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; curl &lt;span class="nt"&gt;--&lt;/span&gt; curl &lt;span class="nt"&gt;-sI&lt;/span&gt; http://httpbin.httpbin:14001/get
HTTP/1.1 200 OK
server: gunicorn/19.9.0
&lt;span class="nb"&gt;date&lt;/span&gt;: Mon, 07 Nov 2022 08:47:55 GMT
content-type: application/json
content-length: 267
access-control-allow-origin: &lt;span class="k"&gt;*&lt;/span&gt;
access-control-allow-credentials: &lt;span class="nb"&gt;true
&lt;/span&gt;osm-stats-namespace: httpbin
osm-stats-kind: Deployment
osm-stats-name: httpbin
osm-stats-pod: httpbin-69dc7d545c-qphrh
connection: keep-alive
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before continuing with the rest of the demonstration, execute the command &lt;code&gt;kubectl delete accesscontrol httpbin -n httpbin&lt;/code&gt; to delete the policy you just created.&lt;/p&gt;

&lt;h4&gt;
  
  
  IP range-based access control, plaintext transfer
&lt;/h4&gt;

&lt;p&gt;First, get the pod IP address of the service &lt;code&gt;curl&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;curl_pod_ip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get pod &lt;span class="nt"&gt;-n&lt;/span&gt; curl &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;curl &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.items[0].status.podIP}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Access control using IP ranges is simple, just set the access source type to &lt;code&gt;IPRange&lt;/code&gt; and configure the IP address you just obtained.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
kind: AccessControl
apiVersion: policy.openservicemesh.io/v1alpha1
metadata:
  name: httpbin
  namespace: httpbin
spec:
  backends:
  - name: httpbin
    port:
      number: 14001 # targetPort of httpbin service
      protocol: http
  sources:
  - kind: IPRange
    name: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;curl_pod_ip&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;/32
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Execute the command again to test if the control policy is in effect.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get pod &lt;span class="nt"&gt;-n&lt;/span&gt; curl &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;curl &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.items..metadata.name}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; curl &lt;span class="nt"&gt;--&lt;/span&gt; curl &lt;span class="nt"&gt;-sI&lt;/span&gt; http://httpbin.httpbin:14001/get
HTTP/1.1 200 OK
server: gunicorn/19.9.0
&lt;span class="nb"&gt;date&lt;/span&gt;: Mon, 07 Nov 2022 09:20:57 GMT
content-type: application/json
content-length: 267
access-control-allow-origin: &lt;span class="k"&gt;*&lt;/span&gt;
access-control-allow-credentials: &lt;span class="nb"&gt;true
&lt;/span&gt;osm-stats-namespace: httpbin
osm-stats-kind: Deployment
osm-stats-name: httpbin
osm-stats-pod: httpbin-69dc7d545c-qphrh
connection: keep-alive
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember to execute &lt;code&gt;kubectl delete accesscontrol httpbin -n httpbin&lt;/code&gt; to clean up the policy.&lt;/p&gt;

&lt;p&gt;The previous ones we used were plaintext transfers, next we look at encrypted transfers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Encrypted transfers
&lt;/h3&gt;

&lt;p&gt;The default access policy certificate feature is off, turn it on by executing the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl patch meshconfig osm-mesh-config &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$osm_namespace&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s1"&gt;'{"spec":{"featureFlags":{"enableAccessCertPolicy":true}}}'&lt;/span&gt; &lt;span class="nt"&gt;--type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;merge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create &lt;code&gt;AccessCert&lt;/code&gt; for the access source to assign a certificate for data encryption. The controller will store the certificate information in &lt;code&gt;Secret&lt;/code&gt; &lt;code&gt;curl-mtls-secret&lt;/code&gt; under the namespace &lt;code&gt;curl&lt;/code&gt;, and here also assign SAN &lt;code&gt;curl.curl.cluster.local&lt;/code&gt; for the access source.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
kind: AccessCert
apiVersion: policy.openservicemesh.io/v1alpha1
metadata:
  name: curl-mtls-cert
  namespace: httpbin
spec:
  subjectAltNames:
  - curl.curl.cluster.local
  secret:
    name: curl-mtls-secret
    namespace: curl
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Redeploy &lt;code&gt;curl&lt;/code&gt; and mount the system-assigned &lt;code&gt;Secret&lt;/code&gt; to the pod.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-n&lt;/span&gt; curl &lt;span class="nt"&gt;-f&lt;/span&gt; - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
apiVersion: apps/v1
kind: Deployment
metadata:
  name: curl
spec:
  replicas: 1
  selector:
    matchLabels:
      app: curl
  template:
    metadata:
      labels:
        app: curl
    spec:
      serviceAccountName: curl
      nodeSelector:
        kubernetes.io/os: linux
      containers:
      - image: curlimages/curl
        imagePullPolicy: IfNotPresent
        name: curl
        command: ["sleep", "365d"]
        volumeMounts:
        - name: curl-mtls-secret
          mountPath: "/certs"
          readOnly: true
      volumes:
        - name: curl-mtls-secret
          secret:
            secretName: curl-mtls-secret
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Service-based Access Control
&lt;/h4&gt;

&lt;p&gt;The next step is to create an access control policy that uses encrypted transport. When configuring the target service, enable client certificate checking by specifying &lt;code&gt;tls.skipClientCertValidation = false&lt;/code&gt;. For the access source, in addition to the &lt;code&gt;Service&lt;/code&gt; type of access source, the SAN &lt;code&gt;curl.curl.cluster.local&lt;/code&gt; should be specified via &lt;code&gt;AuthenticatedPrincipal&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
kind: AccessControl
apiVersion: policy.openservicemesh.io/v1alpha1
metadata:
  name: httpbin
  namespace: httpbin
spec:
  backends:
  - name: httpbin
    port:
      number: 14001 # targetPort of httpbin service
      protocol: http
    tls:
      skipClientCertValidation: false
  sources:
  - kind: Service
    namespace: curl
    name: curl
  - kind: AuthenticatedPrincipal
    name: curl.curl.cluster.local
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test whether the access policy is effective. When sending the request, we have to specify the CA certificate, key and certificate to be used for the &lt;code&gt;curl&lt;/code&gt; command of the access source, which will be responded to by &lt;code&gt;HTTP 200&lt;/code&gt; normally.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get pod &lt;span class="nt"&gt;-n&lt;/span&gt; curl &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;curl &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.items..metadata.name}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; curl &lt;span class="nt"&gt;--&lt;/span&gt; curl &lt;span class="nt"&gt;-ksI&lt;/span&gt; https://httpbin.httpbin:14001/get &lt;span class="nt"&gt;--cacert&lt;/span&gt; /certs/ca.crt &lt;span class="nt"&gt;--key&lt;/span&gt; /certs/tls.key &lt;span class="nt"&gt;--cert&lt;/span&gt; /certs/tls.crt
HTTP/2 200
server: gunicorn/19.9.0
&lt;span class="nb"&gt;date&lt;/span&gt;: Mon, 07 Nov 2022 10:44:05 GMT
content-type: application/json
content-length: 267
access-control-allow-origin: &lt;span class="k"&gt;*&lt;/span&gt;
access-control-allow-credentials: &lt;span class="nb"&gt;true
&lt;/span&gt;osm-stats-namespace: httpbin
osm-stats-kind: Deployment
osm-stats-name: httpbin
osm-stats-pod: httpbin-69dc7d545c-qphrh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  IP Range-Based Access Control
&lt;/h4&gt;

&lt;p&gt;After service-based access control, IP range-based control is simple. You just need to specify the type of access source as &lt;code&gt;IPRange&lt;/code&gt; and specify the IP address of the access source. As the application &lt;code&gt;curl&lt;/code&gt; is redeployed, its IP address needs to be retrieved (perhaps you have discovered the drawbacks of IP range-based access control).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;curl_pod_ip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get pod &lt;span class="nt"&gt;-n&lt;/span&gt; curl &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;curl &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.items[0].status.podIP}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
kind: AccessControl
apiVersion: policy.openservicemesh.io/v1alpha1
metadata:
  name: httpbin
  namespace: httpbin
spec:
  backends:
  - name: httpbin
    port:
      number: 14001 # targetPort of httpbin service
      protocol: http
    tls:
      skipClientCertValidation: false
  sources:
  - kind: IPRange
    name: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;curl_pod_ip&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;/32
  - kind: AuthenticatedPrincipal
    name: curl.curl.cluster.local
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Send the request again for testing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get pod &lt;span class="nt"&gt;-n&lt;/span&gt; curl &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;curl &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.items..metadata.name}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; curl &lt;span class="nt"&gt;--&lt;/span&gt; curl &lt;span class="nt"&gt;-ksI&lt;/span&gt; https://httpbin.httpbin:14001/get &lt;span class="nt"&gt;--cacert&lt;/span&gt; /certs/ca.crt &lt;span class="nt"&gt;--key&lt;/span&gt; /certs/tls.key &lt;span class="nt"&gt;--cert&lt;/span&gt; /certs/tls.crt
HTTP/2 200
server: gunicorn/19.9.0
&lt;span class="nb"&gt;date&lt;/span&gt;: Mon, 07 Nov 2022 10:58:55 GMT
content-type: application/json
content-length: 267
access-control-allow-origin: &lt;span class="k"&gt;*&lt;/span&gt;
access-control-allow-credentials: &lt;span class="nb"&gt;true
&lt;/span&gt;osm-stats-namespace: httpbin
osm-stats-kind: Deployment
osm-stats-name: httpbin
osm-stats-pod: httpbin-69dc7d545c-qphrh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bingo! The access is successful, indicating that our policy has taken effect&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;This blog post will talk about the approaches which can be used to enable services outside of the service mesh to communicate with services within the osm-edge service mesh. There may exist use cases where you have a specific set of services that aren't yet ready for migration to service mesh or for some reason can't be migrated yet.&lt;/p&gt;

&lt;p&gt;The access control approaches presented in this article are suitable for solving such problems, and allow you to choose the appropriate type of access source and whether to transfer data in plaintext or encrypted, depending on your needs. The control is more granular than using a unified Ingress for access.&lt;/p&gt;

</description>
      <category>servicemesh</category>
      <category>accesscontrol</category>
      <category>osmedge</category>
      <category>pipyproxy</category>
    </item>
    <item>
      <title>Pipy: Protecting Kubernetes Apps from SQL Injection &amp; XSS Attacks</title>
      <dc:creator>Ali Naqvi</dc:creator>
      <pubDate>Thu, 03 Nov 2022 13:12:06 +0000</pubDate>
      <link>https://dev.to/flomesh/pipy-protecting-kubernetes-apps-from-sql-injection-xss-attacks-dol</link>
      <guid>https://dev.to/flomesh/pipy-protecting-kubernetes-apps-from-sql-injection-xss-attacks-dol</guid>
      <description>&lt;p&gt;Injection attacks sliding down to 3rd position in 2021 have been on the &lt;a href="https://owasp.org/www-project-top-ten/" rel="noopener noreferrer"&gt;OWASP Top 10&lt;/a&gt; list for many years and SQL Injection (SQLi) is a common injection technique used for attacking websites and web applications. Applications that do not cleanly separate user input from database commands are at risk of malicious input being executed as SQL commands. Successful injection attacks can lead to unauthorized access to sensitive data such as passwords, credit card details, and personal user information. Many recent high-profile data breaches have resulted from SQL injection attacks, resulting in reputational damage and regulatory fines.&lt;/p&gt;

&lt;p&gt;The common and normal workaround which you might have seen with other solutions is using a list of &lt;strong&gt;regular expressions&lt;/strong&gt; to filter out traffic, which works for some cases but falls short with some complex inputs or escaped inputs. We are not trying to bash &lt;code&gt;Regular Expressions&lt;/code&gt;, they are good and have their own use cases, but they aren't a good fit for such use cases.&lt;/p&gt;

&lt;p&gt;This blog post will demonstrate how to use &lt;a href="https://flomesh.io" rel="noopener noreferrer"&gt;Pipy&lt;/a&gt; an open-source programmable proxy to harden the security by adding an extra layer of shield to your applications which might otherwise be vulnerable to such attacks.&lt;/p&gt;

&lt;p&gt;In a previous blog post announcing the latest release of &lt;a href="https://blog.flomesh.io/pipy-0-70-0-is-released-fe417b579fd2" rel="noopener noreferrer"&gt;Pipy 0.70.0&lt;/a&gt;, it was introduced that Pipy added the support of extensions called &lt;a href="https://flomesh.io/docs/en/reference/pjs/3-nmi" rel="noopener noreferrer"&gt;Native Module Interface (NMI)&lt;/a&gt; and we will be using Pipy NMI to develop a module to integrate with mature and stable open-source library &lt;a href="https://github.com/libinjection/libinjection" rel="noopener noreferrer"&gt;libinject&lt;/a&gt; to scan incoming traffic against SQLi and XSS attacks before it reaches the application.&lt;/p&gt;

&lt;p&gt;For the demo application, we will be using an open-source classical LAMP stack &lt;a href="https://hub.docker.com/r/naqvis/mamashop" rel="noopener noreferrer"&gt;Vulnerable Mama Shop (VMS)&lt;/a&gt; which is intentionally developed to have SQLi flaws. We will have fun together by first hacking the basic application to demonstrate the SQLi attacks, then we will harden the application security by adding Pipy as a sidecar to block certain SQLi attacks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pre-requisites
&lt;/h2&gt;

&lt;p&gt;This blog post assumes you have access to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Running Kubernetes cluster (dev box)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/tasks/tools/" rel="noopener noreferrer"&gt;kubectl&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;The demo source code is available on GitHub and can be downloaded from &lt;a href="https://github.com/flomesh-io/pipy-demos/tree/main/pipy-sqli-demo" rel="noopener noreferrer"&gt;pipy-sqli-demo&lt;/a&gt; repository.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Deploy Kubernetes cluster and Vulnerable Mama Shop App
&lt;/h2&gt;

&lt;p&gt;To run the demo locally, we recommend &lt;a href="https://k3d.io/" rel="noopener noreferrer"&gt;k3d&lt;/a&gt; a lightweight wrapper to run &lt;a href="https://github.com/rancher/k3s" rel="noopener noreferrer"&gt;k3s&lt;/a&gt; (Rancher Lab’s minimal Kubernetes distribution) in docker.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;k3d cluster create my-cluster &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:30060@server:0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above command, we are creating a cluster with a single server and mapping port 30060 of the k3d container to the local 8080 port, usage of this port will become clear in the later steps of this tutorial.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy Vulnerable Mama Shop App
&lt;/h2&gt;

&lt;p&gt;We are going to deploy a simple online store application that comes installed with&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Apache Webserver&lt;/li&gt;
&lt;li&gt;MariaDB&lt;/li&gt;
&lt;li&gt;PHP app that runs on Apache and connects to the MariaDB database&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Use the text editor of your choice and create a YAML file called 1-app.yaml with the following contents:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vms&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vms&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vms&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vms&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;naqvis/mamashop&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vms&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
      &lt;span class="na"&gt;nodePort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30060&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vms&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NodePort&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Deploy the app
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; 1-app.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Confirm that pod is up and running, as indicated by the value Running in the STATUS column. It can take 30-40 seconds for them to fully deploy, so it’s useful to run the command again to confirm all pods are running before continuing to the next step.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl get pods
NAME                   READY   STATUS    RESTARTS   AGE
vms-6658dd4478-hn246   1/1     Running   0          2m12s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Query the Servcice
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl get svc vms
NAME   TYPE       CLUSTER-IP      EXTERNAL-IP   PORT&lt;span class="o"&gt;(&lt;/span&gt;S&lt;span class="o"&gt;)&lt;/span&gt;        AGE
vms    NodePort   10.43.244.253   &amp;lt;none&amp;gt;        80:30060/TCP   5m43s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Still remember at the beginning we did port mapping for the K3d container: &lt;code&gt;8080=&amp;gt;30060&lt;/code&gt;? Keen users may also find that we have created a NodePort service for our Vulnerable Mama Shop web application, and the node port is &lt;code&gt;30060&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Open the app in your browser by visiting the URL &lt;strong&gt;&lt;a href="http://localhost:8080" rel="noopener noreferrer"&gt;http://localhost:8080&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd04tnbay6h9v6j2xjhc0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd04tnbay6h9v6j2xjhc0.jpg" alt="Vulnerable Mama Shop Welcome Page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Hack the App
&lt;/h2&gt;

&lt;p&gt;Mama Shop is rather very basic, it comes with only 3 pages. The main page (shown above) is where a user can query items for sale through a drop-down box, a customer login page, and an about page. Play around with these 3 pages to see what each does and how each page works normally.&lt;/p&gt;

&lt;p&gt;Try submitting a category and see how items are listed. The following shows a listing of items from the Drinks category.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo6kt3c7p6qpn2dwcn1hp.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo6kt3c7p6qpn2dwcn1hp.jpg" alt="Listing items in a Category"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you may have noticed, selecting a category and hitting submit doesn't change the URL, so the application is doing a &lt;code&gt;POST&lt;/code&gt; request and we will need some tool to intercept or view the traffic the web page is generating.&lt;/p&gt;

&lt;p&gt;Normally you will be using a proxy tool like Blurp suite or OWASP ZAP to intercept and modify the request to the application. But to keep things simple, we will be using Firefox browser Developer Console to view and modify the requests.&lt;/p&gt;

&lt;p&gt;Go back to your browser (Firefox in this demo) and turn on &lt;strong&gt;Web Developer Tools&lt;/strong&gt; either via &lt;code&gt;Tools | Browser Tools | Web Developer Tools&lt;/code&gt; menu option or via short-cut key &lt;code&gt;Option+Cmd+I&lt;/code&gt; on Mac or similar on your OS. Move to the &lt;code&gt;Network&lt;/code&gt; tab, and hit submit button on a web page to view the network traffic.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbedwcyffbqgmdv6u1lka.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbedwcyffbqgmdv6u1lka.jpg" alt="Firefox Web Developer Tool"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can see all of the requests along with all details, a web page makes to the webserver to display the page. Hit &lt;code&gt;Resend&lt;/code&gt; button at the top right of &lt;em&gt;Request details window&lt;/em&gt; displayed at the bottom right.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4d3dxv0ph9a56oajiaet.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4d3dxv0ph9a56oajiaet.png" alt="Web Developer Tools"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Network action window shows that to browse items in a category, a URL encoded HTTP POST with a single parameter &lt;code&gt;catid&lt;/code&gt; is sent to &lt;code&gt;welcome.php&lt;/code&gt;. To test for SQL injection, it is common to modify user input and send a single quotation mark like &lt;strong&gt;&lt;code&gt;'&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Modify Form Parameter
&lt;/h3&gt;

&lt;p&gt;We will find out if the input is properly escaped with a simple experiment: changing the &lt;code&gt;catid&lt;/code&gt; to a SQL query string, to see if it will cause a syntax error which may be shown on the webpage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;catid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;' or 1 = 1 ; --
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make above change and hit &lt;code&gt;send&lt;/code&gt; button at the bottom right of network action window.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjzhtw1k3ao5ptk5ewymj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjzhtw1k3ao5ptk5ewymj.png" alt="Web Developer Tools"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Whoa, we are upto something, &lt;code&gt;welcome.php&lt;/code&gt; function for displaying category items have a SQL injection vulnerability. The error message also tells us the database is &lt;strong&gt;MariaDB&lt;/strong&gt;. And error is telling us that there is a syntax issue near &lt;code&gt;or 1 = 1&lt;/code&gt;. Using our imaginations, we can assume the database query is something like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;item_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item_category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item_description&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;items_table&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;item_category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;' or 1 = 1 ; -- ;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we were to change the &lt;code&gt;catid&lt;/code&gt; ending to &lt;code&gt;" or 1 = 1 -- ;&lt;/code&gt;, that should fix the quoting issue. It should select all rows from the database, which is useful in a hack.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnbbvqvtpb471jeg1h5r4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnbbvqvtpb471jeg1h5r4.png" alt="Retrieving all rows"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The structure of the assumed SQL query is probably correct, although it is not necessarily the exact query that the developer has used. This is sufficient for devasting attacks such as dumping customer information.&lt;/p&gt;

&lt;h3&gt;
  
  
  Extract User Data
&lt;/h3&gt;

&lt;p&gt;The customer login page tells us that the application contains customer data and this is likely stored in some sort of customer or user table.&lt;/p&gt;

&lt;p&gt;Based on our information gathered so far we can make use of the MariaDB INFORMATION_SCHEMA and the SQL Union operator to retrieve database and tables details.&lt;/p&gt;

&lt;p&gt;Change &lt;code&gt;catid&lt;/code&gt; parameter to below to retrieve database name, which will be further used to retrieve table details.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;catid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="k"&gt;union&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="k"&gt;database&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nv"&gt;"A"&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"B"&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dual&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following shows the response from Vulnerable Mama Shop containing the database name, &lt;code&gt;appdb&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgffnpi0lntqebti4hchn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgffnpi0lntqebti4hchn.png" alt="Retrieving database name"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we have database name, we can obtain the tables in the database&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;catid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="k"&gt;union&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="k"&gt;table_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;table_comment&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;information_schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TABLES&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;table_schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'appdb'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So we get a list of all tables, We can safely assume &lt;code&gt;users&lt;/code&gt; table in the database contains usernames and passwords.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F95hfqfbew08v0nax2ko9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F95hfqfbew08v0nax2ko9.png" alt="Retrieving list of tables"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We need to retrieve list of columns &lt;code&gt;users&lt;/code&gt; table have and we will need to ensure that we use same number of columns as queried from products table for &lt;code&gt;UNION&lt;/code&gt; to work.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;catid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="k"&gt;union&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="k"&gt;table_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;COLUMN_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DATA_TYPE&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;information_schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;COLUMNS&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="k"&gt;table_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'users'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9j6q1wzlufvq79ctyfxl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9j6q1wzlufvq79ctyfxl.png" alt="Retrieving user table structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we know there are a total of six columns in the users table to contains details like firstname, lastname, nric, password, email are available from users table.&lt;/p&gt;

&lt;p&gt;We have gathered enough information to dump out a users listing. The following input can be used to dump out a listing of users with their firstname, password and email address.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;catid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="k"&gt;union&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="n"&gt;firstname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nric&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The values for the LIMIT and offset can be worked out by observing how many item entries there are in a normal request. The offset value should remove these items. The LIMIT can be set a sufficiently large value so that customer records can be dumped out.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ka41xiznqjd68a4yt4p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ka41xiznqjd68a4yt4p.png" alt="Dumping all users"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Play around and use these gathered information to see if you can login with these credentials.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Pipy Sidecar to block certain SQLi attacks
&lt;/h2&gt;

&lt;p&gt;SQL injection occurs when unvalidated user input is mixed with SQL instructions, so developers should pay more attention to escape user input (such as use of parameterized queries), but you  – the Kubernetes engineer  – can also help avoid SQL injection by preventing this attack from reaching the app. That way, even if the app is vulnerable, attacks can still be stopped.&lt;/p&gt;

&lt;p&gt;There are multiple options for protecting your apps, but for this blog post we will focus on &lt;strong&gt;injecting a sidecar container&lt;/strong&gt; to proxy all of the traffic and deny any request that is detected as SQLi attacks.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For demonstration purposes, we are following the approach of manually injecting sidecar, but in reality, &lt;strong&gt;manually deploying proxies as sidecars isn’t the best solution&lt;/strong&gt;. The complexity of your apps and architecture might require more fine–grain control. If your organization requires &lt;strong&gt;Zero Trust&lt;/strong&gt; and has a need for &lt;strong&gt;end–to–end encryption&lt;/strong&gt;, consider a service mesh like &lt;a href="https://flomesh.io" rel="noopener noreferrer"&gt;osm-edge&lt;/a&gt; a light weight, ultra fast, low resources, highly extensible,  Service Mesh Interface (SMI) compatible, built for edge and cloud computing service mesh.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Deploying Pipy Sidecar
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Create a YAML file called 2-app-sidecar.yaml with the contents below, and check out these noteworthy components:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;A sidecar container running Pipy is started on port 8000.&lt;/li&gt;
&lt;li&gt;The Pipy process forwards all traffic to the app.&lt;/li&gt;
&lt;li&gt;Requests URI or &lt;code&gt;POST&lt;/code&gt; body containing SQLi is declined&lt;/li&gt;
&lt;li&gt;The service for the app routes all traffic to the Pipy sidecar container first.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vms&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vms&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vms&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vms&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;naqvis/mamashop&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pipy&lt;/span&gt; &lt;span class="c1"&gt;# &amp;lt;-- sidecar&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;naqvis/pipy-nmi&lt;/span&gt;
          &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PIPY_CONFIG_FILE&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/etc/pipy/nmi/nmi.js&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8000&lt;/span&gt;
          &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/etc/pipy/nmi&lt;/span&gt;
              &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pipy-pjs&lt;/span&gt;
      &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pipy-pjs&lt;/span&gt;
          &lt;span class="na"&gt;configMap&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sidecar&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vms&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8000&lt;/span&gt; &lt;span class="c1"&gt;# &amp;lt;-- the traffic is routed to the proxy&lt;/span&gt;
      &lt;span class="na"&gt;nodePort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30060&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vms&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NodePort&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ConfigMap&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sidecar&lt;/span&gt;
&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;nmi.js&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|-&lt;/span&gt;
    &lt;span class="s"&gt;pipy({&lt;/span&gt;
      &lt;span class="s"&gt;_rejected: undefined,&lt;/span&gt;
    &lt;span class="s"&gt;})&lt;/span&gt;
      &lt;span class="s"&gt;.import({&lt;/span&gt;
        &lt;span class="s"&gt;__is_sqli: 'lib-inject',&lt;/span&gt;
        &lt;span class="s"&gt;__is_xss: 'lib-inject',&lt;/span&gt;
        &lt;span class="s"&gt;__sqli_fingerprint: 'lib-inject',&lt;/span&gt;
      &lt;span class="s"&gt;})&lt;/span&gt;
      &lt;span class="s"&gt;.listen(8000)&lt;/span&gt;
      &lt;span class="s"&gt;.demuxHTTP().to(&lt;/span&gt;
        &lt;span class="s"&gt;$=&amp;gt;$&lt;/span&gt;
            &lt;span class="s"&gt;.use('/etc/pipy/modules/inject-nmi.so')&lt;/span&gt;
            &lt;span class="s"&gt;.handleMessage(() =&amp;gt; _rejected = (__is_sqli || __is_xss))&lt;/span&gt;
            &lt;span class="s"&gt;.branch(&lt;/span&gt;
                &lt;span class="s"&gt;() =&amp;gt; _rejected === true, (&lt;/span&gt;
                &lt;span class="s"&gt;$=&amp;gt;$&lt;/span&gt;
                &lt;span class="s"&gt;.handleMessageStart(_ =&amp;gt;&lt;/span&gt;
                  &lt;span class="s"&gt;console.log(`SQL Injection found with Fingerprint: ${__sqli_fingerprint}`))&lt;/span&gt;
                &lt;span class="s"&gt;.replaceMessage(new Message({ status: 403 }, 'Forbidden'))&lt;/span&gt;
                &lt;span class="s"&gt;),&lt;/span&gt;
                &lt;span class="s"&gt;() =&amp;gt; _rejected === false, (&lt;/span&gt;
                  &lt;span class="s"&gt;$=&amp;gt;$.muxHTTP().to(&lt;/span&gt;
                      &lt;span class="s"&gt;$=&amp;gt;$.connect('localhost:80')&lt;/span&gt;
                  &lt;span class="s"&gt;)&lt;/span&gt;
                &lt;span class="s"&gt;)&lt;/span&gt;
            &lt;span class="s"&gt;)&lt;/span&gt;
      &lt;span class="s"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Deploy the side
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; 2-app-sidecar.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait for pods to be up and ready&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl get pods
NAME                  READY   STATUS    RESTARTS   AGE
vms-945f6f85c-8v7sb   2/2     Running   0          8m48s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Test the Sidecar
&lt;/h3&gt;

&lt;p&gt;Test whether the sidecar is filtering traffic by returning to the app and trying the SQL injection again. Pipy sidecar blocks the request before it reaches the app!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fumwww30b1jbj8mfhmql2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fumwww30b1jbj8mfhmql2.png" alt="Sidecar blocking SQLi traffic"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sidecar is blocking the traffic by returning &lt;strong&gt;403 Forbidden&lt;/strong&gt;. Run few more requests with any of the previous SQLi attempts we made and we will be getting 403 back in response.&lt;br&gt;
We can validate that by looking at the logs of Pipy side car.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F48b2h76sp13xqur33npn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F48b2h76sp13xqur33npn.png" alt="Sidecar logs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The purpose of learning about offensive techniques is to enable developers, defenders and security professionals to protect the confidentiality, the integrity and availability of critical information assets and services.&lt;/p&gt;

&lt;p&gt;Kubernetes is not secure by default. This blog post made use of Vulnerable Mama Shop, a simple application based on LAMP stack to demonstrate SQL injection attacks and how one can use techniques like SideCar to protect against them.&lt;/p&gt;

&lt;p&gt;But as the complexity of your apps and architecture grows, you might require more fine–grain control over your services. And if your organization requires Zero Trust and has a need for end–to–end encryption like mTLS, you should consider a service mesh like &lt;a href="https://flomesh.io" rel="noopener noreferrer"&gt;osm-edge&lt;/a&gt; a light weight, ultra fast, low resources, highly extensible,  Service Mesh Interface (SMI) compatible, built for edge and cloud computing service mesh. When you have communication between services (east–west traffic), a service mesh allows you to control traffic at that level.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>protection</category>
      <category>pipy</category>
      <category>sqlinjection</category>
    </item>
    <item>
      <title>Pipy 0.70.0 is released!</title>
      <dc:creator>Ali Naqvi</dc:creator>
      <pubDate>Fri, 21 Oct 2022 15:26:06 +0000</pubDate>
      <link>https://dev.to/flomesh/pipy-0700-is-released-13mj</link>
      <guid>https://dev.to/flomesh/pipy-0700-is-released-13mj</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;a href="https://flomesh.io"&gt;&lt;code&gt;Pipy&lt;/code&gt;&lt;/a&gt; 0.70.0&lt;/strong&gt; is now available. This release consists of 170+ commits and comes with improvements to several areas including support for writing Pipy modules using C via Pipy Native Module Interface (NMI), PJS language extensions like looping construct, Map, Set, etc, protocols like Thrift, PROXY, TPROXY, Output UDP with Ephemeral ports, Encoder/Decoder for DNS protocol,  and more. This version of Pipy comes with a fresh and new design of modules/plugin system, enhanced Pipy unique Admin Console, IDE is now more robust and supports more features like Intellisense, parameters highlighting, hints, etc.&lt;br&gt;
This release continues on the great work of previous releases and optimization is done for PipyJS and code readability, better documentation, and some bug fixes.&lt;/p&gt;

&lt;p&gt;This release was indeed a community effort and could not have been made possible without all of the hard work from everyone involved in active discussions and the Pipy project on GitHub.The Pipy community provides code submissions covering new functionality and bug fixes, documentation improvements, quality assurance testing, continuous integration environments, bug reports, and more. Everyone has done their part to make this release possible! If you’d like to join this amazing community, you can find it on GitHub, Slack, and the Pipy discussion groups.&lt;/p&gt;

&lt;p&gt;Below we list the most remarkable changes in the Core API and PipyJS. For a detailed change log, refer to &lt;a href="https://github.com/flomesh-io/pipy/releases/tag/0.70.0-2"&gt;Pipy Release Page&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Core
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;NMI (Native Module Interface) for dynamically loaded modules written in C&lt;/li&gt;
&lt;li&gt;New module/plugin system by using chain() filters&lt;/li&gt;
&lt;li&gt;Support loop logic in pipelines by using the new replay() filter&lt;/li&gt;
&lt;li&gt;Builtin GUI frontend greatly reduced in size by using Brotli compression&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Protocols
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Support Thrift protocol&lt;/li&gt;
&lt;li&gt;Support the Proxy protocol proposed by HAProxy&lt;/li&gt;
&lt;li&gt;Support outbound UDP with ephemeral local ports&lt;/li&gt;
&lt;li&gt;Support TPROXY on UDP&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  API
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Implementation of the standard ECMAScript builtin objects Map and Set&lt;/li&gt;
&lt;li&gt;Encode and decode DNS messages&lt;/li&gt;
&lt;li&gt;Logging API now supports HTTPS receivers and Syslog&lt;/li&gt;
&lt;li&gt;Expose subject alternative names of a certificate&lt;/li&gt;
&lt;li&gt;Mux filters to support limit of maximum messages per session&lt;/li&gt;
&lt;li&gt;Netmask API now supports IPv6&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Documentation &amp;amp; Samples
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Renovation of the documentation system by using TypeScript&lt;/li&gt;
&lt;li&gt;All new tutorials with complete API reference&lt;/li&gt;
&lt;li&gt;New samples for HTTP proxy common use cases&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We would like to thank each and every contributor who was involved in this release.&lt;/p&gt;

</description>
      <category>proxy</category>
      <category>pipy</category>
      <category>kubernetes</category>
      <category>programming</category>
    </item>
    <item>
      <title>Flomesh Ingress Controller with Kubernetes Multi-tenancy</title>
      <dc:creator>Ali Naqvi</dc:creator>
      <pubDate>Mon, 03 Oct 2022 13:10:34 +0000</pubDate>
      <link>https://dev.to/flomesh/flomesh-ingress-controller-with-kubernetes-multi-tenancy-1n09</link>
      <guid>https://dev.to/flomesh/flomesh-ingress-controller-with-kubernetes-multi-tenancy-1n09</guid>
      <description>&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;It's very rare for organizations to have or provide a dedicated Kubernetes cluster to each tenant, as it's generally more cost-effective to share a cluster. Sharing clusters reduces expenses and streamlines management. Sharing clusters, however, also comes with difficulties like managing noisy neighbors and ensuring security.&lt;/p&gt;

&lt;p&gt;Clusters can be shared in many ways. In some cases, different applications may run in the same cluster. In other cases, multiple instances of the same application may run in the same cluster, one for each end user. All these types of sharing are frequently described using the umbrella term &lt;em&gt;multi-tenancy&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;While Kubernetes does not have first-class concepts of end users or tenants, it provides several features to help manage different tenancy requirements. These are discussed below.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A common form of multi-tenancy is to share a cluster between multiple teams within an organization, each of whom may operate one or more workloads.  In this scenario, members of the teams often have direct access to Kubernetes resources via tools such as kubectl, or indirect access through GitOps controllers or other types of release automation tools. There is often some level of trust between members of different teams, but Kubernetes policies such as RBAC, quotas, and network policies are essential to safely and fairly share clusters.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The other major form of multi-tenancy frequently involves a Software-as-a-Service (SaaS) vendor running multiple instances of a workload for customers. This business model is so strongly associated with this deployment style that many people call it "SaaS tenancy." In this scenario, the customers do not have access to the cluster; Kubernetes is invisible from their perspective and is only used by the vendor to manage the workloads. Cost optimization is frequently a critical concern, and Kubernetes policies are used to ensure that the workloads are strongly isolated from each other.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Tenant Isolation
&lt;/h3&gt;

&lt;p&gt;There are several ways to design and build multi-tenant solutions with Kubernetes at its control plane, data plane, or at both levels. Each of these methods comes with its own set of tradeoffs that impact the isolation level, implementation effort, operational complexity, and cost of service.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Kubernetes Control plane isolation ensures that different tenants cannot access or affect each other's Kubernetes API resources, and Flomesh Service Mesh (FSM) Ingress controller provides isolated Ingress controllers for Kubernetes Namespaces.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In Kubernetes, a &lt;a href="https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces" rel="noopener noreferrer"&gt;Namespace&lt;/a&gt; provides a mechanism for isolating groups of API resources within a single cluster. This isolation has two key dimensions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Object names within a namespace can overlap with names in other namespaces, similar to files in folders. This allows tenants to name their resources without having to consider what other tenants are doing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Many Kubernetes security policies are scoped to namespaces. For example, RBAC Roles and Network Policies are namespace-scoped resources. Using RBAC, Users and Service Accounts can be restricted to a namespace.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In a multi-tenant environment, a Namespace helps segment a tenant's workload into a logical and distinct management unit. A common practice is to isolate every workload in its namespace, even if multiple workloads are operated by the same tenant. This ensures that each workload has its own identity and can be configured with an appropriate security policy.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In this article, we will learn how to use the Flomesh Service Mesh Ingress controller to create physical isolation of Ingress controllers when hosting multiple tenants in your Kubernetes cluster.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Flomesh Service Mesh (FSM)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/flomesh-io/fsm" rel="noopener noreferrer"&gt;FSM&lt;/a&gt; is an open-source product from &lt;a href="https://flomesh.io" rel="noopener noreferrer"&gt;Flomesh&lt;/a&gt; for Kubernetes north-south traffic, gateway API controller, and multi-cluster management. FSM uses &lt;a href="https://flomesh.io" rel="noopener noreferrer"&gt;Pipy&lt;/a&gt;, a programmable proxy at its core, and provides an Ingress controller, &lt;em&gt;Gateway API&lt;/em&gt; controller, load balancer, cross-cluster service registration discovery, and more.&lt;/p&gt;

&lt;p&gt;FSM Ingress Controller supports a multi-tenancy model via its concept of &lt;code&gt;NamespacedIngress&lt;/code&gt; CRD where it deploys a physically isolated &lt;strong&gt;Ingress Controller&lt;/strong&gt; for requested &lt;strong&gt;Namespace&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For example, the YAML below defines an Ingress Controller that monitors on port 100 and also creates a LoadBalancer type service for it that listens on port 100.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flomesh.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NamespacedIngress&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;namespaced-ingress-100&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test-100&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;serviceType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;LoadBalancer&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;
    &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq4o3bjzdc85h7je19drl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq4o3bjzdc85h7je19drl.png" alt="FSM NamespacedIngress"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Install FSM
&lt;/h3&gt;

&lt;p&gt;FSM provides a standard Helm chart, which can be installed via the Helm CLI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;helm repo add fsm https://flomesh-io.github.io/fsm
&lt;span class="nv"&gt;$ &lt;/span&gt;helm repo update

&lt;span class="nv"&gt;$ &lt;/span&gt;helm &lt;span class="nb"&gt;install &lt;/span&gt;fsm fsm/fsm &lt;span class="nt"&gt;--namespace&lt;/span&gt; flomesh &lt;span class="nt"&gt;--create-namespace&lt;/span&gt; &lt;span class="nt"&gt;--set&lt;/span&gt; fsm.ingress.namespaced&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify that all pods are up and running properly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl get po &lt;span class="nt"&gt;-n&lt;/span&gt; flomesh
NAME                                          READY   STATUS    RESTARTS   AGE
fsm-manager-6857f96858-sjksm                  1/1     Running   0          55s
fsm-repo-59bbbfdc5f-w7vg6                     1/1     Running   0          55s
fsm-bootstrap-8576c5ff4f-7qr7k                1/1     Running   0          55s
fsm-cluster-connector-local-8f8fb87f6-h7z9j   1/1     Running   0          32s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create Sample Application
&lt;/h3&gt;

&lt;p&gt;In this demo, we will be deploying &lt;code&gt;httpbin&lt;/code&gt; service under a namespace &lt;code&gt;httpbin&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create Namespace&lt;/span&gt;
kubectl create ns httpbin

&lt;span class="c"&gt;# Deploy sample&lt;/span&gt;
kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; https://raw.githubusercontent.com/flomesh-io/osm-edge-docs/main/manifests/samples/httpbin/httpbin.yaml &lt;span class="nt"&gt;-n&lt;/span&gt; httpbin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creating a standalone Ingress Controller&lt;/p&gt;

&lt;p&gt;The next step is to create a separate Ingress Controller for the namespace &lt;code&gt;httpbin&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;$ kubectl apply -f - &amp;lt;&amp;lt;EOF&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flomesh.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NamespacedIngress&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;namespaced-ingress-httpbin&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;httpbin&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;serviceType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;LoadBalancer&lt;/span&gt;
  &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;81&lt;/span&gt;
      &lt;span class="na"&gt;nodePort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30081&lt;/span&gt;
  &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;500m&lt;/span&gt;
      &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;200Mi&lt;/span&gt;
    &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;100m&lt;/span&gt;
      &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;20Mi&lt;/span&gt;
&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After executing the above command, you will see an Ingress Controller running successfully under the namespace httpbin.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get po &lt;span class="nt"&gt;-n&lt;/span&gt; httpbin &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;fsm-ingress-pipy
NAME                                        READY   STATUS    RESTARTS   AGE
fsm-ingress-pipy-httpbin-5594ffcfcc-zl5gl   1/1     Running   0          58s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, there should be a corresponding Service under this namespace.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl get svc &lt;span class="nt"&gt;-n&lt;/span&gt; httpbin &lt;span class="nt"&gt;-l&lt;/span&gt; app.kubernetes.io/component&lt;span class="o"&gt;=&lt;/span&gt;controller
NAME                       TYPE           CLUSTER-IP     EXTERNAL-IP    PORT&lt;span class="o"&gt;(&lt;/span&gt;S&lt;span class="o"&gt;)&lt;/span&gt;        AGE
fsm-ingress-pipy-httpbin   LoadBalancer   10.43.62.120   192.168.1.11   81:30081/TCP   2m49s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you have the Ingress Controller, it's time to create the Ingress resource.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;kubectl apply -f - &amp;lt;&amp;lt;EOF&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Ingress&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;httpbin&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;httpbin&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ingressClassName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pipy&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;httpbin.org&lt;/span&gt;
    &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt;
        &lt;span class="na"&gt;pathType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Prefix&lt;/span&gt;
        &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;httpbin&lt;/span&gt;
            &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;14001&lt;/span&gt;
&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have created Ingress resource, let's do a quick &lt;code&gt;curl&lt;/code&gt; to see if things are working as expected.&lt;/p&gt;

&lt;p&gt;For my local setup demo, LoadBalancer IP is &lt;code&gt;192.168.1.11&lt;/code&gt;, your IP might be different. So ensure you are performing a &lt;code&gt;curl&lt;/code&gt; against your setup ExternalIP.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sI&lt;/span&gt; http://192.168.1.11:81/get &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Host: httpbin.org"&lt;/span&gt;
HTTP/1.1 200 OK
server: gunicorn/19.9.0
&lt;span class="nb"&gt;date&lt;/span&gt;: Mon, 03 Oct 2022 12:02:04 GMT
content-type: application/json
content-length: 239
access-control-allow-origin: &lt;span class="k"&gt;*&lt;/span&gt;
access-control-allow-credentials: &lt;span class="nb"&gt;true
&lt;/span&gt;connection: keep-alive
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this blog post, you learned about Kubernetes multi-tenancy, features provided by Kubernetes, tenancy isolation levels, and how to use Flomesh Service Mesh (FSM) Ingress controller to set up isolated Ingress controller for namespaces.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/flomesh-io/fsm" rel="noopener noreferrer"&gt;Flomesh Service Mesh(FSM)&lt;/a&gt; from &lt;a href="https://flomesh.io" rel="noopener noreferrer"&gt;Flomesh&lt;/a&gt; is Kubernetes North-South traffic manager, provides Ingress controllers, Gateway API, Load Balancer, and cross-cluster service registration and service discovery. FSM uses &lt;a href="https://github.com/flomesh-io/pipy" rel="noopener noreferrer"&gt;Pipy&lt;/a&gt; - a programmable network proxy, as its data plane and is suitable for cloud, edge, and IoT.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>ingresscontroller</category>
      <category>pipy</category>
      <category>ingress</category>
    </item>
    <item>
      <title>Using FSM Ingress controller with osm-edge service mesh</title>
      <dc:creator>Ali Naqvi</dc:creator>
      <pubDate>Thu, 18 Aug 2022 15:18:11 +0000</pubDate>
      <link>https://dev.to/flomesh/using-fsm-ingress-controller-with-osm-edge-service-mesh-4moe</link>
      <guid>https://dev.to/flomesh/using-fsm-ingress-controller-with-osm-edge-service-mesh-4moe</guid>
      <description>&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;The Kubernetes Ingress API is designed with a separation of concerns, where the Ingress implementation provides an entry feature infrastructure managed by operations staff; it also allows application owners to control the routing of requests to the backend through rules.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/flomesh-io/osm-edge"&gt;osm-edge&lt;/a&gt; supports multiple Ingress implementations to manage ingress traffic and provides the &lt;code&gt;IngressBackend&lt;/code&gt; API to configure back-end services to receive access from trusted ingress points. This article focuses on the integration of osm-edge with &lt;a href="https://github.com/flomesh-io/fsm"&gt;FSM&lt;/a&gt; to manage ingress traffic.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RiatVQWC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s49fww6fvf1r8rkiueoc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RiatVQWC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s49fww6fvf1r8rkiueoc.png" alt="FSM" width="880" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Introduction to FSM
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/flomesh-io/fsm"&gt;FSM&lt;/a&gt; is another open-source product from &lt;a href="https://flomesh.io"&gt;Flomesh&lt;/a&gt; for Kubernetes north-south traffic, gateway api contoller, and multi-cluster management. FSM uses &lt;a href="https://flomesh.io"&gt;Pipy&lt;/a&gt;, a programmable proxy at its core, and provides an Ingress controller, &lt;em&gt;Gateway API&lt;/em&gt; controller, load balancer, cross-cluster service registration discovery, and more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integration with FSM
&lt;/h2&gt;

&lt;p&gt;FSM is already integrated inside osm-edge and can be enabled during osm-edge installation; it can also be installed independently via helm for existing osm-edge mesh.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Kubernetes cluster, version 1.19.0 and higher&lt;/li&gt;
&lt;li&gt;Helm 3 CLI for standalone installation of FSM&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Download the osm-edge CLI at&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;system&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;:upper:] &lt;span class="o"&gt;[&lt;/span&gt;:lower:]&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;arch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;dpkg &lt;span class="nt"&gt;--print-architecture&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;release&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;v1.1.1
curl &lt;span class="nt"&gt;-L&lt;/span&gt; https://github.com/flomesh-io/osm-edge/releases/download/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;release&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/osm-edge-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;release&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;system&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;arch&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;.tar.gz | &lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-vxzf&lt;/span&gt; -
&lt;span class="nb"&gt;.&lt;/span&gt; /&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;system&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;arch&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/osm version
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; /&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;system&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;arch&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/osm /usr/local/bin/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Integrated installation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;osm_namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;osm-system 
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;osm_mesh_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;osm 

osm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--set&lt;/span&gt; fsm.enabled&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--mesh-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$osm_mesh_name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--osm-namespace&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$osm_namespace&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Standalone installation
&lt;/h3&gt;

&lt;p&gt;If osm-edge is installed without FSM enabled, you can use a standalone installation to install it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm repo add fsm https://charts.flomesh.io

&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;fsm_namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;osm-system 
helm &lt;span class="nb"&gt;install &lt;/span&gt;fsm fsm/fsm &lt;span class="nt"&gt;--namespace&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$fsm_namespace&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--create-namespace&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify that all pods are up and running properly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; osm-system
NAME READY STATUS RESTARTS AGE
repo-8756f76fb-2f78g 1/1 Running 0 5m53s
manager-866585bbd5-pbg7q 1/1 Running 0 5m53s
osm-bootstrap-7c6689ff57-47ksk 1/1 Running 0 5m53s
osm-controller-57888cfc7c-tnqxl 2/2 Running 0 5m52s
osm-injector-5f77898899-45f65 1/1 Running 0 5m53s
bootstrap-fd5894bcc-nr7hf 1/1 Running 0 5m53s
cluster-connector-local-68c7584c8b-qf7xm 1/1 Running 0 2m43s
ingress-pipy-6fb8c8b794-pgthl 1/1 Running 0 5m53s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configuration
&lt;/h3&gt;

&lt;p&gt;In order to authorize clients by restricting access to backend traffic, we will configure &lt;code&gt;IngressBackend&lt;/code&gt; so that only ingress traffic from the &lt;code&gt;ingress-pipy-controller&lt;/code&gt; endpoint can be routed to the backend service. In order to discover the &lt;code&gt;ingress-pipy-controller&lt;/code&gt; endpoint, we need the &lt;code&gt;osm-edge controller&lt;/code&gt; and the corresponding namespace to monitor it. However, to ensure that the FSM functions properly, it cannot be injected with sidecar.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl label namespace &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$osm_namespace&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; openservicemesh.io/monitored-by&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$osm_mesh_name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the external IP address and port of the entry gateway, which will be used later to test access to the backend application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ingress_host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$osm_namespace&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; get service ingress-pipy-controller &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.status.loadBalancer.ingress[0].ip}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; "&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ingress_port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$osm_namespace&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; get service ingress-pipy-controller &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.spec.ports[? (@.name=="http")].port}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$ingress_host&lt;/span&gt;:&lt;span class="nv"&gt;$ingress_port&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deploying the sample service
&lt;/h2&gt;

&lt;p&gt;The next step is to deploy the sample &lt;code&gt;httpbin&lt;/code&gt; service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;## Create namespace kubectl create ns httpbin&lt;/span&gt;
kubectl create ns httpbin

&lt;span class="c"&gt;# Add the namespace to the grid&lt;/span&gt;
osm namespace add httpbin

&lt;span class="c"&gt;# Deploy the application&lt;/span&gt;
kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
apiVersion: v1
kind: ServiceAccount
metadata:
  name: httpbin
  namespace: httpbin
---
apiVersion: v1
kind: Service
metadata:
  name: httpbin
  namespace: httpbin
  labels:
    app: httpbin
    service: httpbin
spec:
  ports:
  - name: http
    port: 14001
  selector:
    app: httpbin
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpbin
  namespace: httpbin
spec:
  replicas: 1
  selector:
    matchLabels:
      app: httpbin
  template:
    metadata:
      labels:
        app: httpbin
    spec:
      serviceAccountName: httpbin
      containers:
      - image: kennethreitz/httpbin
        imagePullPolicy: IfNotPresent
        name: httpbin
        command: ["gunicorn", "-b", "0.0.0.0:14001", "httpbin:app", "-k", "gevent"]
        ports:
        - containerPort: 14001
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify that the pod and service are created and the application is running successfully.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods,services &lt;span class="nt"&gt;-n&lt;/span&gt; httpbin
NAME READY STATUS RESTARTS AGE
pod/httpbin-54cc8cf5d-7vclc 2/2 Running 0 14s

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT&lt;span class="o"&gt;(&lt;/span&gt;S&lt;span class="o"&gt;)&lt;/span&gt; AGE
service/httpbin ClusterIP 10.43.105.166 &amp;lt;none&amp;gt; 14001/TCP 14s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configure entry rules
&lt;/h2&gt;

&lt;p&gt;Next we want to access the deployed &lt;code&gt;httpbin&lt;/code&gt; service from outside the cluster and need to provide the ingress configuration rules.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: httpbin
  namespace: httpbin
  annotations:
    pipy.ingress.kubernetes.io/rewrite-target-from: /httpbin
    pipy.ingress.kubernetes.io/rewrite-target-to: /httpbin
spec:
  ingressClassName: pipy
  rules:
  - host: httpbin.org
    http:
      paths:
      - path: /httpbin
        pathType: Prefix
        backend:
          service:
            name: httpbin
            port:
              number: 14001
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Accessing the &lt;code&gt;httpbin&lt;/code&gt; service using the IP address and port recorded above will result in the following &lt;code&gt;502 Bad Gateway&lt;/code&gt; error response. This is because we have not set the ingress of the FSM as a trusted portal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sI&lt;/span&gt; http://&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ingress_host&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;:&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ingress_port&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;/httpbin/get &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Host: httpbin.org"&lt;/span&gt;
HTTP/1.1 502 Bad Gateway
content-length: 0
connection: keep-alive
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Execute the following command to set the FSM ingress as a trusted entry.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
kind: IngressBackend
apiVersion: policy.openservicemesh.io/v1alpha1
metadata:
  name: httpbin
  namespace: httpbin
spec:
  backends:
  - name: httpbin
    port:
      number: 14001 # targetPort of httpbin service
      protocol: http
  sources:
  - kind: Service
    namespace: "&lt;/span&gt;&lt;span class="nv"&gt;$osm_namespace&lt;/span&gt;&lt;span class="sh"&gt;"
    name: ingress-pipy-controller
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Try requesting the &lt;code&gt;httpbin&lt;/code&gt; service again, and you will be able to access it successfully.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sI&lt;/span&gt; http://&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ingress_host&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;:&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ingress_port&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;/httpbin/get &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Host: httpbin.org"&lt;/span&gt;
HTTP/1.1 200 OK
server: gunicorn/19.9.0
&lt;span class="nb"&gt;date&lt;/span&gt;: Thu, 18 Aug 2022 05:18:50 GMT
content-type: application/json
content-length: 241
access-control-allow-origin: &lt;span class="k"&gt;*&lt;/span&gt;
access-control-allow-credentials: &lt;span class="nb"&gt;true
&lt;/span&gt;osm-stats-namespace: httpbin
osm-stats-kind: Deployment
osm-stats-name: httpbin
osm-stats-pod: httpbin-54cc8cf5d-7vclc
connection: keep-alive
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;FSM Ingress exposes the application access points within the Kubernetes cluster for easy management of portal traffic. osm-edge's IngressBackend API provides an additional line of defense against accidental data leakage by exposing services within the mesh to the public.&lt;/p&gt;

</description>
      <category>ingress</category>
      <category>servicemesh</category>
      <category>pipy</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Benchmarking osm and osm-edge data planes</title>
      <dc:creator>Ali Naqvi</dc:creator>
      <pubDate>Sun, 07 Aug 2022 04:51:14 +0000</pubDate>
      <link>https://dev.to/flomesh/benchmarking-osm-and-osm-edge-data-planes-3c65</link>
      <guid>https://dev.to/flomesh/benchmarking-osm-and-osm-edge-data-planes-3c65</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/flomesh-io/osm-edge"&gt;osm-edge&lt;/a&gt; is built on top of &lt;a href="https://github.com/openservicemesh/osm/tree/release-v1.1"&gt;Open Service Mesh (OSM) v1.1.0&lt;/a&gt; codebase and is a lightweight service mesh for resource-sensitive cloud environments and edge computing scenarios. It uses osm as the control plane and &lt;a href="https://flomesh.io"&gt;Pipy&lt;/a&gt; as the data plane and features high performance, low resources, simplicity, ease of use, scalability, and compatibility (x86/arm64 support).&lt;/p&gt;

&lt;p&gt;osm-edge is a simple, complete, and standalone &lt;a href="https://en.wikipedia.org/wiki/Service_mesh"&gt;service mesh&lt;/a&gt; and ships out-of-the-box with all the necessary components to deploy a complete service mesh. As a lightweight and &lt;a href="https://smi-spec.io/"&gt;SMI&lt;/a&gt;-compatible Service Mesh, osm-edge is designed to be intuitive and scalable.&lt;/p&gt;

&lt;p&gt;For detailed introduction and documentation, refer to &lt;a href="https://osm-edge-docs.flomesh.io"&gt;osm-edge documentation&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;In this experiment, benchmarks were conducted for osm-edge(pipy) (v1.1.0) and osm(envoy) (v1.1.0). The main focus is on service TPS, latency distribution when using two different meshes, and monitoring the resource overhead of the data plane.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;osm-edge uses Pipy as the data plane; osm uses Envoy as the data plane.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Testing Environment
&lt;/h2&gt;

&lt;p&gt;The benchmark was performed in a Kubernetes cluster running on Cloud. Cluster comprised of 2 worker nodes and one load generator node. Software and hardware configurations as below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Kubernetes: k3s v1.20.14+k3s2&lt;/li&gt;
&lt;li&gt;OS: Ubuntu 20.04&lt;/li&gt;
&lt;li&gt;Nodes: 16c32g * 2&lt;/li&gt;
&lt;li&gt;Load Generator: 8c16g&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What features were tested?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Both meshes had permissive traffic mode enabled&lt;/li&gt;
&lt;li&gt;Both meshes had mutual TLS enabled and were encrypting traffic and validating identity between all application pods.&lt;/li&gt;
&lt;li&gt;Both meshes were reporting metrics, including L7 metrics, though these metrics were not consumed in this experiment.&lt;/li&gt;
&lt;li&gt;Both meshes logged various messages at the INFO level by default. We did not configure logging.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What application was used for testing?
&lt;/h3&gt;

&lt;p&gt;The test application uses the common SpringCloud microservices architecture. The application code is taken from &lt;a href="https://github.com/flomesh-io/flomesh-bookinfo-demo/"&gt;flomesh-bookinfo-demo&lt;/a&gt;, which is a SpringCloud implementation of bookinfo application using SpringCloud. In the tests, not all services were used, but rather the API gateway and the Bookinfo Ratings service were selected.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iR7MhVlF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/2224492/178288704-3aa44151-4c57-4538-9a0a-55310bb4f200.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iR7MhVlF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/2224492/178288704-3aa44151-4c57-4538-9a0a-55310bb4f200.png" alt="applications" width="880" height="485"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;External access to the service is provided through Ingress; the load generator uses the common Apache Jmeter 5.5.&lt;/p&gt;

&lt;p&gt;For the tests, 2 paths were chosen: one is the direct access to the Bookinfo Ratings service via Ingress (hereafter ratings), and the other passes through the API Gateway (hereafter gateway-ratings) in the middle. The reason for choosing these two paths is to cover both single-sidecar and multiple-sidecar scenarios.&lt;/p&gt;

&lt;h2&gt;
  
  
  Procedure
&lt;/h2&gt;

&lt;p&gt;We start the test with a non-mesh (i.e., no sidecar injection, hereafter referred to as non-mesh), and then test with osm-edge(pipy) and osm(envoy) mesh, respectively.&lt;/p&gt;

&lt;p&gt;To simulate the resource-constrained scenario of the edge, the CPU used by the sidecar is limited when using the mesh, and the 1 core and 2 core scenarios are tested respectively.&lt;/p&gt;

&lt;p&gt;Thus, there are 5 rounds of testing, with 2 different tests in each round.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;p&gt;Jmeter uses 200 threads during the test and runs the test for 5 minutes. Each round of testing is preceded by a 2-minute warm-up.&lt;/p&gt;

&lt;p&gt;For sake of verbosity, only the results of the gateway-ratings paths are shown below with different sidecar resource constraints.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: The sidecar in the table refers to the API Gateway sidecar&lt;/em&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;mesh&lt;/th&gt;
&lt;th&gt;sidecar max CPU&lt;/th&gt;
&lt;th&gt;TPS&lt;/th&gt;
&lt;th&gt;90th&lt;/th&gt;
&lt;th&gt;95th&lt;/th&gt;
&lt;th&gt;99th&lt;/th&gt;
&lt;th&gt;sidecar CPU usage&lt;/th&gt;
&lt;th&gt;sidecar memory usage&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;non-mesh&lt;/td&gt;
&lt;td&gt;NA&lt;/td&gt;
&lt;td&gt;3283&lt;/td&gt;
&lt;td&gt;87&lt;/td&gt;
&lt;td&gt;89&lt;/td&gt;
&lt;td&gt;97&lt;/td&gt;
&lt;td&gt;NA&lt;/td&gt;
&lt;td&gt;NA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;osm-edge(pipy)&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;3395&lt;/td&gt;
&lt;td&gt;77&lt;/td&gt;
&lt;td&gt;79&lt;/td&gt;
&lt;td&gt;84&lt;/td&gt;
&lt;td&gt;130%&lt;/td&gt;
&lt;td&gt;52&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;osm(envoy)&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2189&lt;/td&gt;
&lt;td&gt;102&lt;/td&gt;
&lt;td&gt;104&lt;/td&gt;
&lt;td&gt;109&lt;/td&gt;
&lt;td&gt;200%&lt;/td&gt;
&lt;td&gt;108&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;osm-edge(pipy)&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2839&lt;/td&gt;
&lt;td&gt;76&lt;/td&gt;
&lt;td&gt;77&lt;/td&gt;
&lt;td&gt;79&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;34&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;osm(envoy)&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1097&lt;/td&gt;
&lt;td&gt;201&lt;/td&gt;
&lt;td&gt;203&lt;/td&gt;
&lt;td&gt;285&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;105&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Sidecar with 2 CPU core limitations
&lt;/h3&gt;

&lt;p&gt;In the sidecar 2-core scenario, using the osm-edge(pipy) mesh gives a small TPS improvement over not using the mesh, and also improves latency. Improvement of TPS and latency is due the fact that Java NIO uses reactor pattern, while Pipy is built on C++ ASIO which uses the proactor pattern and the connection from Pipy to Java are long duplex connections. The sidecar for both API Gateway and Bookinfo Ratings is still not running out of 2 cores (only 65%), when the Bookinfo Ratings service itself is at its performance limit.&lt;/p&gt;

&lt;p&gt;The TPS of the osm(envoy) mesh was down nearly 30%, and the API Gateway sidecar CPU was running full, which was the bottleneck.&lt;/p&gt;

&lt;p&gt;In terms of memory, the memory usage of osm-edge(pipy) and osm(envoy) sidecar is 50 MiB and 105 MiB respectively, meaning osm-edge(pipy) was utilizing 52% less memory than osm(envoy).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TPS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--znxT7lq---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/2224492/178294418-d3d63aef-8c54-49e4-a40e-8bacdec26f74.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--znxT7lq---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/2224492/178294418-d3d63aef-8c54-49e4-a40e-8bacdec26f74.png" alt="TPS" width="880" height="251"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Latency distribution&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jGZq9Pno--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/2224492/178294471-b8e1b3c6-a8fd-47cb-872a-0c40418b0da7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jGZq9Pno--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/2224492/178294471-b8e1b3c6-a8fd-47cb-872a-0c40418b0da7.png" alt="Latency distribution" width="880" height="251"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;API gateway sidecar CPU usage&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3VlO71Rn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/2224492/178294732-73aaa9f4-e159-4b8e-ab12-521985313358.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3VlO71Rn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/2224492/178294732-73aaa9f4-e159-4b8e-ab12-521985313358.png" alt="API gateway sidecar cpu usage" width="880" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;API gateway sidecar memory footprint&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uY0s485n--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/2224492/178294829-9d2f0794-12e7-4cd6-827d-11af8b632db9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uY0s485n--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/2224492/178294829-9d2f0794-12e7-4cd6-827d-11af8b632db9.png" alt="API gateway sidecar memory footprint" width="880" height="406"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bookinfo Ratings sidecar CPU usage&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uZFqg4r_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/2224492/178295086-6380004f-369d-4f6b-afeb-71b48c0e3053.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uZFqg4r_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/2224492/178295086-6380004f-369d-4f6b-afeb-71b48c0e3053.png" alt="Bookinfo Ratings sidecar CPU usage" width="880" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bookinfo Ratings sidecar memory usage&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--N2s4Z553--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/2224492/178295267-004e7676-04b5-4fef-8e5d-ca196bd7dedc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--N2s4Z553--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/2224492/178295267-004e7676-04b5-4fef-8e5d-ca196bd7dedc.png" alt="Bookinfo Ratings sidecar memory usage" width="880" height="406"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Sidecar with 1 CPU core limitation
&lt;/h3&gt;

&lt;p&gt;The difference is particularly noticeable in tests that limit the sidecar to 1 core CPU. At this point, the API Gateway sidecar becomes the performance bottleneck, with both the osm-edge and osm sidecar running out of CPU.&lt;/p&gt;

&lt;p&gt;In terms of TPS, osm-edge(Pipy) drops by 12% and osm(Envoy)'s TPS drops by a staggering 65%.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TPS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8nC49CDy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/2224492/178295573-8be92413-d499-476e-b3e1-a23d0bcbcda3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8nC49CDy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/2224492/178295573-8be92413-d499-476e-b3e1-a23d0bcbcda3.png" alt="1 CPU TPS" width="880" height="251"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Latency distribution&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--y0Dj7VtV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/2224492/178296728-c7ea9a12-d9d4-4be0-9c8d-32bb91724f36.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--y0Dj7VtV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/2224492/178296728-c7ea9a12-d9d4-4be0-9c8d-32bb91724f36.png" alt="1c Latency distribution" width="880" height="251"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;API gateway sidecar CPU usage&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--21a8TOOH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/2224492/178300176-0a76080b-3bcb-48f4-a506-4a105ad8c4a8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--21a8TOOH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/2224492/178300176-0a76080b-3bcb-48f4-a506-4a105ad8c4a8.png" alt="1c API gateway sidecar CPU usage" width="880" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;API gateway sidecar memory footprint&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Zkdihj_W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/2224492/178300241-95917e41-5857-4a80-8234-ff6533310ef5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Zkdihj_W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/2224492/178300241-95917e41-5857-4a80-8234-ff6533310ef5.png" alt="1c API gateway sidecar memory footprint" width="880" height="406"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bookinfo Ratings sidecar CPU usage&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eqVkarur--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/2224492/178300596-2f767c75-6872-4aa5-b943-a3eeae84c55e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eqVkarur--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/2224492/178300596-2f767c75-6872-4aa5-b943-a3eeae84c55e.png" alt="1c Bookinfo Ratings sidecar CPU usage" width="880" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bookinfo Ratings sidecar memory usage&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--i8RWD5rl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/2224492/178300658-53bdf00d-6f2f-484a-8c3f-0399f9b683ed.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--i8RWD5rl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/2224492/178300658-53bdf00d-6f2f-484a-8c3f-0399f9b683ed.png" alt="1c Bookinfo Ratings sidecar memory usage" width="880" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;The focus of this experiment was to benchmark the performance and resource consumption of both meshes in a resource-constrained environment. Experiment results revealed that osm-edge maintained high performance and made efficient use of allocated resources. This experiment proves that complete service mesh functionalities can be used and utilized for resource-constrained edge scenarios.&lt;/p&gt;

&lt;p&gt;osm-edge is well-suited and ready for both cloud and resource-sensitive environments.&lt;/p&gt;

</description>
      <category>benchmark</category>
      <category>osm</category>
      <category>osmedge</category>
      <category>servicemesh</category>
    </item>
    <item>
      <title>Announcing osm-edge 1.1: ARM support and more</title>
      <dc:creator>Ali Naqvi</dc:creator>
      <pubDate>Thu, 28 Jul 2022 13:19:04 +0000</pubDate>
      <link>https://dev.to/flomesh/announcing-osm-edge-11-arm-support-and-more-49j2</link>
      <guid>https://dev.to/flomesh/announcing-osm-edge-11-arm-support-and-more-49j2</guid>
      <description>&lt;p&gt;We're very happy to announce the release of &lt;a href="https://github.com/flomesh-io/osm-edge"&gt;osm-edge 1.1&lt;/a&gt;. This release is the culmination of months of effort from the &lt;a href="https://flomesh.io"&gt;flomesh.io&lt;/a&gt; team and we are very excited to unveil it today. osm-edge is built on top of &lt;a href="https://github.com/openservicemesh/osm/tree/release-v1.1"&gt;Open Service Mesh v1.1.0&lt;/a&gt; codebase and is built purposely for edge computing and uses lightweight, high-performant, cloud native, and programmable proxy &lt;a href="https://flomesh.io"&gt;Pipy&lt;/a&gt; as its data plane and sidecar proxy.&lt;/p&gt;

&lt;p&gt;osm-edge is a simple, complete, and standalone &lt;a href="https://en.wikipedia.org/wiki/Service_mesh"&gt;service mesh&lt;/a&gt; and ships out-of-the-box with all the necessary components to deploy a complete service mesh. As a lightweight and &lt;a href="https://smi-spec.io/"&gt;SMI&lt;/a&gt;-compatible Service Mesh, osm-edge is designed to be intuitive and scalable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why osm-edge?
&lt;/h2&gt;

&lt;p&gt;In practice, we have encountered users from a variety of industries with similar requirements for service mesh. These industry users and scenarios include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Energy and power companies. They want to build simple server rooms at each substation or gas station to deploy computing and storage capacity for the processing of data generated by devices within the coverage area of that location. They want to push traditional data center applications to these simple rooms and take full advantage of data center application management and operation capabilities&lt;/li&gt;
&lt;li&gt;Telematics service providers. They want to build their simple computing environments in non-data center environments for data collection and service delivery to cars and vehicle owners. These environments may be near highway locations, parking lots, or high-traffic areas&lt;/li&gt;
&lt;li&gt;Retailers. They want to build a minimal computing environment in each store, and in addition to supporting traditional capabilities such as inventory, sales, and payment collection, they also hope to introduce new capabilities of data collection, processing, and transmission&lt;/li&gt;
&lt;li&gt;Medical institutions. They want to provide network capabilities at every hospital, or a simple point of care, so that in addition to providing digital service capability for patients, they can also complete data collection and data linkage with higher management departments at the same time&lt;/li&gt;
&lt;li&gt;Teaching institutions, hospitals, and campuses alike. These campuses are characterized by a relatively regular and dense flow of people. They want to deploy computing resources near more crowd gathering points for delivering digital services, as well as collecting and processing data in real-time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are typical edge computing scenarios, and they have similar needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Users want to bring the traditional data center computing model, especially microservices, and the related application delivery, management operation, and maintenance capabilities to the edge side&lt;/li&gt;
&lt;li&gt;In terms of the working environment, users have to deal with factors such as power supply, limited computing power, and unstable network. Therefore, computing platforms are required to be more robust and can be deployed quickly or recover a computing environment completely in extreme situations&lt;/li&gt;
&lt;li&gt;The number of locations (we call &lt;strong&gt;POP&lt;/strong&gt;=&lt;code&gt;Point of Presence&lt;/code&gt;) that usually need to be deployed is large and constantly evolving and expanding. The cost of a POP point, the price of maintenance, and the price of expansion are all important cost considerations.&lt;/li&gt;
&lt;li&gt;Common, or low-end, PC servers are more often used in these scenarios to replace cloud-standard servers; low-power technology-based computing power such as ARM is further replacing low-end PC servers. On these hardware platforms, which are not comparable to cloud-standard servers, users still want to have enough computing power to handle the growth in functionality and data volume. The conflicting demands of computing moving closer to where the data is generated, the growth in data volume and functional requirements at the edge, and the limited computing resources at the edge require edge-side computing platforms to have better computing power efficiency ratios, i.e., running more applications and supporting larger data volumes with as little power and as few servers as possible&lt;/li&gt;
&lt;li&gt;The fragility and a large number of POP points require better application support for multi-cluster, cross-POP failover. For example, if a POP point fails, the neighboring POP points can quickly share or even temporarily take over the computing tasks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Compared with the cloud data center computing scenario, the three core and main differences and difficulties of edge computing are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Edge computing requires support for heterogeneous hardware architectures. We see non-x86 computing power being widely used at the edge, often with the advantage of low power consumption and low cost&lt;/li&gt;
&lt;li&gt;Edge computing POP points are fragile. This fragility is reflected in the fact that they may not have an extremely reliable power supply, or the power supply is not as powerful as a data center; they may operate in a worse environment than the constant temperature and ventilation of a data center; their networks may be narrowband and unstable&lt;/li&gt;
&lt;li&gt;Edge computing is naturally distributed computing. In almost all edge computing scenarios, there are multiple POP points, and the number of POP points is continuously increasing. the POP points can disaster-proof each other and migrate to adjacent POP points in case of failure, which is a fundamental capability of edge computing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The evolution of Kubernetes to the edge side solves the difficulties of edge computing to a certain extent, especially against fragility; while the development of service mesh to the edge side focuses on network issues in edge computing, against network fragility, as well as providing basic network support for distributed, such as fault migration. In practice, container platforms, as today's de facto quasi-standard means of application delivery, are rapidly evolving to the edge side,  with a large number of releases targeting edge features, such as &lt;a href="https://k3s.io"&gt;k3s&lt;/a&gt;; but service mesh, as an important network extension for container platforms, are not quickly keeping up with this trend. It is currently difficult for users to find service mesh for edge computing scenarios, so we started the &lt;a href="https://github.com/flomesh-io/osm-edge"&gt;osm-edge&lt;/a&gt; an open source project with several important considerations and goals, namely&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Support and compatibility with the SMI specification, so that it can meet users' needs for standardization of service mesh management&lt;/li&gt;
&lt;li&gt;Full support for the ARM ecosystem, which is the "first-class citizen" or even the preferred computing platform for edge computing, and the Service Mesh should be fully adapted to meet this trend. &lt;a href="https://github.com/flomesh-io/osm-edge"&gt;osm-edge&lt;/a&gt; follows the &lt;strong&gt;ARM First&lt;/strong&gt; strategy, which means that all features are developed, tested, and delivered on the ARM platform first&lt;/li&gt;
&lt;li&gt;High performance and low resources. The service mesh as infrastructure should use fewer resources (CPU/MEM) while delivering higher performance (TPS/Latency) at the edge.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Light-weight, high-performant, cloud-native, extensible&lt;/li&gt;
&lt;li&gt;Out-of-the-box supports x86, ARM architectures&lt;/li&gt;
&lt;li&gt;Easily and transparently configure traffic shifting for deployments&lt;/li&gt;
&lt;li&gt;Secure service-to-service communication by enabling mutual TLS&lt;/li&gt;
&lt;li&gt;Define and execute fine-grained access control policies for services&lt;/li&gt;
&lt;li&gt;Observability and insights into application metrics for debugging and monitoring services&lt;/li&gt;
&lt;li&gt;Integrate with external certificate management services/solutions with a pluggable interface&lt;/li&gt;
&lt;li&gt;Onboard applications onto the mesh by enabling automatic sidecar injection of Pipy proxy&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ARM Support
&lt;/h2&gt;

&lt;p&gt;osm-edge 1.1 brings the oft-requested support for ARM (both for development &amp;amp; production use), Whether you’re focused on cost reduction with ARM-based compute such as AWS Graviton or simply want to run service mesh on your Raspberry Pi cluster, now you can!&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-cluster Kubernetes the Kubernetes way
&lt;/h2&gt;

&lt;p&gt;osm-edge 1.1 comes bundled with &lt;a href="https://github.com/flomesh-io/fsm"&gt;Flomesh Service Mesh (FSM)&lt;/a&gt; a Kubernetes North-South traffic manager, provides Ingress controllers, Gateway API, Load Balancer, and cross-cluster service registration and service discovery.&lt;/p&gt;

&lt;p&gt;With the help of FSM, osm-edge can now connect Kubernetes services across cluster boundaries in a way that’s secure, fully transparent to the application, and independent of network topology. Automated fail-over ability to automatically redirect all traffic from a failing or inaccessible service to one or more replicas of that service—including replicas on other clusters. &lt;/p&gt;

&lt;h2&gt;
  
  
  Multiple Sidecar Proxy support
&lt;/h2&gt;

&lt;p&gt;To break the tight coupling on Pipy and open doors for 3rd parties to develop or make use of their data plane or sidecar proxies, we have refactored the &lt;code&gt;OSM v1.1.0&lt;/code&gt; codebase to make it generic and provide extension points. We strongly believe in and support open source and our &lt;a href="https://github.com/openservicemesh/osm/issues/4874"&gt;proposal&lt;/a&gt; for this refactoring have been submitted to upstream for their review, discussion, and/or utilization.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--f1ZcRxqf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/95846930/175471277-30c65994-af30-4eef-ab15-f9ac1f9ace64.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--f1ZcRxqf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/95846930/175471277-30c65994-af30-4eef-ab15-f9ac1f9ace64.png" alt="multiple sidecar proxy support" width="880" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  And lot more
&lt;/h2&gt;

&lt;p&gt;osm-edge 1.1 also has a tremendous list of other improvements, performance enhancements, and bug fixes, for a detailed change log, please refer to the Release page on &lt;a href="https://github.com/flomesh-io/osm-edge/releases"&gt;Github&lt;/a&gt;. Below are some of the notable changes included in this release:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Refactoring of Proxy Control Plane component to stay generic and allow interaction with new sidecar proxy implementation&lt;/li&gt;
&lt;li&gt;Added new &lt;code&gt;driver.Driver&lt;/code&gt; interface that needs to be implemented by 3rd party vendors wishing to provide sidecar proxy for control plane&lt;/li&gt;
&lt;li&gt;Added new &lt;code&gt;driver.HealthProbes&lt;/code&gt;, &lt;code&gt;driver.HealthProbe&lt;/code&gt;, &lt;code&gt;driver.InjectorContext&lt;/code&gt;, &lt;code&gt;driver.controllerContext&lt;/code&gt; struct to use with new sidecar proxy driver implementation&lt;/li&gt;
&lt;li&gt;Refactored Envoy based proxy sidecar integration to a separate Driver, so that it works as an implementation of &lt;code&gt;driver.Driver&lt;/code&gt; interface&lt;/li&gt;
&lt;li&gt;Added &lt;a href="https://github.com/flomesh-io/pipy"&gt;pipy&lt;/a&gt; implementation as a new Proxy Control Plane component proxy Driver&lt;/li&gt;
&lt;li&gt;Refactors Helm chart &lt;code&gt;values.yaml&lt;/code&gt; and added items &lt;code&gt;osm.sidecarClass&lt;/code&gt;, &lt;code&gt;osm.sidecarImage&lt;/code&gt;, &lt;code&gt;osm.sidecarWindowsImage&lt;/code&gt;, &lt;code&gt;osm.sidecarDrivers&lt;/code&gt; List to allow configuring the proxy sidecar driver.&lt;/li&gt;
&lt;li&gt;Pipy driver is the default driver of osm-edge distribution, but can be configured via cli flag &lt;code&gt;--set=osm.sidecarClass=XXX&lt;/code&gt; where &lt;code&gt;XXX&lt;/code&gt; refers to sidecar Driver.&lt;/li&gt;
&lt;li&gt;osm-edge control plane images are now multi-architecture, built for Linux/amd64 and Linux/arm64&lt;/li&gt;
&lt;li&gt;osm-edge test suite used images are now multi-architecture, built for Linux/amd64 and Linux/arm64&lt;/li&gt;
&lt;li&gt;Optimization of scripts&lt;/li&gt;
&lt;li&gt;Added Makefile targets for easier installation/setup&lt;/li&gt;
&lt;li&gt;Updated scripts to setup a development environment on amd64 and arm64 architectures.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's next and where to learn more?
&lt;/h2&gt;

&lt;p&gt;For more documentation, a quick-start guide, and step-by-step tutorials please visit &lt;a href="https://osm-edge-docs.flomesh.io/docs/getting_started/"&gt;osm-edge-docs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;osm-edge is a fork of &lt;a href="https://github.com/openservicemesh/osm/tree/release-v1.1"&gt;open service mesh&lt;/a&gt; and we will strive to keep this fork in sync with its upstream and propose back major changes and/or feature proposals to upstream for broader benefits of the community. Both &lt;a href="https://github.com/openservicemesh/osm"&gt;OSM&lt;/a&gt; and &lt;a href="https://github.com/flomesh-io/osm-edge"&gt;osm-edge&lt;/a&gt; are hosted on Github. If you have any feature request, question, or comment, we’d love to have you join the rapidly-growing community via &lt;a href="https://github.com/flomesh-io/osm-edge/issues"&gt;Github Issues&lt;/a&gt;, &lt;a href="https://github.com/flomesh-io/osm-edge/pulls"&gt;Pull Requests&lt;/a&gt;, or &lt;a href="https://cloud-native.slack.com/archives/C018794NV1C"&gt;osm slack channel&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>osm</category>
      <category>servicemesh</category>
      <category>smi</category>
      <category>cloudnative</category>
    </item>
  </channel>
</rss>
