<?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: Sören Metje</title>
    <description>The latest articles on DEV Community by Sören Metje (@soerenmetje).</description>
    <link>https://dev.to/soerenmetje</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%2F1032690%2Fff3545d8-e061-4f04-93bc-c1b5c0cc5e4c.jpeg</url>
      <title>DEV Community: Sören Metje</title>
      <link>https://dev.to/soerenmetje</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/soerenmetje"/>
    <language>en</language>
    <item>
      <title>How to Deploy Dolibarr on Kubernetes - ERP &amp; CRM System</title>
      <dc:creator>Sören Metje</dc:creator>
      <pubDate>Mon, 11 Sep 2023 11:03:59 +0000</pubDate>
      <link>https://dev.to/soerenmetje/how-to-deploy-dolibarr-on-kubernetes-erp-crm-system-38dj</link>
      <guid>https://dev.to/soerenmetje/how-to-deploy-dolibarr-on-kubernetes-erp-crm-system-38dj</guid>
      <description>&lt;p&gt;Ever wondered how to create invoices without relying on paid services or abusing Microsoft Excel? &lt;a href="https://www.dolibarr.org/"&gt;Dolibarr&lt;/a&gt; is a software that provides functionality to create invoices and offers, as well as to manage corresponding resources such as customers, partners, products, service, projects, payments, etc. It is free and open-source. After setup, You can access your own Dolibarr instance via web browser. Officially, Dolibarr is referred as an ERP (Enterprise Resource Planning) and CRM (Customer Relationship Management) system. From my experience, it is overall the best choice among open-source systems. Other candidates are &lt;a href="https://github.com/odoo/odoo"&gt;Odoo&lt;/a&gt;, &lt;a href="https://github.com/metasfresh/metasfresh"&gt;Metafresh&lt;/a&gt;, &lt;a href="https://github.com/kivitendo/kivitendo-erp"&gt;Kivitendo&lt;/a&gt;, and &lt;a href="https://github.com/apache/ofbiz-framework"&gt;Apache OFBiz&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This article shows how to set up Dolibarr in your Kubernetes cluster. This way you can benefit from Kubernetes advantages such as high availability and automatic volume backups (if enabled). Although, this might be overkill for some uses cases. As a bonus, a reference to a simple setup using Docker compose is also included.&lt;/p&gt;

&lt;p&gt;Try out a Dolibarr demo at &lt;a href="https://demo.dolibarr.org"&gt;https://demo.dolibarr.org&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--o0UHElAb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d0xs7sj3zly0zszvj069.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--o0UHElAb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d0xs7sj3zly0zszvj069.png" alt="Screenshot of a Dolibarr page to edit an invoice" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Kubernetes cluster is set up and ready&lt;/li&gt;
&lt;li&gt;Subdomain e.g. &lt;code&gt;dolibarr.example.com&lt;/code&gt; points to your Kubernetes cluster&lt;/li&gt;
&lt;li&gt;Kubernetes cluster has a &lt;code&gt;ClusterIssuer&lt;/code&gt; named &lt;code&gt;lets-encrypt&lt;/code&gt; set up and ready (you can adjust this setup if named differently)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Deployment @ Kubernetes
&lt;/h2&gt;

&lt;p&gt;To deploy Dolibarr on your Kubernetes cluster, multiple Kubernetes objects are needed. The GitHub repository &lt;a href="https://github.com/soerenmetje/kubernetes-dolibarr"&gt;https://github.com/soerenmetje/kubernetes-dolibarr&lt;/a&gt;  contains Kubernetes template files (&lt;code&gt;*.yaml&lt;/code&gt;) and detailed setup instructions. In summary, following steps are necessary:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new namespace&lt;/li&gt;
&lt;li&gt;Modify the template files&lt;/li&gt;
&lt;li&gt;Apply the template files to create the Kubernetes objects&lt;/li&gt;
&lt;li&gt;Wait&lt;/li&gt;
&lt;li&gt;Check if Dolibarr instance is reachable&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you want to restrict the access to certain IPs or IP ranges, further configuration steps are included in the repository. Additionally, the upgrading process and advanced configuration of Dolibarr, as well as known issues and troubleshooting are covered.&lt;/p&gt;

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

