<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	
	xmlns:georss="http://www.georss.org/georss"
	xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#"
	>

<channel>
	<title>Tag: Linux - Ryan Daniels</title>
	<atom:link href="https://ryandaniels.ca/blog/tag/linux/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description></description>
	<lastBuildDate>Fri, 17 Jan 2025 02:33:13 +0000</lastBuildDate>
	<language>en-CA</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://ryandaniels.ca/wp-content/uploads/2019/07/img_5907-small-blur-square-100x100.jpg</url>
	<title>Tag: Linux - Ryan Daniels</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">22628916</site>	<item>
		<title>bootc (Bootable Containers): One Container Image to rule them all</title>
		<link>https://ryandaniels.ca/blog/bootc-bootable-containers-one-container-image-to-rule-them-all/</link>
		
		<dc:creator><![CDATA[Ryan Daniels]]></dc:creator>
		<pubDate>Fri, 17 Jan 2025 02:13:15 +0000</pubDate>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Atomic]]></category>
		<category><![CDATA[bootc]]></category>
		<category><![CDATA[Fedora]]></category>
		<category><![CDATA[Immutable]]></category>
		<category><![CDATA[RHEL]]></category>
		<guid isPermaLink="false">https://ryandaniels.ca/?p=4319</guid>

					<description><![CDATA[<p>bootc has the potential to be groundbreaking (for Enterprise server Linux). A scalable and immutable OS for servers. (Although I like the term Atomic better).</p>
<p>The post <a href="https://ryandaniels.ca/blog/bootc-bootable-containers-one-container-image-to-rule-them-all/">bootc (Bootable Containers): One Container Image to rule them all</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>bootc has the potential to be groundbreaking (for Enterprise server Linux). A scalable and immutable OS for servers. (Although I like the term Atomic better).</p>



<p>Earlier in 2024 Red Hat announced <a href="https://www.redhat.com/en/blog/introducing-image-mode-red-hat-enterprise-linux">&#8220;Image Mode&#8221; for Red Hat Enterprise Linux</a>. Currently Image Mode is in &#8220;Technology Preview&#8221; for RHEL. This is powered by Bootable Containers (or bootc for short). Fedora is also using this new technology, and they have great <a href="https://docs.fedoraproject.org/en-US/bootc/getting-started/">documentation</a>.</p>



<p>To summarize what bootc does,<br>from the Fedora Documentation:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>The <a href="https://containers.github.io/bootc/">bootc documentation</a> summarizes bootable containers as &#8220;transactional, in-place operating system updates using OCI/Docker container images&#8221;. In other words, updates to the operating system (OS) are shipped by using container images. That implies that the Linux kernel, the bootloader, drivers, etc. are all part of the container image which renders the container image &#8220;bootable&#8221;.</p>
</blockquote>



<p>These deployments are atomic, meaning they are (mostly) read-only by default.</p>



<p>Updates are easy, just re-build the Container Image and by default the bootc host will update (and reboot) on it&#8217;s own.</p>



<figure class="wp-block-image size-thumbnail"><a href="https://ryandaniels.ca/wp-content/uploads/2024/12/bootc_updates.png" rel="lightbox[4319]"><img fetchpriority="high" decoding="async" width="300" height="178" src="https://ryandaniels.ca/wp-content/uploads/2024/12/bootc_updates-300x178.png" alt="bootc update flow" class="wp-image-4347" srcset="https://ryandaniels.ca/wp-content/uploads/2024/12/bootc_updates-300x178.png 300w, https://ryandaniels.ca/wp-content/uploads/2024/12/bootc_updates.png 658w" sizes="(max-width: 300px) 100vw, 300px" /></a><figcaption class="wp-element-caption">Image Credit: <a href="https://docs.fedoraproject.org/en-US/bootc/getting-started/#_updating_bootable_containers">Fedora docs</a></figcaption></figure>



<h2 class="wp-block-heading">What makes bootc so exciting?</h2>



<p>One Container Image to rule them all.<br>Sorry, I meant to say: One Container Image to keep every server up to date, automatically.</p>



<p>Every server automatically checks for a new container image. When there&#8217;s a new image, the server automatically updates. If the update or reboot fails, no problem. It will &#8220;auto-heal&#8221;. (there&#8217;s a buzz word I haven&#8217;t heard in a while!)</p>



<p>There is also no chance of a different package version being installed during a rolling update of many servers (when external repositories are not in your control).</p>



<p>If you need more than one image (if you have many different workloads on your servers then don&#8217;t put everything into one image!), it&#8217;s pretty simple to have a single &#8220;base image&#8221; and many specialized images built from that.</p>



<h2 class="wp-block-heading">What could be better?</h2>



<ul class="wp-block-list">
<li>Updates require a reboot.. for any update, any package install.</li>



<li>There is still possibility for configuration drift in /etc</li>



<li>Initial install can be difficult.</li>



<li>Can&#8217;t easily add extra (non-root) disk (via the Dockerfile/Containerfile).</li>



<li>Some packages can&#8217;t be installed into a Container.</li>



<li>No release notes or changelog to see what packages change.</li>



<li>Day 2 configuration changes are somewhat painful. Redeploying the entire OS isn&#8217;t great if you want to be truly immutable.</li>



<li>Ansible doesn&#8217;t detect a bootc server any different from a normal RHEL or Fedora installation. But trying to install a package on a bootc server will obviously fail the Ansible Playbook. This makes re-using Ansible Roles difficult.</li>



<li>Simple things like user management are not simple considering <a href="https://containers.github.io/bootc/building/users-and-groups.html">issues with drift</a>. This means using <a href="https://ryandaniels.ca/blog/ansible-user-management/">Ansible for User Management</a> doesn&#8217;t really make sense anymore.</li>



<li>Advanced automatic update mechanism not included, like rolling updates of a 5 node cluster.</li>
</ul>



<h2 class="wp-block-heading">Conclusion</h2>



<p>I think bootc has the potential for amazing things in 2025 (and beyond). An Atomic server OS that scales. Even with the above somewhat long list of needed improvements, I&#8217;m still very excited. Is it too early to start using Bootable Containers in production? I don&#8217;t think so.</p>



<p></p>
<p>The post <a href="https://ryandaniels.ca/blog/bootc-bootable-containers-one-container-image-to-rule-them-all/">bootc (Bootable Containers): One Container Image to rule them all</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">4319</post-id>	</item>
		<item>
		<title>Goodbye Ansible 2.9 &#8211; Hello Ansible 2.16</title>
		<link>https://ryandaniels.ca/blog/goodbye-ansible-2-9-hello-ansible-2-16/</link>
		
		<dc:creator><![CDATA[Ryan Daniels]]></dc:creator>
		<pubDate>Fri, 20 Dec 2024 20:59:52 +0000</pubDate>
				<category><![CDATA[Ansible]]></category>
		<category><![CDATA[Linux]]></category>
		<guid isPermaLink="false">https://ryandaniels.ca/?p=4321</guid>

					<description><![CDATA[<p>Ansible 2.9, or maybe just this time in history, was a great time for simple configuration management that (mostly) just worked.</p>
<p>The post <a href="https://ryandaniels.ca/blog/goodbye-ansible-2-9-hello-ansible-2-16/">Goodbye Ansible 2.9 &#8211; Hello Ansible 2.16</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Ansible 2.9, or maybe just this time in history, was a great time for simple configuration management that (mostly) just worked. Even when using Ansible across hundreds of different Managed nodes, it was relatively simple to setup.</p>



<p>Side note: I still use Ansible today, including the first Role I ever created to <a href="https://ryandaniels.ca/blog/ansible-user-management/">Manage Users with Ansible</a>.</p>



<p>Fast forward to today, and as a user of Ansible it&#8217;s just <strong>annoying</strong>. Take a minute to think about the <a href="https://docs.ansible.com/ansible/latest/reference_appendices/release_and_maintenance.html#ansible-core-support-matrix">ansible-core Version Support Matrix</a>.</p>



<p>And then you need to think about:</p>



<ul class="wp-block-list">
<li>Certain Ansible versions only work on certain Control nodes, because they need to use a certain version of Python. </li>



<li>Certain Ansible versions only work on certain Managed nodes, because they need to use a certain version of Python. </li>



<li>Make sure you have the specific version of Python on your Control node to work with the version of Ansible you need. Is that version of Python available on your OS?</li>



<li>Install and update all the Ansible Collections you need. Which ones?</li>



<li>Install the dependencies for all your Ansible Collections using Python pip (or whatever you use), because those are separate! Which ones?</li>



<li>If you are upgrading from an old version of Ansible: fix all your Ansible Playbooks and Ansible Roles to work with the new version of Ansible.</li>
</ul>



<p>What happened to Ansible?</p>



<p>If you want to manage a Red Hat Enterprise Linux (RHEL) 8 host? <a href="https://www.jeffgeerling.com/blog/2024/newer-versions-ansible-dont-work-rhel-8">Good luck with that</a>, you are basically stuck on Ansible 2.16. <a href="https://github.com/ansible/ansible/issues/83357#issuecomment-2150254754">At least it appears Ansible 2.16 will stick around for a long time (Until the end of RHEL 8 lifecycle)</a>. Ansible 2.16 is the new Ansible 2.9 I guess.. At least until RHEL 11 comes out which will probably use an unsupported version of Python.</p>



<p>I&#8217;ve continued using Ansible 2.9 for as long as possible but it is inevitable. Newer hosts will use newer versions of Python, so the upgrade from Ansible 2.9 must begin because Ansible 2.9 doesn&#8217;t work with Managed hosts using newer versions of Python. RHEL 10 will be using Python 3.12. So now it is time to start moving to a new version of Ansible.</p>



<h2 class="wp-block-heading">Ansible 2.16 to the rescue</h2>


<div class="wp-block-image">
<figure class="alignright size-full"><img decoding="async" width="261" height="49" src="https://ryandaniels.ca/wp-content/uploads/2024/12/image.png" alt="Ansible &quot;Deprecated: Removed in 12&quot; warning from the Ansible Collection Index" class="wp-image-4323"/></figure></div>


<p>The only option at this point (for me) is Ansible 2.16. You *just* need to install it, do all the other install requirements, upgrade all your playbooks &amp; roles, etc. Easier said than done, but let&#8217;s go. Clean up some technical debt this holiday season!</p>



<h2 class="wp-block-heading">Cheat sheet to setup Ansible 2.16 on a RHEL 9 Control node</h2>



<p>On a RHEL 9 Control node, you need to install a newer version of Python. Then proceed to install all the rest of Ansible&#8217;s requirements.<br>For example:</p>



<pre class="wp-block-code"><code># On Control node as Ansible user (not root):
sudo dnf install python3.11 python3.11-pip

ln -s /usr/bin/python3.11 ~/.local/bin/python

python3.11 -m pip install -U --user ansible-core&lt;2.17 ansible-lint netaddr jmespath jc

ansible-galaxy collection install ansible.posix
ansible-galaxy collection install ansible.netcommon
ansible-galaxy collection install community.general
ansible-galaxy collection list</code></pre>



<p>You will now be using Ansible 2.16 on a RHEL 9 Control node which should work across all &#8220;modern&#8221; Linux hosts, even RHEL 7 (which is not modern, but Python 2.7 still works in Ansible 2.16).</p>



<p>Next up, change every single Ansible Playbook and Role and hope for the best. These <a href="https://docs.ansible.com/ansible/latest/porting_guides/porting_guides.html">Porting Guides</a> do <strong>not</strong> look fun!! Don&#8217;t forget to Ansible Lint &amp; syntax check everything.</p>



<pre class="wp-block-code"><code>ansible-lint *.yml

ansible-playbook --syntax-check *.yml</code></pre>



<h2 class="wp-block-heading">Conclusion &#8211; RIP Ansible 2.9</h2>



<p>RIP Ansible 2.9<br>Long live Ansible 2.16</p>



<p></p>
<p>The post <a href="https://ryandaniels.ca/blog/goodbye-ansible-2-9-hello-ansible-2-16/">Goodbye Ansible 2.9 &#8211; Hello Ansible 2.16</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">4321</post-id>	</item>
		<item>
		<title>Use Ansible to get OS package version (even with a dash)</title>
		<link>https://ryandaniels.ca/blog/ansible-get-os-package-version-with-dash/</link>
		
		<dc:creator><![CDATA[Ryan Daniels]]></dc:creator>
		<pubDate>Sat, 13 Jan 2024 22:27:28 +0000</pubDate>
				<category><![CDATA[Ansible]]></category>
		<category><![CDATA[Linux]]></category>
		<guid isPermaLink="false">https://ryandaniels.ca/?p=2909</guid>

					<description><![CDATA[<p><a href="https://ryandaniels.ca/blog/ansible-get-os-package-version-with-dash/"><img class="alignleft size-thumbnail wp-image-1170" src="https://ryandaniels.ca/wp-content/uploads/2018/02/Ansible_logo-e1517962271957-150x150.png" alt="ansible package version" width="150" height="150" /></a><br />
Get the OS package versions using Ansible, addressing challenges with package names containing dashes. The process involves using the package_facts module. Despite complexities, the approach ensures accurate version retrieval, even with dashes in package names.</p>
<p>The post <a href="https://ryandaniels.ca/blog/ansible-get-os-package-version-with-dash/">Use Ansible to get OS package version (even with a dash)</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></description>
										<content:encoded><![CDATA[<div class="wp-block-image">
<figure class="alignright size-full"><img decoding="async" width="256" height="315" src="https://ryandaniels.ca/wp-content/uploads/2018/02/Ansible_logo.png" alt="Ansible package version (Ansible Logo)" class="wp-image-1170" srcset="https://ryandaniels.ca/wp-content/uploads/2018/02/Ansible_logo.png 256w, https://ryandaniels.ca/wp-content/uploads/2018/02/Ansible_logo-244x300.png 244w" sizes="(max-width: 256px) 100vw, 256px" /></figure></div>


<p>Getting an OS package version using Ansible seems like a simple thing to do, except it&#8217;s not simple when there&#8217;s a dash in the package name. This approach will always work, even for packages with a dash in the name.</p>



<h2 class="wp-block-heading">Get the OS package version using Ansible</h2>



<p>This is using the builtin Ansible module: <a href="https://docs.ansible.com/ansible/2.9/modules/package_facts_module.html" target="_blank" rel="noreferrer noopener">package_facts</a>.</p>



<p>The example will get the version of the OS package &#8220;haproxy&#8221;, even if it has a dash. And the template file has logic to use certain configuration if the version of the OS package is greater or equal to version &#8220;2.0&#8221;. If the version is less than 2.0, then the older configuration will be used.</p>



<p>Example Ansible task:</p>



<pre class="wp-block-code"><code># tasks/main.yml<br><br>- name: Gather the OS package facts<br>  package_facts:<br>    manager: auto<br>  tags:<br>    - always<br><br>- name: show package version (RHEL 7)<br>  debug:<br>    # This doesn't work. Doesn't work with a dash in the name<br>    # var: ansible_facts.packages.rh-haproxy18-haproxy.version<br>    var: ansible_facts.packages | json_query('"rh-haproxy18-haproxy"&#91;*].version') | join(' ')<br>  when:<br>    - ansible_os_family == "RedHat"<br>    - ansible_distribution_major_version | int == 7<br>  tags:<br>    - always<br><br>- name: Set fact for haproxy version (RHEL 7)<br>  set_fact:<br>    stat_install_haproxy_haproxy_version: "{{ ansible_facts.packages | json_query('\"rh-haproxy18-haproxy\"&#91;*].version') | join(' ') }}"<br>  when:<br>    - ansible_os_family == "RedHat"<br>    - ansible_distribution_major_version | int == 7<br>    - ansible_facts.packages | json_query('"rh-haproxy18-haproxy"&#91;*].version') | join(' ') is defined<br>  tags:<br>    - always<br><br>- name: install-haproxy | show haproxy version<br>  debug: var=stat_install_haproxy_haproxy_version<br>  tags:<br>    - always<br><br>- name: Generate haproxy config (RHEL7)<br>  template:<br>    src: templates/haproxy.cfg.j2<br>    dest: "{{ install_haproxy_config_dir }}/haproxy.cfg"<br>    validate: haproxy -f %s -c -q<br>  environment:<br>    PATH: "/usr/sbin:/usr/local/sbin:/sbin:{{ install_haproxy_bin_dir }}"<br>  notify:<br>    - reload haproxy<br>  when:<br>    - ansible_os_family == "RedHat"<br>    - ansible_distribution_major_version | int == 7<br>  tags:<br>    - config</code></pre>



<p>And then a template file which applies different configuration options depending on the package version.</p>



<p>Example Ansible template file:</p>



<pre class="wp-block-code"><code># templates/haproxy.cfg.j2<br><br># {{ ansible_managed | comment }}<br><br>{% if stat_install_haproxy_haproxy_version is version('2.0', '&gt;=') %}<br>    config here only for version greater or equal to 2.0<br>{% else %}<br>    config here for version less than 2.0<br>{% endif %}<br><br># {{ ansible_managed | comment }}</code></pre>



<p>The above example isn&#8217;t complete, some variables need to be defined. But you get the idea.</p>



<h2 class="wp-block-heading">Conclusion</h2>



<p>That&#8217;s it. Not exactly straight forward, but the example above should be enough to understand how to accomplish getting an OS package version using Ansible. This even works when there is a dash in the package name.</p>



<p>Want another interesting <a href="https://ryandaniels.ca/blog/tag/ansible/">Ansible</a> example? Check out <a href="https://ryandaniels.ca/blog/ansible-quick-tip-how-to-add-an-inline-comment/">How to add an Inline Comment using Ansible</a>.</p>
<p>The post <a href="https://ryandaniels.ca/blog/ansible-get-os-package-version-with-dash/">Use Ansible to get OS package version (even with a dash)</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2909</post-id>	</item>
		<item>
		<title>Run different Linux program based on current directory (using Bash shell)</title>
		<link>https://ryandaniels.ca/blog/run-different-linux-program-based-on-current-directory-using-bash-shell/</link>
		
		<dc:creator><![CDATA[Ryan Daniels]]></dc:creator>
		<pubDate>Sun, 26 Nov 2023 20:47:29 +0000</pubDate>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Bash]]></category>
		<guid isPermaLink="false">https://ryandaniels.ca/?p=2901</guid>

					<description><![CDATA[<p>This provides a way for using different versions of a program based on the current directory name. By adding this example code to the .bashrc file, users can run a unique terraform version based on the directory name.</p>
<p>The post <a href="https://ryandaniels.ca/blog/run-different-linux-program-based-on-current-directory-using-bash-shell/">Run different Linux program based on current directory (using Bash shell)</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Sometimes I want to use a specific version of a program, depending on the directory I&#8217;m currently in. With no obvious solution from <a href="https://stackoverflow.com/questions/tagged/linux+shell" target="_blank" rel="noreferrer noopener">Stack Overflow</a>, I&#8217;ll document my own.</p>



<p>I find this useful for my infrastructure as code configuration with terraform. Each directory is a different environment or site, and I can use different versions of terraform based on the name of the directory.</p>



<p>This is for bash shell on Linux. Tested on bash version 4.3 or newer. Might work on older version too.</p>



<p>Add this code to your .bashrc file:</p>



<pre class="wp-block-code"><code>function terraform () {
  case "${PWD##*/}" in
    *env-2023*) ~/terraform_1.6.2 "$@";;
    *) ~/terraform_0.11.15 "$@";; # default case
  esac
}</code></pre>



<p>Then log out and log back in.</p>



<h2 class="wp-block-heading">What is this doing?</h2>



<p>When you run the command &#8220;terraform&#8221;, your current directory is checked. If you are in a directory that has &#8220;env-2023&#8221; anywhere in it, then terraform_1.6.2 will run. Otherwise the (really) old version will run.</p>



<h2 class="wp-block-heading">Conclusion</h2>



<p>With this in your .bashrc file, you can have multiple directory patterns in the case syntax, each running a specific version of an application. I find this helpful when in the process of upgrading terraform config for all of my different environments for my infrastructure as code.</p>



<p>Here are some <a href="https://ryandaniels.ca/blog/tag/linux/">more Linux related posts</a>.</p>
<p>The post <a href="https://ryandaniels.ca/blog/run-different-linux-program-based-on-current-directory-using-bash-shell/">Run different Linux program based on current directory (using Bash shell)</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2901</post-id>	</item>
		<item>
		<title>Docker and Trouble with Red Hat Enterprise Linux 9: iptables</title>
		<link>https://ryandaniels.ca/blog/docker-and-trouble-with-red-hat-enterprise-linux-9-iptables/</link>
		
		<dc:creator><![CDATA[Ryan Daniels]]></dc:creator>
		<pubDate>Sun, 19 Mar 2023 19:18:17 +0000</pubDate>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[RHEL]]></category>
		<guid isPermaLink="false">https://ryandaniels.ca/?p=2846</guid>

					<description><![CDATA[<p>Red Hat Enterprise Linux 9 (RHEL 9) and Docker don't get along very well. Running a container that requires older iptables (and not nftables) can be a problem.</p>
<p>The post <a href="https://ryandaniels.ca/blog/docker-and-trouble-with-red-hat-enterprise-linux-9-iptables/">Docker and Trouble with Red Hat Enterprise Linux 9: iptables</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Red Hat Enterprise Linux 9 (RHEL 9) and Docker don&#8217;t get along very well sometimes. It turns out, running a container that requires older iptables (and not nftables) can be a problem.<br>This is a problem for other Operating Systems too that use nftables, but let&#8217;s focus on RHEL 9 today. </p>



<h2 class="wp-block-heading">Problem with running a newer OS (like RHEL 9)</h2>



<p>Wow, RHEL 9 is using a modern kernel and toolchain. Ok, now I can continue.</p>



<p>Some newer Linux Operating Systems are moving away from <a href="https://en.wikipedia.org/wiki/Iptables" target="_blank" rel="noreferrer noopener">iptables</a> and changing to <a href="https://en.wikipedia.org/wiki/Nftables" target="_blank" rel="noreferrer noopener">nftables</a>. This can be a problem when an app is expecting iptables. Normally the OS can load the older iptables, but you can run into problems when running containers. </p>



<h3 class="wp-block-heading">Error from GitLab Runner</h3>



<p>It&#8217;s even more fun trying to figure out what&#8217;s going on when running on a GitLab Runner.</p>



<p>This is the error from a GitLab Runner job:</p>



<pre class="wp-block-code"><code>ERROR: error during connect: Get https://docker:2376/v1.40/info: dial tcp: lookup docker on 8.8.8.8:53: server misbehaving</code></pre>



<h3 class="wp-block-heading">Error when running Docker container</h3>



<p>This is the error when running a container using Docker:</p>



<pre class="wp-block-code"><code># docker run --rm -it --privileged --name dind docker:19.03-dind

...
INFO&#91;2023-03-18T21:03:46.764203869Z] Loading containers: start.                   
WARN&#91;2023-03-18T21:03:46.774269934Z] Running iptables --wait -t nat -L -n failed with message: `iptables v1.8.4 (legacy): can't initialize iptables table `nat': Table does not exist (do you need to insmod?)
Perhaps iptables or your kernel needs to be upgraded.`, error: exit status 3 
INFO&#91;2023-03-18T21:03:46.801647539Z] stopping event stream following graceful shutdown  error="&lt;nil&gt;" module=libcontainerd namespace=moby
...
failed to start daemon: Error initializing network controller: error obtaining controller instance: failed to create NAT chain DOCKER: iptables failed: iptables -t nat -N DOCKER: iptables v1.8.4 (legacy): can't initialize iptables table `nat': Table does not exist (do you need to insmod?)
Perhaps iptables or your kernel needs to be upgraded.
 (exit status 3)</code></pre>



<p>So here we can see the problem. Our container is trying to use iptables and it&#8217;s not working.</p>



<p>But, if you run a newer Docker in Docker (DinD) container, it works! And then the old container also starts to work (this is, until a reboot of the host). The culprit? iptables, and a clever trick in newer DinD containers to workaround this issue..</p>



<h2 class="wp-block-heading">Enable iptables from inside a Container</h2>



<p>If you run a container as privileged, you can actually trigger the host OS to load the iptables kernel modules! </p>



<p>This was found from Docker in Docker (DinD) adding a <a href="https://github.com/docker-library/docker/blob/849b56e6c81dc509da780121352f844e8f26bb7a/23.0/cli/modprobe.sh" target="_blank" rel="noreferrer noopener">custom modprobe script</a> (called from the <a href="https://github.com/docker-library/docker/blob/94129ecd12de7acbc9d5a15d25d535ee091770b1/23.0/dind/dockerd-entrypoint.sh#L152" target="_blank" rel="noreferrer noopener">entrypoint script</a>), which is essentially just running this command:</p>



<pre class="wp-block-code"><code># ip link show ip_tables</code></pre>



<p>The Docker in Docker modprobe script gives credit to:</p>


<div class="wp-block-image">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="550" height="273" src="https://ryandaniels.ca/wp-content/uploads/2023/02/Luca_Bruno-ip_link_show_module-dark.png" alt="Loading Linux kernel modules the 'alternative' way: 'ip link show $module'. No need for modprobe binary, kernel object files. This fixes the problem with RHEL 9 and iptables with Docker" class="wp-image-2847" srcset="https://ryandaniels.ca/wp-content/uploads/2023/02/Luca_Bruno-ip_link_show_module-dark.png 550w, https://ryandaniels.ca/wp-content/uploads/2023/02/Luca_Bruno-ip_link_show_module-dark-300x149.png 300w" sizes="auto, (max-width: 550px) 100vw, 550px" /></figure></div>


<h2 class="wp-block-heading">Enable iptables on Red Hat Enterprise Linux 9</h2>



<p>But if your container isn&#8217;t using this &#8216;ip link show ip_tables&#8217; trick, the container will have problems. You need to enable the iptables legacy module on your host OS.</p>



<p>To have iptables loaded and ready to go, you can also run the above trick directly on the host. But the &#8220;proper&#8221; way is to use modprobe when the OS boots.</p>



<pre class="wp-block-code"><code># modprobe ip_tables</code></pre>



<p>That will dynamically enable the older iptables. But after a reboot the change is gone, so to make a persistent change:</p>



<pre class="wp-block-code"><code>echo ip_tables &gt; /etc/modules-load.d/ip_tables.conf</code></pre>



<p>Reboot and check:</p>



<pre class="wp-block-code"><code># lsmod|grep -E "^ip_tables|^iptable_filter|^iptable_nat"
ip_tables              28672  0</code></pre>



<p>Now the older containers will also work (that need iptables (legacy).</p>



<h2 class="wp-block-heading">Conclusion</h2>



<p>Red Hat doesn&#8217;t recommend running Docker (instead they recommend Podman). Probably for these reasons. And I wonder if this problem also has something to do with the underlying and undocumented way that <a href="https://ryandaniels.ca/blog/docker-iptables-input-chain/">Docker uses iptables INPUT chain</a>.</p>
<p>The post <a href="https://ryandaniels.ca/blog/docker-and-trouble-with-red-hat-enterprise-linux-9-iptables/">Docker and Trouble with Red Hat Enterprise Linux 9: iptables</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2846</post-id>	</item>
		<item>
		<title>Ansible Quick Tip: How to add an Inline Comment</title>
		<link>https://ryandaniels.ca/blog/ansible-quick-tip-how-to-add-an-inline-comment/</link>
		
		<dc:creator><![CDATA[Ryan Daniels]]></dc:creator>
		<pubDate>Sat, 28 Jan 2023 20:42:09 +0000</pubDate>
				<category><![CDATA[Ansible]]></category>
		<category><![CDATA[Linux]]></category>
		<guid isPermaLink="false">https://ryandaniels.ca/?p=2814</guid>

					<description><![CDATA[<p>How to add an inline comment using Ansible.</p>
<p>The post <a href="https://ryandaniels.ca/blog/ansible-quick-tip-how-to-add-an-inline-comment/">Ansible Quick Tip: How to add an Inline Comment</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>If you&#8217;ve ever wanted to add a comment block to a file with Ansible it is pretty easy. Just add the &#8220;comment&#8221; filter to the text you want to use as a comment. But what if you want to have an inline comment?</p>



<p>For example, in a Linux config file like /etc/hosts you can have Ansible add a comment block:</p>



<pre class="wp-block-code"><code>#
# This is for my NAS
#
192.168.1.100 nas</code></pre>



<p>But, what if you want to have the comment at the end of the line (an inline comment)?</p>



<pre class="wp-block-code"><code>192.168.1.100 nas # This is for my NAS</code></pre>



<h2 class="wp-block-heading">Ansible Comment</h2>



<p>Adding a comment with Ansible is easy.<br>And when adding a comment in a Linux config file, you need to use the # character. <br>This can be accomplished using Ansible&#8217;s &#8220;<a href="https://docs.ansible.com/ansible/2.9/user_guide/playbooks_filters.html#comment-filter">comment filter</a>&#8220;.</p>



<pre class="wp-block-code"><code>ansible_variable1: "192.168.1.100 nas {{ 'This is for my NAS' | comment }}"</code></pre>



<p>The result will be:</p>



<pre class="wp-block-code"><code>TASK &#91;Print normal comment] ********************************************************************************************
ok: &#91;localhost] =&gt; {
    "msg": "#\n# This is for my NAS\n#\n192.168.1.100 nas"
}</code></pre>



<p>And when using something like the Ansible Module <a href="https://docs.ansible.com/ansible/2.9/modules/lineinfile_module.html">lineinfile</a>, you would get:</p>



<pre class="wp-block-code"><code>#
# This is for my NAS
#
192.168.1.100 nas</code></pre>



<h2 class="wp-block-heading">Ansible Inline Comment</h2>



<p>Adding an inline comment with Ansible isn&#8217;t obvious. You can&#8217;t just add the # character as part of the text in the Ansible yaml. Because that&#8217;s actually a comment in the yaml file.<br>You need to use Ansible&#8217;s &#8220;<a href="https://docs.ansible.com/ansible/2.9/user_guide/playbooks_filters.html#comment-filter">comment filter</a>&#8220;, like a normal comment, however you need to change a few options.</p>



<p>Modify the prefix and postfix options for the comment filter:<br></p>



<pre class="wp-block-code"><code>ansible_variable2: "192.168.1.100 nas {{ 'This is for my NAS' | comment('plain', prefix='', postfix='') }}"</code></pre>



<p>The result will be:</p>



<pre class="wp-block-code"><code>TASK &#91;Print inline comment] ********************************************************************************************
ok: &#91;localhost] =&gt; {
    "msg": "192.168.1.100 nas # This is for my NAS\n"
}</code></pre>



<p>And when using something like the Ansible Module <a href="https://docs.ansible.com/ansible/2.9/modules/lineinfile_module.html">lineinfile</a>, you would get:</p>



<pre class="wp-block-code"><code>192.168.1.100 nas # This is for my NAS</code></pre>



<h2 class="wp-block-heading">Demo</h2>



<p>Here is a demo Ansible Playbook to test with.</p>



<pre class="wp-block-code"><code>---
- hosts: localhost
  name: Ansible Inline Comment Demo
  vars:
    my_other_var: "nas"
    ansible_variable1: "{{ 'This is for my NAS' | comment }}\n192.168.1.100 {{ my_other_var }}"
    ansible_variable2: "192.168.1.100 {{ my_other_var }} {{ 'This is for my NAS' | comment('plain', prefix='', postfix='') }}"

  tasks:
    - name: Print normal comment
      debug:
        msg: "{{ ansible_variable1 }}"

    - name: Print inline comment
      debug:
        msg: "{{ ansible_variable2 }}"</code></pre>



<p>If you want to get started with Ansible, check out my post: <a href="https://ryandaniels.ca/blog/getting-started-ansible-ubuntu-centos/">Getting Started with Ansible</a>. It has some Ansible basics that can help you get started.</p>
<p>The post <a href="https://ryandaniels.ca/blog/ansible-quick-tip-how-to-add-an-inline-comment/">Ansible Quick Tip: How to add an Inline Comment</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2814</post-id>	</item>
		<item>
		<title>Helm Post-Renderer and an ugly Windows Batch Script</title>
		<link>https://ryandaniels.ca/blog/helm-post-renderer-and-ugly-windows-batch-script/</link>
		
		<dc:creator><![CDATA[Ryan Daniels]]></dc:creator>
		<pubDate>Sun, 28 Nov 2021 19:36:00 +0000</pubDate>
				<category><![CDATA[Kubernetes]]></category>
		<category><![CDATA[ci/cd]]></category>
		<category><![CDATA[GitLab CI/CD]]></category>
		<category><![CDATA[Helm]]></category>
		<category><![CDATA[IT Automation]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Windows]]></category>
		<guid isPermaLink="false">https://ryandaniels.ca/?p=2592</guid>

					<description><![CDATA[<p>The year is 2021, and I need to write a Windows Batch Script to get Helm Post-Renderer working on Windows so I can deploy my application to Kubernetes.</p>
<p>The post <a href="https://ryandaniels.ca/blog/helm-post-renderer-and-ugly-windows-batch-script/">Helm Post-Renderer and an ugly Windows Batch Script</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>The year is 2021, and I need to write a Windows Batch Script to get Helm Post-Renderer working on Windows so I can deploy my application to Kubernetes.</p>



<span id="more-2592"></span>



<h2 class="wp-block-heading" id="what-is-helm">What is Helm?</h2>



<p>From the <a href="https://helm.sh/" target="_blank" rel="noreferrer noopener">Helm website</a>: &#8220;Helm helps you manage Kubernetes applications&#8221;.<br>If you use Kubernetes, there&#8217;s a good chance you will be using at least some portion of Helm. Helm has many features, and is most well known for Helm Charts. You can (and should) also use Helm to deploy your application to Kubernetes.</p>



<h2 class="wp-block-heading" id="helm-post-renderer">Helm Post-Renderer</h2>



<p>The <a href="https://helm.sh/docs/topics/advanced/" target="_blank" rel="noreferrer noopener">Helm Post-Renderer feature</a> allows Helm to deploy an application using advance configurations using tools like <a href="https://kustomize.io/" target="_blank" rel="noreferrer noopener">Kustomize</a>. </p>



<h2 class="wp-block-heading" id="windows-batch-script-with-helm-post-renderer-and-wsl">Windows Batch Script with Helm Post-Renderer and WSL</h2>



<p>I want my Kubernetes deployment (using Helm and Kustomize) to be able to work on my laptop, and also in a GitLab CI/CD pipeline. And because my Windows laptop has WSL (no WSL2!) I can do a few cool Linux things with it, like directly run Helm commands (Maybe WSL2 also has this problem). If only I could use a <a href="https://ryandaniels.ca/blog/5-reasons-windows-upgrade-to-linux/">real Linux laptop</a> at work, but anyways..</p>



<p>The Helm Post-Renderer gives an error when running a Linux Bash script in WSL. So much to my amazement, in 2021 I needed to write a Windows Batch Script!</p>



<h3 class="wp-block-heading" id="error-message-in-wsl">Error message in WSL</h3>



<p>Running a Helm install/upgrade gives the error:</p>



<pre class="wp-block-code"><code>helm upgrade --install release123 my-charts/app123-charts --version=0.1.0 --namespace=dev1 --values=../values.yaml --post-renderer ./kustomize.sh --debug --dry-run

## Error: error while running post render on files: error while running command \\C\Users\username\helm\my-charts\app123-charts\app-kustomize\kustomize-post-render\kustomize.sh. error output:
## : fork/exec \\C\Users\username\helm\my-charts\app123-charts\app-kustomize\kustomize-post-render\kustomize.sh: %1 is not a valid Win32 application.</code></pre>



<p>Just the error:</p>



<pre class="wp-block-code"><code>%1 is not a valid Win32 application.</code></pre>



<p>Okay, that&#8217;s interesting. Running a helm command gives me a Windows related error. So now we need to do it the Windows way.</p>



<h2 class="wp-block-heading" id="helm-post-renderer-windows-batch-script">Helm Post-Renderer Windows Batch Script</h2>



<p>This Windows Batch Script will work from Windows (kustomize.bat):</p>



<pre class="wp-block-code"><code>@echo off

REM fix mapped drive in TS: https://stackoverflow.com/questions/9013941/how-to-run-batch-file-from-network-share-without-unc-path-are-not-supported-me/34182234#34182234
@pushd %~dp0

REM findstr is pure windows command: https://superuser.com/questions/853580/real-windows-equivalent-to-cat-stdin/1425671#1425671
FINDSTR . &gt; all.yaml

kustomize build . &amp;&amp; del all.yaml || exit 1

@popd

</code></pre>



<p>The above Batch Script also works from a Windows Terminal Server that is mapping a drive.</p>



<h2 class="wp-block-heading" id="helm-post-renderer-linux-bash-script">Helm Post-Renderer Linux Bash script</h2>



<p>For reference, the same in Linux would be (kustomize.sh):</p>



<pre class="wp-block-code"><code>#!/bin/bash

cat &lt;&amp;0 &gt; all.yaml

kustomize build . &amp;&amp; rm all.yaml</code></pre>



<p>Above Linux bash script source: <a href="https://github.com/thomastaylor312/advanced-helm-demos/blob/master/post-render/kustomize/kustomize" target="_blank" rel="noreferrer noopener">Taylor Thomas</a>.</p>



<h2 class="wp-block-heading" id="conclusion">Conclusion</h2>



<p>With this Windows Batch Script, you can run Helm install/upgrade commands directly on your Windows laptop so you can deploy to your local or remote Kubernetes cluster. This can help to debug your true pipeline deployments, if using something like GitLab CI/CD since it&#8217;s now possible to deploy using the same method.</p>
<p>The post <a href="https://ryandaniels.ca/blog/helm-post-renderer-and-ugly-windows-batch-script/">Helm Post-Renderer and an ugly Windows Batch Script</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2592</post-id>	</item>
		<item>
		<title>Secure Docker with iptables firewall and Ansible</title>
		<link>https://ryandaniels.ca/blog/secure-docker-with-iptables-firewall-and-ansible/</link>
		
		<dc:creator><![CDATA[Ryan Daniels]]></dc:creator>
		<pubDate>Sun, 24 May 2020 19:11:41 +0000</pubDate>
				<category><![CDATA[Ansible]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[CentOS]]></category>
		<category><![CDATA[Guide]]></category>
		<category><![CDATA[IT Automation]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<guid isPermaLink="false">https://ryandaniels.ca/?p=2290</guid>

					<description><![CDATA[<figure class="alignleft wp-block-image size-thumbnail"><img src="https://ryandaniels.ca/wp-content/uploads/2020/05/punch_hole_eye-200x300.jpg" alt="" class="wp-image-2489"/></figure>
<p>Out of the box, security with Docker (and Docker Swarm) over the network is bad. Okay, that's not entirely true. Out of the box when you have no containers started, it's fine. But after you start a container, and if you publish a port, they are exposed to the outside world by default. And it's not easy to fix. You need to create a custom Docker firewall with iptables.<br />
&#160;</p>
<p>The post <a href="https://ryandaniels.ca/blog/secure-docker-with-iptables-firewall-and-ansible/">Secure Docker with iptables firewall and Ansible</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Out of the box, security with Docker (and Docker Swarm) over the network is bad. Okay, that&#8217;s not entirely true. Out of the box when you have no containers started, it&#8217;s fine. But after you start a container, and if you publish a port, they are exposed to the outside world by default. And it&#8217;s not easy to fix. You need to create a custom Docker firewall with iptables.</p>



<p>Let&#8217;s discuss the background of firewall issues with Docker, and a working solution for my use case (either setup manually or using Ansible). By the end we will use a firewall on the server to lock down everything by default, only allowing my trusted IPs! With the option to open specified ports publicly (like SSH).</p>



<p>Note: This solution works with CentOS 7, RHEL 7, Ubuntu 18.04, and Ubuntu 20.04.</p>



<span id="more-2290"></span>


				<div class="wp-block-uagb-table-of-contents uagb-toc__align-left uagb-toc__columns-1  uagb-block-5708b17e-d0f5-4528-8221-706c39a8a865      "
					data-scroll= ""
					data-offset= "30"
					style=""
				>
				<div class="uagb-toc__wrap">
						<div class="uagb-toc__title">
							Table Of Contents						</div>
																						<div class="uagb-toc__list-wrap ">
						<ol class="uagb-toc__list"><li class="uagb-toc__list"><a href="#background" class="uagb-toc-link__trigger">Background</a><li class="uagb-toc__list"><a href="#roll-your-own-solution" class="uagb-toc-link__trigger">Roll your own solution</a><li class="uagb-toc__list"><a href="#problems-i-need-to-solve" class="uagb-toc-link__trigger">Problems I need to solve</a><li class="uagb-toc__list"><a href="#solution-docker-firewall-with-iptables-and-ipset" class="uagb-toc-link__trigger">Solution &#8211; Docker firewall with iptables and ipset</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#high-level-summary" class="uagb-toc-link__trigger">High level summary</a></li></ul></li><li class="uagb-toc__list"><a href="#warnings" class="uagb-toc-link__trigger">Warnings</a><li class="uagb-toc__list"><a href="#the-manual-way" class="uagb-toc-link__trigger">The manual way</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#prep" class="uagb-toc-link__trigger">Prep</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#configure-ipset" class="uagb-toc-link__trigger">Configure ipset</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#configure-iptables" class="uagb-toc-link__trigger">Configure iptables</a></li></ul></li></ul></li><li class="uagb-toc__list"><a href="#the-automatic-way-with-ansible" class="uagb-toc-link__trigger">The Automatic way with Ansible</a><li class="uagb-toc__list"><a href="#conclusion" class="uagb-toc-link__trigger">Conclusion</a><li class="uagb-toc__list"><a href="#references" class="uagb-toc-link__trigger">References</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#background-for-dockers-undocumented-use-of-iptables-input-chain" class="uagb-toc-link__trigger">Background for Docker&#039;s undocumented use of iptables INPUT chain</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#references-and-links" class="uagb-toc-link__trigger">References and links</a></ul></ul></ul></ol>					</div>
									</div>
				</div>
			


<h2 class="wp-block-heading">Background</h2>



<div class="wp-block-image"><figure class="alignright size-medium"><img loading="lazy" decoding="async" width="400" height="600" src="https://ryandaniels.ca/wp-content/uploads/2020/05/punch_hole_eye-400x600.jpg" alt="Docker punches a hole through firewall" class="wp-image-2489" srcset="https://ryandaniels.ca/wp-content/uploads/2020/05/punch_hole_eye-400x600.jpg 400w, https://ryandaniels.ca/wp-content/uploads/2020/05/punch_hole_eye-480x720.jpg 480w, https://ryandaniels.ca/wp-content/uploads/2020/05/punch_hole_eye-200x300.jpg 200w, https://ryandaniels.ca/wp-content/uploads/2020/05/punch_hole_eye.jpg 533w" sizes="auto, (max-width: 400px) 100vw, 400px" /><figcaption><sup>Image credit: <a rel="noreferrer noopener" href="https://www.pexels.com/photo/brown-human-eye-2873058/" target="_blank">Jonathan Borba</a></sup></figcaption></figure></div>



<p>Firstly, even if you were using a firewall like iptables, Docker makes that useless. Docker punches a whole right through your firewall!</p>



<p>And if you <a href="https://ryandaniels.ca/blog/ansible-manage-firewalld/">try another firewall, like firewalld</a>? Docker Swarm (and even regular Docker) with firewalld is a complete mess. Restart the firewalld service, or change the firewalld config, and you lost all the config that Docker needed. Now you have to restart Docker! What happens if the firewalld service failed and restarted? That Docker Swarm node is out of service.</p>



<p>Keep in mind, when I mention Docker, it means the regular Docker Engine. Docker Swarm means SwarmKit, which is the newer way of using Swarm. (The old way is the standalone solution which is old and not referenced at all here).</p>



<p>There are many attempts to solve this problem by users of Docker. Unfortunately the Docker team has been pretty quiet about these issues. They recommend a manual user solution, and to disable Docker&#8217;s use of iptables. I&#8217;m speculating here, but it seems like any future change from Docker will likely be a breaking change since this is a complicated issue to fix.</p>



<p>The attempted solutions (from users) are not very straight forward for a normal Docker user. And that&#8217;s the real issue. On top of that, out of the box (after you start one service with a published port), there is no security at the network layer. Anyone can connect to an exposed container&#8217;s port. Most importantly, even if you think you have a firewall protecting you.. Wrong, you don&#8217;t! With normal Docker, you can bind your service to your localhost which helps. But what about Docker Swarm? Nope, that doesn&#8217;t work.</p>



<p>There&#8217;s a great article about &#8220;<a rel="noreferrer noopener" href="https://utcc.utoronto.ca/~cks/space/blog/tech/SecurityChoiceProblem" data-type="URL" data-id="https://utcc.utoronto.ca/~cks/space/blog/tech/SecurityChoiceProblem" target="_blank">The problem of forcing users to make choices (in security)</a>.&#8221; Definitely worth the read!</p>



<h2 class="wp-block-heading">Roll your own solution</h2>



<p>Until this is actually addressed in Docker, our only hope is to find the simplest solution possible. And turning off iptables integration in Docker is unacceptable (which is constantly recommended by the Docker developers). The other option is to move on from Docker and/or Docker Swarm. I hear this thing called Kubernetes is pretty great. Anyways, back to Docker. <br>Many people have spent hours trying to learn, and figure out iptables as a solution to this. You need to roll your own solution apparently! So iptables is probably the best approach, since that is what Docker needs to use to do it&#8217;s magic (and most other firewalls are just a wrapper for iptables anyway depending on your OS).</p>



<p>Something <s>fun</s> I found out while testing this, <a href="https://ryandaniels.ca/blog/docker-iptables-input-chain/">Docker Swarm uses iptables in an undocumented way</a>. Docker Swarm uses the iptables INPUT chain! It&#8217;s only for encrypted overlay networks. But it&#8217;s not very fun realizing that! All of a sudden rules are being appended to the INPUT chain.</p>



<p>Okay, enough backstory. On with my futile attempt to roll my own solution. This took way longer than I thought it would! But it does work! Currently it works at least.. (That&#8217;s why I use the word futile!)</p>



<h2 class="wp-block-heading">Problems I need to solve</h2>



<ol class="wp-block-list"><li>Only allow traffic from multiple &#8220;trusted&#8221; IP addresses to my servers. Not all of these IPs will be in the same &#8220;IP block/range&#8221; either. This will be to all services running directly on the server, and also all of the Docker containers.</li><li>Let only specific ports be publicly accessible, like SSH.</li><li>I&#8217;m not managing which containers are accessible through the firewall. Meaning, I&#8217;m not manually adding ports into my firewall solution. That kind of manual work is not happening. I need a dynamic, and flexible solution that blocks by default except to my trusted IPs.</li><li>The firewall solution must be simple. More complex means more room for error.</li><li>The firewall solution must not impact performance significantly.</li><li>Restarting the firewall won&#8217;t break Docker. </li><li>Restarting Docker won&#8217;t break the firewall.</li><li>No impact to running server processes or Docker services when making a change. Things need to keep working! <br>Firewall changes need to happen online and not impact Docker. Meaning I can&#8217;t be restarting Docker because I made a firewall change.<br>Docker &#8220;changes&#8221; need to happen online. Meaning I can&#8217;t be restarting the firewall because I made a Docker change. (A Docker &#8220;change&#8221; means starting/stopping a container).</li></ol>



<p>That sounds very simple! Unfortunately, it is not with Docker (and Docker Swarm).</p>



<h2 class="wp-block-heading">Solution &#8211; Docker firewall with iptables and ipset</h2>



<p>If you don&#8217;t know much about iptables, or ipset, that&#8217;s okay. You don&#8217;t really need to know. You should have some basic understandings though, so you don&#8217;t break your servers! The <a rel="noreferrer noopener" href="https://wiki.archlinux.org/index.php/Iptables#Chains" target="_blank">Arch Linux wiki</a> has great information about iptables. Including this helpful <a rel="noreferrer noopener" href="https://www.frozentux.net/iptables-tutorial/chunkyhtml/images/tables_traverse.jpg" target="_blank" rel="lightbox[2290]">visual</a> about the iptables flow.</p>



<p>Note: This solution works with CentOS 7, RHEL 7, Ubuntu 18.04, and Ubuntu 20.04.</p>



<h3 class="wp-block-heading">High level summary</h3>



<p>iptables with ipset will handle all of this for us. And keep our servers, and Docker locked down from the network level. </p>



<p>In this solution, we will use the iptables INPUT chain to jump to another chain (let&#8217;s call our custom chain FILTERS), but return if there&#8217;s some legitimate looking traffic, so the Swarm overlay can do whatever it wants in INPUT with IPSEC, or whatever it is appending to INPUT.<br>Inside our custom chain FILTERS, we drop everything that doesn&#8217;t match our trusted list of IPs. We also allow our SSH port and the basic default iptables stuff.. You can also add any OS port to be publicly accessible.<br>The DOCKER-USER chain only needs a few entries. Any internal Docker traffic is returned, and it will drop any other traffic that&#8217;s not in our allowed IP list. You can also add any container port to be publicly accessible.</p>



<p>One of the dangers with this approach is if Docker changes it&#8217;s behaviour our firewall could break, or our Docker services could stop working. Since Docker doesn&#8217;t offer any solution for their users, we need our own solution. So keep in mind that you need to test this when upgrading to a new version of Docker. That is the trade-off with a &#8220;roll your own&#8221; solution. But what choice do we have?</p>



<p>I&#8217;ve created an <a rel="noreferrer noopener" href="https://galaxy.ansible.com/ryandaniels/iptables_docker" target="_blank">Ansible Role: iptables for Docker</a>, on <a rel="noreferrer noopener" href="https://github.com/ryandaniels/ansible-role-iptables-docker" target="_blank">GitHub</a> and <a rel="noreferrer noopener" href="https://galaxy.ansible.com/ryandaniels/iptables_docker" target="_blank">Ansible Galaxy</a>.</p>



<h2 class="wp-block-heading">Warnings</h2>



<p><strong>Warning: Be sure you have everything needed in your configuration. Once the iptables firewall is started it blocks anything that wasn’t added! Don&#8217;t lock yourself out of your server. Be sure to have another way to connect, like a console.</strong></p>



<p><strong>Disclaimer: Keep in mind, you should test all of this in your lab or staging environments. I can’t guarantee this will be 100% safe and can’t be held responsible for anything going wrong!</strong></p>



<p><strong>SELinux Bug</strong>: If using SELinux, currently there&#8217;s a bug with SELinux which prevents saving the iptables rules to the iptables.save file.<br><strong>Impact</strong>: Saving the iptables rules a 2nd time will silently fail. Workaround has been added so SELinux allows chmod to interact with the iptables.save file. <a rel="noreferrer noopener" href="https://github.com/ryandaniels/ansible-role-iptables-docker/blob/master/README.md#selinux-manual-workaround-for-iptables-and-chmod" target="_blank">See notes on GitHub for SELinux workaround steps</a>. Alternatively you could disable SELinux, but that&#8217;s not recommended. Bug report: <a rel="noreferrer noopener" href="https://bugs.centos.org/view.php?id=12648" target="_blank">https://bugs.centos.org/view.php?id=12648</a></p>



<h2 class="wp-block-heading">The manual way</h2>



<p>Run the commands below. These commands are only for CentOS/RHEL 7. If you don&#8217;t want to do this manually, jump to the <a href="#the-automatic-way-with-ansible">Automatic section, using Ansible</a> (which also works with Ubuntu).</p>



<h3 class="wp-block-heading">Prep</h3>



<p>Make note of what you already have in iptables (if you are already using it). Be sure you have some background with iptables, since you could break things!</p>



<pre class="wp-block-code"><code># iptables -nvL --line-numbers</code></pre>



<p>Install the required packages for CentOS / RHEL:</p>



<pre class="wp-block-code"><code># yum install iptables iptables-services ipset ipset-service</code></pre>



<h3 class="wp-block-heading">Configure ipset</h3>



<p>ipset allows you to add a list of IPs that you can use with iptables. In our case, we will add a list of IPs we want to be able to connect to our servers.</p>



<p>Configure ipset with a setname of <code>ip_allow</code>.<br>Add IPs you want to allow. Change the IPs below to your actual trusted/allowed IP ranges. Be sure to include your Docker server IPs here, because if you don&#8217;t they can&#8217;t communicate with eachother:</p>



<pre class="wp-block-code"><code># mkdir -p /etc/sysconfig/ipset.d
# vi /etc/sysconfig/ipset.d/ip_allow.set

create -exist ip_allow hash:ip family inet hashsize 1024 maxelem 65536
add ip_allow 192.168.1.123
add ip_allow 192.168.100.0/24
add ip_allow 192.168.101.0/24
add ip_allow 192.168.102.0/24</code></pre>



<p>Start, and Enable the ipset service:</p>



<pre class="wp-block-code"><code># systemctl status ipset
# systemctl start ipset
# systemctl enable ipset</code></pre>



<p>See what ipset has in it&#8217;s loaded configuration:</p>



<pre class="wp-block-code"><code># ipset list | head</code></pre>



<p>Important: Make note of the size of &#8220;Number of entries&#8221;. If that number is close to the maxelem size (65536), then you need to delete the ipset and re-create it with a larger max size. If you only use a few IP ranges like above, you don&#8217;t need to worry and will be well below the limit.</p>



<h3 class="wp-block-heading">Configure iptables</h3>



<p>Next up, iptables. iptables is our solution for a firewall. We will create a file with our rules and then add those rules into iptables. The important part is to not flush the existing rules if you are already using Docker  (or Docker Swarm) on your server.</p>



<p>Create an iptables file to use with iptables-restore, to add the rules into iptables:</p>



<pre class="wp-block-code"><code># vi iptables-rules.txt</code></pre>



<p>Add below to the file. There is a lot going on here..</p>



<pre class="wp-block-code"><code>*filter
:DOCKER-USER - &#91;0:0]
:FILTERS - &#91;0:0]
#Can't flush INPUT. wipes out docker swarm encrypted overlay rules
#-F INPUT
#Use ansible or run manually once instead to add -I INPUT -j FILTERS
#-I INPUT -j FILTERS
-F DOCKER-USER
-A DOCKER-USER -m state --state RELATED,ESTABLISHED -j RETURN
-A DOCKER-USER -i docker_gwbridge -j RETURN
-A DOCKER-USER -s 172.18.0.0/16 -j RETURN
-A DOCKER-USER -i docker0 -j RETURN
-A DOCKER-USER -s 172.17.0.0/16 -j RETURN
#Below Docker ports open to everyone if uncommented
#-A DOCKER-USER -p tcp -m tcp -m multiport --dports 8000,8001 -j RETURN
#-A DOCKER-USER -p udp -m udp -m multiport --dports 9000,9001 -j RETURN
-A DOCKER-USER -m set ! --match-set ip_allow src -j DROP
-A DOCKER-USER -j RETURN
-F FILTERS
#Because Docker Swarm encrypted overlay network just appends rules to INPUT. Has to be at top unfortunately
-A FILTERS -p udp -m policy --dir in --pol ipsec -m udp -m set --match-set ip_allow src --dport 4789 -j RETURN
-A FILTERS -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FILTERS -p icmp -j ACCEPT
-A FILTERS -i lo -j ACCEPT
#Below OS ports open to everyone if uncommented
-A FILTERS -p tcp -m state --state NEW -m tcp -m multiport --dports 22 -j ACCEPT
#-A FILTERS -p udp -m udp -m multiport --dports 53,123 -j ACCEPT
-A FILTERS -m set ! --match-set ip_allow src -j DROP
-A FILTERS -j RETURN
COMMIT</code></pre>



<p>Use iptables-restore to add the above rules into iptables. The very important flag is <code>-n</code>. That makes sure we don&#8217;t flush the iptables rules if we have rules already in Docker (or Docker Swarm).</p>



<pre class="wp-block-code"><code># iptables-restore -n &lt; iptables-rules.txt</code></pre>



<p>Next, add a rule to the INPUT chain, so we start using the new rules in FILTERS. It has to be at the top, and only needs to be added once:</p>



<pre class="wp-block-code"><code># iptables -I INPUT 1 -j FILTERS</code></pre>



<p>Save the iptables rules:</p>



<pre class="wp-block-code"><code># /usr/libexec/iptables/iptables.init save</code></pre>



<p>That will save any existing and our new iptables rules to the iptables configuration file so it will be persistent after a reboot.</p>



<p>In addition, it was needed to run the above iptables command manually since we want to ensure it&#8217;s only inserted once. And we can&#8217;t flush the INPUT chain to ensure that since Docker Swarm could have rules there already.</p>



<p>Start and Enable the iptables service:</p>



<pre class="wp-block-code"><code># systemctl status iptables
# systemctl start iptables
# systemctl enable iptables</code></pre>



<p>If you want to customize the iptables rules to allow more ports to be open to everyone, just add the port to the appropriate rule in the iptables file (tcp or udp), then re-run the same commands from above:</p>



<pre class="wp-block-code"><code># iptables-restore -n &lt; iptables-rules.txt
# /usr/libexec/iptables/iptables.init save</code></pre>



<p><strong>Don&#8217;t miss the <a href="#warnings">Warnings</a> from above! Especially about SELinux.</strong></p>



<p>If you don&#8217;t want to do all of that manually, and you use Ansible, then do this instead..</p>



<h2 class="wp-block-heading">The Automatic way with Ansible</h2>



<p>Manually run all of the above, on every Docker server is not ideal. Let&#8217;s use Ansible instead!</p>



<p>I&#8217;ve created an <a rel="noreferrer noopener" href="https://galaxy.ansible.com/ryandaniels/iptables_docker" target="_blank">Ansible Role: iptables for Docker</a>, on <a rel="noreferrer noopener" href="https://github.com/ryandaniels/ansible-role-iptables-docker" target="_blank">GitHub</a> and <a rel="noreferrer noopener" href="https://galaxy.ansible.com/ryandaniels/iptables_docker" target="_blank">Ansible Galaxy</a>. </p>



<p>This works on CentOS 7, RHEL 7, Ubuntu 18.04, and Ubuntu 20.04.</p>



<p>Install the Ansible Role using Ansible Galaxy:</p>



<pre class="wp-block-code"><code>$ ansible-galaxy install ryandaniels.iptables_docker</code></pre>



<p>Or, clone the GitHub project:</p>



<pre class="wp-block-code"><code>$ git clone https://github.com/ryandaniels/ansible-role-iptables-docker.git roles/ryandaniels.iptables_docker</code></pre>



<p>Create the Ansible Playbook, called iptables_docker.yml:</p>



<pre class="wp-block-code"><code>---
- hosts: '{{ inventory }}'
  become: yes
  vars:
    # Use this role
    iptables_docker_managed: true
  roles:
  - ryandaniels.iptables_docker</code></pre>



<p>Make configuration changes to add desired IP addresses and ports as needed.</p>



<p><strong>Don&#8217;t miss the <a href="#warnings">Warnings</a> from above!</strong></p>



<p>Then run the playbook:</p>



<pre class="wp-block-code"><code>$ ansible-playbook iptables_docker.yml --extra-vars "inventory=centos7" -i hosts-dev</code></pre>



<h2 class="wp-block-heading">Conclusion</h2>



<p>In conclusion, now we have secured our Docker (and Docker Swarm) environments using Ansible to perform the installation and configuration of iptables! None of our Docker published ports are exposed to the world, unless we want them to be! We have created a custom Docker firewall with iptables. Hopefully, some day this will be the default behaviour and shipped with Docker out of the box! Dare to dream. Security is hard.</p>



<h2 class="wp-block-heading">References</h2>



<h3 class="wp-block-heading">Background for Docker&#8217;s undocumented use of iptables INPUT chain</h3>



<p><a href="https://ryandaniels.ca/blog/docker-iptables-input-chain/">See my previous post about this</a>.</p>



<h3 class="wp-block-heading">References and links</h3>



<p>References, notes, and links about the Docker firewall discussion:</p>



<ul class="wp-block-list"><li><a rel="noreferrer noopener" href="https://docs.docker.com/network/overlay/#encrypt-traffic-on-an-overlay-network" target="_blank">Docker Documentation &#8211; Overlay Networks</a></li><li><a rel="noreferrer noopener" href="https://github.com/docker/for-linux/issues/690" target="_blank">Docker bypasses ufw firewall rules</a></li><li><a rel="noreferrer noopener" href="https://unrouted.io/2017/08/15/docker-firewall/" target="_blank">unrouted</a> &#8211; Solution using iptables. Not for Swarm. It clobbers the INPUT chain, which is used by encrypted overlay with Docker Swarm</li><li><a rel="noreferrer noopener" href="https://github.com/moby/moby/issues/22054" target="_blank">The big thread about Docker and a firewall</a></li><li><a rel="noreferrer noopener" href="https://wiki.archlinux.org/index.php/Iptables#Chains" target="_blank">Arch Linux wiki to the rescue to show iptables</a> flow which links to a <a rel="noreferrer noopener" href="https://www.frozentux.net/iptables-tutorial/chunkyhtml/images/tables_traverse.jpg" target="_blank" rel="lightbox[2290]">great visual</a><br><br></li></ul>
<p>The post <a href="https://ryandaniels.ca/blog/secure-docker-with-iptables-firewall-and-ansible/">Secure Docker with iptables firewall and Ansible</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2290</post-id>	</item>
		<item>
		<title>How to fix Ubuntu 20.04 in 1 step</title>
		<link>https://ryandaniels.ca/blog/how-to-fix-ubuntu-20-04-in-1-step/</link>
		
		<dc:creator><![CDATA[Ryan Daniels]]></dc:creator>
		<pubDate>Sat, 23 May 2020 20:40:59 +0000</pubDate>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<guid isPermaLink="false">https://ryandaniels.ca/?p=2427</guid>

					<description><![CDATA[<p>There's not a lot wrong with Ubuntu 20.04. So it's pretty easy to fix the one thing that's missing! Hint: Install the Cinnamon Desktop.</p>
<p>The post <a href="https://ryandaniels.ca/blog/how-to-fix-ubuntu-20-04-in-1-step/">How to fix Ubuntu 20.04 in 1 step</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Ubuntu 20.04 was recently released! <br>Overall, it&#8217;s great, and it works very well. But I did have one problem with it. It&#8217;s missing the Cinnamon Desktop.</p>



<p>I fixed it by running one command:</p>



<pre class="wp-block-code"><code>$ sudo apt install cinnamon-desktop-environment</code></pre>



<p>After it&#8217;s installed, reboot your computer. Then, before logging in, click the gear icon and change your session to Cinnamon.</p>



<p>Now everything is so much better!</p>



<h2 class="wp-block-heading">Cinnamon Desktop</h2>



<p>This will install the <a rel="noreferrer noopener" href="https://projects.linuxmint.com/cinnamon/" target="_blank">Cinnamon Desktop Environment</a> for you. Which was initially developed for Linux Mint.</p>



<div class="wp-block-image"><figure class="aligncenter size-large"><a href="https://ryandaniels.ca/wp-content/uploads/2020/05/Ubuntu_20.04_Cinnamon_Desktop.png" rel="lightbox[2427]"><img loading="lazy" decoding="async" width="1152" height="720" src="https://ryandaniels.ca/wp-content/uploads/2020/05/Ubuntu_20.04_Cinnamon_Desktop-1152x720.png" alt="Cinnamon Desktop on Ubuntu 20.04" class="wp-image-2438" srcset="https://ryandaniels.ca/wp-content/uploads/2020/05/Ubuntu_20.04_Cinnamon_Desktop-1152x720.png 1152w, https://ryandaniels.ca/wp-content/uploads/2020/05/Ubuntu_20.04_Cinnamon_Desktop-800x500.png 800w, https://ryandaniels.ca/wp-content/uploads/2020/05/Ubuntu_20.04_Cinnamon_Desktop-300x188.png 300w, https://ryandaniels.ca/wp-content/uploads/2020/05/Ubuntu_20.04_Cinnamon_Desktop-768x480.png 768w, https://ryandaniels.ca/wp-content/uploads/2020/05/Ubuntu_20.04_Cinnamon_Desktop-1200x750.png 1200w, https://ryandaniels.ca/wp-content/uploads/2020/05/Ubuntu_20.04_Cinnamon_Desktop.png 1440w" sizes="auto, (max-width: 1152px) 100vw, 1152px" /></a></figure></div>



<p>The main downside with this approach is you&#8217;ll probably be using this version of Cinnamon Desktop for a while. Packages don&#8217;t update very often in Ubuntu. However, in general not being on the newest of the new does bring stability.</p>



<p>If you still use Windows you are missing out. You should think about <a href="https://ryandaniels.ca/blog/5-reasons-windows-upgrade-to-linux/">switching to Linux</a>.</p>



<p>It&#8217;s amazing! Give it a try.</p>
<p>The post <a href="https://ryandaniels.ca/blog/how-to-fix-ubuntu-20-04-in-1-step/">How to fix Ubuntu 20.04 in 1 step</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2427</post-id>	</item>
		<item>
		<title>Docker and the iptables INPUT chain</title>
		<link>https://ryandaniels.ca/blog/docker-iptables-input-chain/</link>
		
		<dc:creator><![CDATA[Ryan Daniels]]></dc:creator>
		<pubDate>Tue, 19 May 2020 01:02:55 +0000</pubDate>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Security]]></category>
		<guid isPermaLink="false">https://ryandaniels.ca/?p=2393</guid>

					<description><![CDATA[<p>When testing Docker and iptables I stumbled upon something interesting. It appears Docker uses the iptables INPUT chain in an undocumented way. Well that's interesting..</p>
<p>The post <a href="https://ryandaniels.ca/blog/docker-iptables-input-chain/">Docker and the iptables INPUT chain</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>When testing Docker and iptables I stumbled upon something interesting. It appears Docker uses the iptables INPUT chain in an undocumented way. Well that&#8217;s interesting.. Why Docker, Why?</p>



<p>I could find pretty much nothing about this, anywhere.</p>



<p>Wait, let&#8217;s take a step back. What am I talking about?</p>



<p>I was testing iptables with Docker. What a nightmare. Anyways, I noticed something strange with my three node Docker Swarm test VMs. Some very strange rules at the top of the iptables INPUT chain.</p>



<pre class="wp-block-code"><code># iptables -nvL INPUT
Chain INPUT (policy ACCEPT 33477 packets, 8115K bytes)
 pkts bytes target     prot opt in     out     source               destination
    0     0 ACCEPT     udp  --  *      *       0.0.0.0/0            0.0.0.0/0            policy match dir in pol ipsec udp dpt:4789 u32 "0x0>>0x16&amp;0x3c@0xc&amp;0xffffff00=0x100600"
    0     0 DROP       udp  --  *      *       0.0.0.0/0            0.0.0.0/0            udp dpt:4789 u32 "0x0>>0x16&amp;0x3c@0xc&amp;0xffffff00=0x100600"
   21  3669 ACCEPT     udp  --  *      *       0.0.0.0/0            0.0.0.0/0            policy match dir in pol ipsec udp dpt:4789 u32 "0x0>>0x16&amp;0x3c@0xc&amp;0xffffff00=0x100100"
    0     0 DROP       udp  --  *      *       0.0.0.0/0            0.0.0.0/0            udp dpt:4789 u32 "0x0>>0x16&amp;0x3c@0xc&amp;0xffffff00=0x100100"
    1   101 ACCEPT     udp  --  *      *       0.0.0.0/0            0.0.0.0/0            policy match dir in pol ipsec udp dpt:4789 u32 "0x0>>0x16&amp;0x3c@0xc&amp;0xffffff00=0x100200"
    0     0 DROP       udp  --  *      *       0.0.0.0/0            0.0.0.0/0            udp dpt:4789 u32 "0x0>>0x16&amp;0x3c@0xc&amp;0xffffff00=0x100200"</code></pre>



<p>What is that? Some kind of rules using a Docker port, and something about IPSEC.</p>



<p>Searching the internet has no information about this, that I could find at least. Only some random Docker issues on GitHub. It does have some similar details in the INPUT chain though.</p>



<p>Also found were two references to the Docker documentation.</p>



<p>The Docker documentation does have a pretty good section about <a rel="noreferrer noopener" href="https://docs.docker.com/network/iptables/" target="_blank">iptables</a>. But no mention of the <code>INPUT</code> chain. They very specifically say they only modify the <code>DOCKER-USER</code> and <code>DOCKER</code> chains in iptables.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="907" height="292" src="https://ryandaniels.ca/wp-content/uploads/2020/05/image.png" alt="docker iptables input chain" class="wp-image-2399" srcset="https://ryandaniels.ca/wp-content/uploads/2020/05/image.png 907w, https://ryandaniels.ca/wp-content/uploads/2020/05/image-800x258.png 800w, https://ryandaniels.ca/wp-content/uploads/2020/05/image-300x97.png 300w, https://ryandaniels.ca/wp-content/uploads/2020/05/image-768x247.png 768w" sizes="auto, (max-width: 907px) 100vw, 907px" /><figcaption>Source: <a href="https://docs.docker.com/network/iptables/#add-iptables-policies-before-dockers-rules" target="_blank" rel="noreferrer noopener">Docker documentation for iptables</a></figcaption></figure>



<p>There&#8217;s also some information about the <a rel="noreferrer noopener" href="https://docs.docker.com/network/overlay/#encrypt-traffic-on-an-overlay-network" target="_blank">overlay network in the Docker documentation</a>, but unfortunately it&#8217;s also very high level. No details about the Docker magic that makes all the networking work seamlessly! However, it does mention using IPSEC. Time to do some testing.</p>



<p>When testing in Docker Swarm, by starting containers which use an encrypted overlay I get those iptables rules in the INPUT chain. <s>Fun!</s></p>



<h2 class="wp-block-heading">Conclusion</h2>



<p>Not a very exciting mystery. But very unexpected that Docker is modifying the INPUT chain in iptables! That changes a few thing when trying to secure Docker.. Hopefully other people weren&#8217;t relying on having the last rule in the INPUT chain. </p>



<p>Only Docker knows how their next version of Docker will behave. Anything a user does to try and secure Docker at the network layer is futile.</p>



<p>That being said, I&#8217;ve attempted to <a href="https://ryandaniels.ca/blog/secure-docker-with-iptables-firewall-and-ansible/">secure Docker with an iptables firewall</a>. Check it out!</p>
<p>The post <a href="https://ryandaniels.ca/blog/docker-iptables-input-chain/">Docker and the iptables INPUT chain</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2393</post-id>	</item>
	</channel>
</rss>