&lt;p&gt;In the end, we will end up with following Kubernetes objects:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--i6yD_r0H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/apswyqov3w86hdqr1aho.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--i6yD_r0H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/apswyqov3w86hdqr1aho.png" alt="Dolibarr Kubernetes architecture" width="800" height="768"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;webserver&lt;/code&gt; pod, &lt;a href="https://hub.docker.com/r/tuxgasy/dolibarr"&gt;Tuxgasys' Dolibarr Docker image&lt;/a&gt; is used. Luckily, this image handles the installation process of Dolibarr automatically on the first start. The &lt;code&gt;db&lt;/code&gt; pod runs a &lt;a href="https://hub.docker.com/_/mariadb"&gt;mariadb&lt;/a&gt; container. The persistent volumes &lt;code&gt;dolibarr-custom&lt;/code&gt;, &lt;code&gt;dolibarr-documents&lt;/code&gt;, and &lt;code&gt;db-data&lt;/code&gt; ensure that configurations, generated PDF files, and the database content is persistently stored. The &lt;code&gt;dolibarr-ingress&lt;/code&gt; ingress allows accessing Dolibarr via https using a user-defined subdomain. &lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: Deployment @ Docker
&lt;/h2&gt;

&lt;p&gt;In the GitHub repository of Tuxgasys' Dolibarr Docker image a &lt;a href="https://github.com/tuxgasy/docker-dolibarr/tree/master/examples/with-rp-traefik"&gt;Docker compose deployment&lt;/a&gt; is included that integrates &lt;a href="https://hub.docker.com/_/traefik"&gt;traefik&lt;/a&gt; as a reverse proxy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/tuxgasy/docker-dolibarr"&gt;https://github.com/tuxgasy/docker-dolibarr&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Dolibarr/dolibarr"&gt;https://github.com/Dolibarr/dolibarr&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wiki.dolibarr.org/index.php?title=Home"&gt;https://wiki.dolibarr.org/index.php?title=Home&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/soerenmetje/kubernetes-dolibarr"&gt;https://github.com/soerenmetje/kubernetes-dolibarr&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>kubernetes</category>
      <category>devops</category>
      <category>docker</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Stripe Search Query Injections and How to Prevent Them</title>
      <dc:creator>Sören Metje</dc:creator>
      <pubDate>Wed, 24 May 2023 11:40:39 +0000</pubDate>
      <link>https://dev.to/soerenmetje/injections-in-stripe-search-queries-and-how-to-prevent-them-cbo</link>
      <guid>https://dev.to/soerenmetje/injections-in-stripe-search-queries-and-how-to-prevent-them-cbo</guid>
      <description>&lt;p&gt;If you directly use user input in a &lt;a href="https://stripe.com/docs/search"&gt;Stripe search query&lt;/a&gt;, it is vulnerable to injections. Attackers can exploit this to gain read access to all records of your Stripe resource. The principle is basically the same as in SQL injections. In this article, I propose a fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// NodeJS&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stripe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stripe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRIPE_SECRET_KEY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;124' OR created&amp;gt;0 OR status:'active&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="c1"&gt;// Injection&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;subscriptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;stripe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscriptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`metadata['myField']: '&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userInput&lt;/span&gt;&lt;span class="p"&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subscriptions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// all subscriptions ever&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;I was developing a backend that integrates &lt;a href="https://stripe.com"&gt;Stripe&lt;/a&gt; to manage customers and to process subscriptions. In one use case, it should search for user input in the metadata of Stripe subscriptions.&lt;br&gt;
When I looked up the documentation about how to use the search functionality I came across the &lt;a href="https://stripe.com/docs/search#search-query-language"&gt;Search Query Language&lt;/a&gt;. It looked like users could easily inject their own additional query clauses. After a simple check: Yes, e.g. for the user input &lt;code&gt;"124' OR status:'active"&lt;/code&gt; all active subscriptions are returned as well. &lt;/p&gt;

&lt;p&gt;I searched for &lt;code&gt;escape&lt;/code&gt; and &lt;code&gt;injection&lt;/code&gt; in Stripe documentation and asked Google and ChatGPT - no results.&lt;br&gt;
The Stripe support informed me that there is currently no functionality for this type of validation in the Stripe NodeJS library or API. This is something developers would have to build on their own. &lt;br&gt;
As a developer, I would expect to find this statement in the documentation.&lt;/p&gt;

&lt;p&gt;Is this a problem?&lt;br&gt;
A quick search on GitHub for the usage of Stripe search query showed: &lt;br&gt;
4 out of 6 projects I looked at do not implement any input escape or input validation functionality. Therefore, all these projects are potentially vulnerable.&lt;/p&gt;
&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;I wrote a small NodeJS library &lt;a href="https://www.npmjs.com/package/stripe-escape-input"&gt;stripe-escape-input&lt;/a&gt; that does the job.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i stripe-escape-input
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;escapeInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stripe-escape-input&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stripe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stripe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRIPE_SECRET_KEY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;124' OR created&amp;gt;0 OR status:'active&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="c1"&gt;// Injection&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;subscriptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;stripe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscriptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`metadata['myField']: '&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;escapeInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userInput&lt;/span&gt;&lt;span class="p"&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subscriptions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// 0 subscriptions&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To prevent injections, we need to escape the user input before using it in a Stripe search query. What exactly has to be considered tells us the &lt;a href="https://stripe.com/docs/search#search-query-language"&gt;Stripe query language documentation&lt;/a&gt;. Let's hope it is complete.&lt;br&gt;
Based on that, it comes down to string replacement of single quotes &lt;code&gt;'&lt;/code&gt;, double quotes &lt;code&gt;"&lt;/code&gt;, and backslashes &lt;code&gt;\&lt;/code&gt;, so an attacker can not end the value part and add additional query clauses.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Is this a good solution? No. As an external developer, I can only implement what is documented by Stripe. There might exist undocumented behavior that could lead to new vulnerabilities. The best approach would be for Stripe to provide this functionality since they know all the implementation details of their search queries. Until then, this is the best we can achieve.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://stripe.com/docs/search"&gt;https://stripe.com/docs/search&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stripe.com/docs/api/subscriptions/search"&gt;https://stripe.com/docs/api/subscriptions/search&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/soerenmetje/stripe-escape-input"&gt;https://github.com/soerenmetje/stripe-escape-input&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/stripe-escape-input"&gt;https://www.npmjs.com/package/stripe-escape-input&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>security</category>
      <category>stripe</category>
      <category>backend</category>
    </item>
    <item>
      <title>Debugging Kubernetes Applications - A Swiss Army Knife Pod</title>
      <dc:creator>Sören Metje</dc:creator>
      <pubDate>Sat, 15 Apr 2023 21:05:37 +0000</pubDate>
      <link>https://dev.to/soerenmetje/debug-kubernetes-applications-a-swiss-army-knife-container-56id</link>
      <guid>https://dev.to/soerenmetje/debug-kubernetes-applications-a-swiss-army-knife-container-56id</guid>
      <description>&lt;p&gt;To debug Kubernetes applications, e.g. if pods can reach a service, an interactive container shell including all essential tools is great - a Swiss army knife so to speak. Unfortunately, in popular base images such as Ubuntu, Debian, CentOS, and Busybox essential debugging tools are not included due to image size reduction and security. While this is great in production environments, it is counterproductive for debugging. Here, we presented an approach based on the extended Ubuntu image &lt;a href="https://hub.docker.com/r/leodotcloud/swiss-army-knife"&gt;leodotcloud/swiss-army-knife&lt;/a&gt; created by &lt;a href="https://github.com/leodotcloud"&gt;leodotcloud&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create Debugging-Pod
&lt;/h3&gt;

&lt;p&gt;Spin up 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 create &lt;span class="nt"&gt;-n&lt;/span&gt; mynamespace &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: Pod
metadata:
  name: swiss-army-knife
  labels:
    app: swiss-army-knife
spec:
  containers:
  - name: swiss-army-knife
    image: leodotcloud/swiss-army-knife:latest
    command: ["/bin/sleep", "3650d"]
    imagePullPolicy: IfNotPresent
  restartPolicy: Always
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Get Interactive Shell
&lt;/h3&gt;

&lt;p&gt;Get access to the container command line and debug your stuff:&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="nt"&gt;-n&lt;/span&gt; mynamespace swiss-army-knife  &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; /bin/bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As an example the following command checks whether the port &lt;code&gt;3306&lt;/code&gt; (MySQL) is accessible on &lt;code&gt;10.152.183.115&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;netcat &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; 4 10.152.183.115 3306
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Remove Debugging-Pod
&lt;/h3&gt;

&lt;p&gt;After debugging, you can delete 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 delete pod &lt;span class="nt"&gt;-n&lt;/span&gt; mynamespace swiss-army-knife
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Tools and Packages
&lt;/h2&gt;

&lt;p&gt;Following tools and packages are included. An up-to-date list is available in the &lt;a href="https://github.com/leodotcloud/swiss-army-knife/blob/main/package/Dockerfile"&gt;Dockerfile&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;arping&lt;/li&gt;
&lt;li&gt;arptables&lt;/li&gt;
&lt;li&gt;bridge-utils&lt;/li&gt;
&lt;li&gt;ca-certificates&lt;/li&gt;
&lt;li&gt;conntrack&lt;/li&gt;
&lt;li&gt;curl&lt;/li&gt;
&lt;li&gt;dnsutils&lt;/li&gt;
&lt;li&gt;ethtool&lt;/li&gt;
&lt;li&gt;iperf&lt;/li&gt;
&lt;li&gt;iperf3&lt;/li&gt;
&lt;li&gt;iproute2&lt;/li&gt;
&lt;li&gt;ipsec-tools&lt;/li&gt;
&lt;li&gt;ipset&lt;/li&gt;
&lt;li&gt;iptables&lt;/li&gt;
&lt;li&gt;iputils-ping&lt;/li&gt;
&lt;li&gt;jq&lt;/li&gt;
&lt;li&gt;kmod&lt;/li&gt;
&lt;li&gt;ldap-utils&lt;/li&gt;
&lt;li&gt;less&lt;/li&gt;
&lt;li&gt;libpcap-dev&lt;/li&gt;
&lt;li&gt;man&lt;/li&gt;
&lt;li&gt;manpages-posix&lt;/li&gt;
&lt;li&gt;mtr&lt;/li&gt;
&lt;li&gt;net-tools&lt;/li&gt;
&lt;li&gt;netcat&lt;/li&gt;
&lt;li&gt;netcat-openbsd&lt;/li&gt;
&lt;li&gt;openssl&lt;/li&gt;
&lt;li&gt;openssh-client&lt;/li&gt;
&lt;li&gt;psmisc&lt;/li&gt;
&lt;li&gt;socat&lt;/li&gt;
&lt;li&gt;tcpdump&lt;/li&gt;
&lt;li&gt;telnet&lt;/li&gt;
&lt;li&gt;tmux&lt;/li&gt;
&lt;li&gt;traceroute&lt;/li&gt;
&lt;li&gt;tcptraceroute&lt;/li&gt;
&lt;li&gt;tree&lt;/li&gt;
&lt;li&gt;ngrep&lt;/li&gt;
&lt;li&gt;vim&lt;/li&gt;
&lt;li&gt;wget&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/leodotcloud/swiss-army-knife"&gt;https://github.com/leodotcloud/swiss-army-knife&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hub.docker.com/r/leodotcloud/swiss-army-knife"&gt;https://hub.docker.com/r/leodotcloud/swiss-army-knife&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.digitalocean.com/community/tutorials/how-to-use-netcat-to-establish-and-test-tcp-and-udp-connections"&gt;https://www.digitalocean.com/community/tutorials/how-to-use-netcat-to-establish-and-test-tcp-and-udp-connections&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>kubernetes</category>
      <category>devops</category>
      <category>debug</category>
    </item>
    <item>
      <title>How to Secure a Docker Host Using Firewalld</title>
      <dc:creator>Sören Metje</dc:creator>
      <pubDate>Thu, 23 Feb 2023 23:41:45 +0000</pubDate>
      <link>https://dev.to/soerenmetje/how-to-secure-a-docker-host-using-firewalld-2joo</link>
      <guid>https://dev.to/soerenmetje/how-to-secure-a-docker-host-using-firewalld-2joo</guid>
      <description>&lt;p&gt;If you are using a firewall like ufw or firewalld and docker you may encounter the problem that docker bypasses the firewall rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  Goal
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The firewall rules should count for whole host system - so including Docker containers with port mappings&lt;/li&gt;
&lt;li&gt;A Docker container should be accessible from the internet if and only if the host port used in Docker container port mapping is allowed in the firewall&lt;/li&gt;
&lt;li&gt;The approach should not break container networking&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Existing Approaches
&lt;/h2&gt;

&lt;p&gt;I found following approaches that try to fix the problem. However, each approach introduced another problem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Just do not use docker. Podman for example obeys firewall rules by default. Problem: Some can not or may not want to switch to a different container runtime, but I generally recommend checking if this is an option for you. &lt;a href="https://phoenixnap.com/kb/podman-vs-docker" rel="noopener noreferrer"&gt;This article&lt;/a&gt; includes a comparison. &lt;/li&gt;
&lt;li&gt;Use external firewall like security groups in Openstack instead of ufw or firewalld. Problem: Not available in my case.&lt;/li&gt;
&lt;li&gt;Just do not map ports in docker. Problem: may introduce security risk because of no single source of truth for exposed host ports.&lt;/li&gt;
&lt;li&gt;Disabling iptables for docker. Problem: Containers can not access internet.&lt;/li&gt;
&lt;li&gt;Configuring the firewall to ignore port mappings. Problem: The port inside the container have to be allowed in the host firewall. If multiple containers use same port and only one should be allowed we have to additionally specify container IP or service name. In summary: Counterintuitive, complex and error-prone.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Approach
&lt;/h2&gt;

&lt;p&gt;Idea: Disable iptables for docker and configure firewalld to allow container networking. It is based on this &lt;a href="https://erfansahaf.medium.com/why-docker-and-firewall-dont-get-along-with-each-other-ddca7a002e10" rel="noopener noreferrer"&gt;Medium article&lt;/a&gt; by Erfan Sahafnejad and several posts. I tested it with Ubuntu 22.04.2 LTS but the concept should also work on other Linux. &lt;/p&gt;

&lt;h3&gt;
  
  
  Security Implications
&lt;/h3&gt;

&lt;p&gt;It is important to notice, that this approach can have security implications depending on the setup, e.g., as described &lt;a href="https://www.reddit.com/r/selfhosted/comments/186bz2g/a_mailserver_incident_postmortem/" rel="noopener noreferrer"&gt;Keval Kapdee's post&lt;/a&gt;. In his setup, he operated a mail server in a docker container with a similar configuration as discussed in this article. Due to the configured masquarading of packets, from the mailserver perspective, all packets originate from the IP address &lt;code&gt;172.22.1.1&lt;/code&gt;, which is listed as a trusted address in Postfix by default. Therefore, Postfix relayed all requests from every internet IP address as these were seen as originating from a trusted address. In summary, this approach is not suited for use cases, which use original internet IP addresses, e.g., for access control. &lt;/p&gt;

&lt;p&gt;Overall, especially in production setups, I recommend using &lt;strong&gt;other approaches such as Podman&lt;/strong&gt; instead of the approach discussed in this article.&lt;/p&gt;

&lt;h3&gt;
  
  
  Preparation
&lt;/h3&gt;

&lt;p&gt;If you added any configuration to iptables regarding docker before, remove it first.&lt;/p&gt;

&lt;p&gt;If ufw is installed and active, disable it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ufw disable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install and activate firewalld:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt &lt;span class="nb"&gt;install &lt;/span&gt;firewalld &lt;span class="nt"&gt;-y&lt;/span&gt;
systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;--now&lt;/span&gt; firewalld

&lt;span class="c"&gt;# Confirm that the service is running&lt;/span&gt;
firewall-cmd &lt;span class="nt"&gt;--state&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Compared to ufw, firewalld is more powerful - it provides features that we need for upcoming firewall configurations. However, it also just a convenient frontend for iptables. Learn more about firewalld here: &lt;a href="https://docs.rockylinux.org/guides/security/firewalld-beginners/" rel="noopener noreferrer"&gt;https://docs.rockylinux.org/guides/security/firewalld-beginners/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Disable iptables for Docker
&lt;/h3&gt;

&lt;p&gt;Disable iptables for docker in &lt;code&gt;/etc/docker/daemon.json&lt;/code&gt; so it should look like follows:&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;"iptables"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&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;p&gt;If &lt;code&gt;/etc/docker/daemon.json&lt;/code&gt; does not exist, create the file first.&lt;/p&gt;

&lt;p&gt;Restart docker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl restart docker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Already at this point, only container ports that are allowed in firewall should be reachable from the internet. However, as a side effect of disabling iptables in docker, we broke container internet access: From the inside of containers we can not access the internet anymore.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; busybox ping &lt;span class="nt"&gt;-c4&lt;/span&gt; 8.8.8.8
&lt;span class="c"&gt;# PING 8.8.8.8 (8.8.8.8): 56 data bytes&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# --- 8.8.8.8 ping statistics ---&lt;/span&gt;
&lt;span class="c"&gt;# 4 packets transmitted, 0 packets received, 100% packet loss&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configure firewalld
&lt;/h3&gt;

&lt;p&gt;At next, we configure firewalld to enable docker container networking.&lt;/p&gt;

&lt;p&gt;Add Masquerading to the zone which leads out to the Internet, typically &lt;code&gt;public&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;# Masquerading allows for docker ingress and egress (this is the juicy bit)&lt;/span&gt;
firewall-cmd &lt;span class="nt"&gt;--zone&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;public &lt;span class="nt"&gt;--add-masquerade&lt;/span&gt; &lt;span class="nt"&gt;--permanent&lt;/span&gt;
&lt;span class="c"&gt;# Reload firewall to apply permanent rules&lt;/span&gt;
firewall-cmd &lt;span class="nt"&gt;--reload&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sources: &lt;a href="https://serverfault.com/a/987687" rel="noopener noreferrer"&gt;https://serverfault.com/a/987687&lt;/a&gt; and &lt;a href="https://serverfault.com/a/1046550" rel="noopener noreferrer"&gt;https://serverfault.com/a/1046550&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Additionally, in order to enable docker containers accessing host ports, add docker interface to the &lt;code&gt;trusted&lt;/code&gt; zone:&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;# Show interfaces to find out docker interface name&lt;/span&gt;
ip &lt;span class="nb"&gt;link &lt;/span&gt;show

&lt;span class="c"&gt;# Assumes docker interface is docker0&lt;/span&gt;
firewall-cmd &lt;span class="nt"&gt;--permanent&lt;/span&gt; &lt;span class="nt"&gt;--zone&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;trusted &lt;span class="nt"&gt;--add-interface&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;docker0
firewall-cmd &lt;span class="nt"&gt;--reload&lt;/span&gt;
systemctl restart docker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sources: &lt;a href="https://unix.stackexchange.com/a/225845" rel="noopener noreferrer"&gt;https://unix.stackexchange.com/a/225845&lt;/a&gt; and &lt;a href="https://unix.stackexchange.com/a/333356" rel="noopener noreferrer"&gt;https://unix.stackexchange.com/a/333356&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So far, docker containers that are not attached to a docker network can access the internet. But containers that are attached can still not. This is often the case when using docker compose.&lt;/p&gt;

&lt;p&gt;If we try to ping Google DNS server this is the result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; busybox ping &lt;span class="nt"&gt;-c4&lt;/span&gt; 8.8.8.8
&lt;span class="c"&gt;# PING 8.8.8.8 (8.8.8.8): 56 data bytes&lt;/span&gt;
&lt;span class="c"&gt;# 64 bytes from 8.8.8.8: seq=0 ttl=58 time=3.699 ms&lt;/span&gt;
&lt;span class="c"&gt;# 64 bytes from 8.8.8.8: seq=1 ttl=58 time=3.588 ms&lt;/span&gt;
&lt;span class="c"&gt;# 64 bytes from 8.8.8.8: seq=2 ttl=58 time=3.587 ms&lt;/span&gt;
&lt;span class="c"&gt;# 64 bytes from 8.8.8.8: seq=3 ttl=58 time=3.518 ms&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# --- 8.8.8.8 ping statistics ---&lt;/span&gt;
&lt;span class="c"&gt;# 4 packets transmitted, 4 packets received, 0% packet loss&lt;/span&gt;
&lt;span class="c"&gt;# round-trip min/avg/max = 3.518/3.598/3.699 ms&lt;/span&gt;


&lt;span class="c"&gt;# Create docker network for testing purpose (can be deleted later)&lt;/span&gt;
docker network create &lt;span class="nt"&gt;--driver&lt;/span&gt; bridge mynet

docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--net&lt;/span&gt; mynet busybox ping &lt;span class="nt"&gt;-c4&lt;/span&gt; 8.8.8.8
&lt;span class="c"&gt;# PING 8.8.8.8 (8.8.8.8): 56 data bytes&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# --- 8.8.8.8 ping statistics ---&lt;/span&gt;
&lt;span class="c"&gt;# 4 packets transmitted, 0 packets received, 100% packet loss&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To fix this, add your network interface to &lt;code&gt;public&lt;/code&gt; zone:&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;# Show public ip&lt;/span&gt;
curl &lt;span class="nt"&gt;-4&lt;/span&gt; ip.gwdg.de
&lt;span class="c"&gt;# Show interfaces to find out network interface name with your public IP&lt;/span&gt;
ip addr

&lt;span class="c"&gt;# Assumes network interface with your public IP is eth0&lt;/span&gt;
&lt;span class="c"&gt;# (ens18 is also a name I came accross)&lt;/span&gt;
firewall-cmd &lt;span class="nt"&gt;--permanent&lt;/span&gt; &lt;span class="nt"&gt;--zone&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;public &lt;span class="nt"&gt;--add-interface&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;eth0
firewall-cmd &lt;span class="nt"&gt;--reload&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Networking should work properly now and therefore containers should be able to access the internet.&lt;/p&gt;

&lt;p&gt;If we now try to ping Google DNS server again, it works as expected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; busybox ping &lt;span class="nt"&gt;-c4&lt;/span&gt; 8.8.8.8
&lt;span class="c"&gt;# PING 8.8.8.8 (8.8.8.8): 56 data bytes&lt;/span&gt;
&lt;span class="c"&gt;# 64 bytes from 8.8.8.8: seq=0 ttl=58 time=3.641 ms&lt;/span&gt;
&lt;span class="c"&gt;# 64 bytes from 8.8.8.8: seq=1 ttl=58 time=3.565 ms&lt;/span&gt;
&lt;span class="c"&gt;# 64 bytes from 8.8.8.8: seq=2 ttl=58 time=3.605 ms&lt;/span&gt;
&lt;span class="c"&gt;# 64 bytes from 8.8.8.8: seq=3 ttl=58 time=3.546 ms&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# --- 8.8.8.8 ping statistics ---&lt;/span&gt;
&lt;span class="c"&gt;# 4 packets transmitted, 4 packets received, 0% packet loss&lt;/span&gt;
&lt;span class="c"&gt;# round-trip min/avg/max = 3.546/3.589/3.641 ms&lt;/span&gt;

docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--net&lt;/span&gt; mynet busybox ping &lt;span class="nt"&gt;-c4&lt;/span&gt; 8.8.8.8
&lt;span class="c"&gt;# PING 8.8.8.8 (8.8.8.8): 56 data bytes&lt;/span&gt;
&lt;span class="c"&gt;# 64 bytes from 8.8.8.8: seq=0 ttl=58 time=3.671 ms&lt;/span&gt;
&lt;span class="c"&gt;# 64 bytes from 8.8.8.8: seq=1 ttl=58 time=3.644 ms&lt;/span&gt;
&lt;span class="c"&gt;# 64 bytes from 8.8.8.8: seq=2 ttl=58 time=3.561 ms&lt;/span&gt;
&lt;span class="c"&gt;# 64 bytes from 8.8.8.8: seq=3 ttl=58 time=3.508 ms&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# --- 8.8.8.8 ping statistics ---&lt;/span&gt;
&lt;span class="c"&gt;# 4 packets transmitted, 4 packets received, 0% packet loss&lt;/span&gt;
&lt;span class="c"&gt;# round-trip min/avg/max = 3.508/3.596/3.671 ms&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Open Firewall Ports
&lt;/h3&gt;

&lt;p&gt;In the end, open the desired ports for your service to allow incoming traffic, e.g. on port 8080:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firewall-cmd &lt;span class="nt"&gt;--permanent&lt;/span&gt; &lt;span class="nt"&gt;--zone&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;public &lt;span class="nt"&gt;--add-port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;8080/tcp
&lt;span class="c"&gt;# Reload firewall to apply permanent rules&lt;/span&gt;
firewall-cmd &lt;span class="nt"&gt;--reload&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Extra: Testing
&lt;/h3&gt;

&lt;p&gt;It is important to run tests to ensure the whole setup is working properly. Although the actual tests depend on your setup, here are some statements that may be important to verify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Container running on allowed port can be accessed from internet&lt;/li&gt;
&lt;li&gt;Container running on &lt;strong&gt;not&lt;/strong&gt; allowed port can &lt;strong&gt;not&lt;/strong&gt; be accessed from internet&lt;/li&gt;
&lt;li&gt;Container can access internet&lt;/li&gt;
&lt;li&gt;Container with new docker network can access internet&lt;/li&gt;
&lt;li&gt;Container can access service running on host system port&lt;/li&gt;
&lt;li&gt;Container can access other container inside same docker network&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To start a webserver on 8080 you can run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--restart&lt;/span&gt; unless-stopped &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:80 &lt;span class="nt"&gt;-d&lt;/span&gt; nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To curl a service running on host system port from inside of a container you can run:&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;# Show docker interface ip address&lt;/span&gt;
ip addr
&lt;span class="c"&gt;# ...&lt;/span&gt;
&lt;span class="c"&gt;# 3: docker0: &amp;lt;BROADCAST,MULTICAST,UP,LOWER_UP&amp;gt; mtu 1500 qdisc noqueue state UP group default &lt;/span&gt;
&lt;span class="c"&gt;#    link/ether 02:42:37:6b:6e:2a brd ff:ff:ff:ff:ff:ff&lt;/span&gt;
&lt;span class="c"&gt;#    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0&lt;/span&gt;
&lt;span class="c"&gt;#       valid_lft forever preferred_lft forever&lt;/span&gt;
&lt;span class="c"&gt;# ...&lt;/span&gt;

&lt;span class="c"&gt;# Assumes docker interface ip is 172.17.0.1&lt;/span&gt;
&lt;span class="c"&gt;# and service runs on port 80&lt;/span&gt;
docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; curlimages/curl &lt;span class="nt"&gt;-v&lt;/span&gt; http://172.17.0.1:80/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Good firewalld guide: &lt;a href="https://docs.rockylinux.org/guides/security/firewalld-beginners/" rel="noopener noreferrer"&gt;https://docs.rockylinux.org/guides/security/firewalld-beginners/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Great article for understanding container networking (and also the steps of this article): &lt;a href="https://iximiuz.com/en/posts/container-networking-is-simple/" rel="noopener noreferrer"&gt;https://iximiuz.com/en/posts/container-networking-is-simple/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://erfansahaf.medium.com/why-docker-and-firewall-dont-get-along-with-each-other-ddca7a002e10" rel="noopener noreferrer"&gt;https://erfansahaf.medium.com/why-docker-and-firewall-dont-get-along-with-each-other-ddca7a002e10&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/docker/for-linux/issues/955#issuecomment-621141128" rel="noopener noreferrer"&gt;https://github.com/docker/for-linux/issues/955#issuecomment-621141128&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/network/iptables/#prevent-docker-from-manipulating-iptables" rel="noopener noreferrer"&gt;https://docs.docker.com/network/iptables/#prevent-docker-from-manipulating-iptables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serverfault.com/a/987687" rel="noopener noreferrer"&gt;https://serverfault.com/a/987687&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serverfault.com/a/1046550" rel="noopener noreferrer"&gt;https://serverfault.com/a/1046550&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://unix.stackexchange.com/a/225845" rel="noopener noreferrer"&gt;https://unix.stackexchange.com/a/225845&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>docker</category>
      <category>firewall</category>
      <category>devops</category>
      <category>linux</category>
    </item>
  </channel>
</rss>
