<?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: Guide - Ryan Daniels</title>
	<atom:link href="https://ryandaniels.ca/blog/tag/guide/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description></description>
	<lastBuildDate>Fri, 29 Oct 2021 14:26:40 +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: Guide - Ryan Daniels</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">22628916</site>	<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 fetchpriority="high" 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="(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>Manage firewalld with Ansible</title>
		<link>https://ryandaniels.ca/blog/ansible-manage-firewalld/</link>
		
		<dc:creator><![CDATA[Ryan Daniels]]></dc:creator>
		<pubDate>Sun, 19 Apr 2020 21:45:00 +0000</pubDate>
				<category><![CDATA[Ansible]]></category>
		<category><![CDATA[CentOS]]></category>
		<category><![CDATA[Guide]]></category>
		<category><![CDATA[IT Automation]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Security]]></category>
		<guid isPermaLink="false">https://ryandaniels.ca/?p=2180</guid>

					<description><![CDATA[<p><a href="https://ryandaniels.ca/blog/ansible-manage-firewalld/"><img class="alignleft size-thumbnail wp-image-1170" src="https://ryandaniels.ca/wp-content/uploads/2018/02/Ansible_logo-e1517962271957-150x150.png" alt="Ansible manage firewalld" width="150" height="150" /></a> Managing firewalld can be a tricky. Especially if you have many servers to manage. Ansible can help manage firewalld rules for you!</p>
<p>The post <a href="https://ryandaniels.ca/blog/ansible-manage-firewalld/">Manage firewalld with Ansible</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Managing firewalld can be a tricky. Especially if you have many servers to manage. Ansible can help manage firewalld rules for you!</p>



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



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



<p><a rel="noreferrer noopener" href="https://firewalld.org/" target="_blank">Firewalld</a> is a firewall which runs on many Linux distributions. It is software which runs on a server, and is used to locally secure the server. For example, it can restrict which ports are available for all source IPs, or it can further restrict access by allowing only certain IPs to a specific port (and zone). Check out the <a rel="noreferrer noopener" href="https://firewalld.org/documentation/" target="_blank">documentation</a> to read more about the features of firewalld.</p>



<p>Everything is blocked when firewalld starts! The only exception is for ssh on port 22. This is normally what you want on a new server. </p>



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



<p>However, firewalld isn&#8217;t with out it&#8217;s limitations. To run commands to configure which ports you want to allow through firewalld, you need to have the firewalld service running. But, what if you are adding firewalld to a server that has an application which is already in use? As soon as you start firewalld, it will be blocked!</p>



<p>There are two ways around this. </p>



<ol class="wp-block-list"><li>Copy your firewalld config files in the right place, with all the right ports, zones, etc. And then start firewalld. This can work. But having Ansible copy files around and deal with all that is a challenge since firewalld behaves a certain way.</li><li>Use the &#8220;offline&#8221; firewalld commands!</li></ol>



<p>Let&#8217;s explore options 2. And lucky for us, we want to use Ansible to help us manage this configuration. And, Ansible can make use of &#8220;offline&#8221; mode.<br>But, unlucky for us, the Ansible module which handles firewalld can&#8217;t do everything. (At least not everything that I want it to do).</p>



<p>I want the configuration for firewalld to be as simple as possible. I don&#8217;t want the configuration for services in one place, and the configuration for ports in another.<br>But more importantly, I don&#8217;t want any service interruption.</p>



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



<p>Create my own Ansible role that does what I want.</p>



<p>If you&#8217;re new to Ansible, check out my <a href="https://ryandaniels.ca/blog/getting-started-ansible-ubuntu-centos/">Ansible Getting Started Guide</a>.</p>



<p>I want firewalld to behave in a certain way. Meaning if I have an application already running, and I want firewalld to start restricting access, I don&#8217;t want an outage on that application as soon as I start up the firewalld service on the server.</p>



<h2 class="wp-block-heading">Firewalld Limitations</h2>



<p>Firewalld does have some limitations. You should be aware of this before using it.<br>Anything firewalld is not aware of in the back-end (for example if using iptables), will be removed since firewalld wants to be the single source of truth for firewall rules.<br>This is why firewalld and Docker do not get along.<br>See details from: <a rel="noreferrer noopener" href="https://success.docker.com/article/why-am-i-having-network-problems-after-firewalld-is-restarted" target="_blank">here</a>, <a rel="noreferrer noopener" href="https://www.tripwire.com/state-of-security/devops/psa-beware-exposing-ports-docker/" target="_blank">here</a>, and <a rel="noreferrer noopener" href="https://docs.docker.com/network/iptables/" target="_blank">here</a>.</p>



<p>In case you missed that..<br><strong>Do not use firewalld and Docker.</strong><br><strong>Update</strong>: Instead, if you need a solution to work with Docker try using iptables directly. See my post about <a href="https://ryandaniels.ca/blog/secure-docker-with-iptables-firewall-and-ansible/">securing Docker with iptables and Ansible</a>.</p>



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



<div class="wp-block-image"><figure class="alignright size-medium"><img decoding="async" width="244" height="300" src="https://ryandaniels.ca/wp-content/uploads/2018/02/Ansible_logo-244x300.png" alt="Ansible manage firewalld" class="wp-image-1170" srcset="https://ryandaniels.ca/wp-content/uploads/2018/02/Ansible_logo-244x300.png 244w, https://ryandaniels.ca/wp-content/uploads/2018/02/Ansible_logo.png 256w" sizes="(max-width: 244px) 100vw, 244px" /></figure></div>



<p>You can find my <a rel="noreferrer noopener" href="https://github.com/ryandaniels/ansible-role-firewalld" target="_blank">firewalld Ansible Role on GitHub</a> or in <a rel="noreferrer noopener" href="https://galaxy.ansible.com/ryandaniels/firewalld" target="_blank">Ansible Galaxy</a>.</p>



<p>This Ansible Role manages firewalld in offline and persistent mode only. I don&#8217;t want to mess around with non-persistent changes. And using online mode is not an option.</p>



<p>It uses the <a rel="noreferrer noopener" href="https://docs.ansible.com/ansible/latest/modules/firewalld_module.html" target="_blank">Ansible module for firewalld</a> for a few things, but most changes have to be done using the command module. Specifically: &#8220;firewall-offline-cmd&#8221;.</p>



<p>Why? What&#8217;s the benefit doing it this way? It let&#8217;s you create your own custom <a rel="noreferrer noopener" href="https://firewalld.org/documentation/service/" target="_blank">service</a> in firewalld. Even built-in firewalld services can be used, and easily modified. For example, moving the ssh port from 22 to something else. (Warning, be careful changing your SSH port. You could lock yourself out!)</p>



<p>Here&#8217;s a short example of the configuration:</p>



<pre class="wp-block-code"><code>rhel_firewalld_zone_source:
  - zone: internal
    state: enabled
    source:
      - "192.168.22.64/26"
      - "192.168.23.64/26"

rhel_firewalld_custom_service:
  - name: zabbix-agent
    zone: public
    state: enabled
    port_protocol:
    # - 10050/tcp
      - 3333/tcp
  - name: openvpn
    zone: public
    state: enabled
  - name: app123-public
    zone: public
    state: enabled
    description: app123 firewall rules for public zone
    port_protocol:
      - 5000/tcp
  - name: app123-internal
    zone: internal
    state: enabled
    description: app123 firewall rules for internal zone
    port_protocol:
      - 8080/tcp
      - 9000/tcp</code></pre>



<p>In the variable <code>rhel_firewalld_zone_source</code>:<br>This will configure the Zone named <code>internal</code> to only allow IP ranges that are in <code>source</code>.</p>



<p>In the variable <code>rhel_firewalld_custom_service</code>:<br>This will configure the <code>zabbix-agent</code> service (which is actually built-in) for the zone <code>public</code>, but not use the default port (of 10050, commented out for demonstration). Instead it&#8217;s using port 3333.<br>The <code>openvpn</code> service is added to the zone <code>public</code>, and will just use the default configuration (since this is also a built-in firewalld service). You need to know it&#8217;s built-in, if you don&#8217;t specify a port. So it&#8217;s usually better to just specify a port all the time!<br>Last, there are two custom services, <code>app123-public</code> and <code>app123-internal</code>, which are added to their defined zones. They are also adding port 5000 using tcp (attached to the public zone), and adding ports 8080 and 9000 both using tcp (attached to the internal zone).</p>



<p>If you decide you want to change a port, just remove it from the configuration.</p>



<p><a href="https://github.com/ryandaniels/ansible-role-firewalld" target="_blank" rel="noreferrer noopener">More details are on GitHub. Be sure to read the README!</a></p>



<h2 class="wp-block-heading">Getting Started &#8211; Ansible firewalld</h2>



<p>Install from Ansible Galaxy:</p>



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



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



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



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



<pre class="wp-block-preformatted">---
- hosts: '{{ inventory }}'
  become: yes
  vars:
    # Use this role
    rhel_firewalld_managed: true
  roles:
  - firewalld</pre>



<p>Make configuration changes add desired firewalld services and ports. </p>



<p><strong>Warning: Be sure you have everything needed in your configuration. Once firewalld is started it blocks anything that wasn&#8217;t added!</strong></p>



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



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



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



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



<p>In conclusion, Ansible is now being used to manage firewalld rules! We have a custom firewalld service created using two different zones. The built-in firewalld services are also enabled, but we don&#8217;t really care they are built-in, since we can change the port they use if we want.<br>We have a nice and simple configuration, and this was all done in &#8220;offline&#8221; mode so there was no impact to any existing services using the ports.</p>



<p>Again, your mileage may vary. Always test in your lab or staging environment first! I&#8217;m not responsible for anything you break. </p>



<p>Stay safe!</p>
<p>The post <a href="https://ryandaniels.ca/blog/ansible-manage-firewalld/">Manage firewalld with Ansible</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2180</post-id>	</item>
		<item>
		<title>Find Version Tag for Latest Docker Image</title>
		<link>https://ryandaniels.ca/blog/find-version-tag-latest-docker-image/</link>
		
		<dc:creator><![CDATA[Ryan Daniels]]></dc:creator>
		<pubDate>Thu, 05 Mar 2020 02:17:00 +0000</pubDate>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[Guide]]></category>
		<category><![CDATA[Linux]]></category>
		<guid isPermaLink="false">https://ryandaniels.ca/?p=2196</guid>

					<description><![CDATA[<p>If you've ever used Docker, you've probably used the latest Docker image tag. This is bad. Do not do this! You will be in a situation where you need to find what version you were actually using. This is how you can find the version of that "latest" image you have running.</p>
<p>The post <a href="https://ryandaniels.ca/blog/find-version-tag-latest-docker-image/">Find Version Tag for Latest Docker Image</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>If you&#8217;ve ever used Docker, you&#8217;ve probably used the latest Docker image tag. This is bad. Do not do this! You will be in a situation where you need to find what version you were actually using. This is how you can find the version of that &#8220;latest&#8221; image you have running.</p>



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



<p><strong>Every time</strong> you build a new image, use a <strong>new version</strong> for your image tags. <br><strong>Every time</strong> you pull an image, use a specific image tag <strong>version</strong>.</p>



<p>This <a rel="noreferrer noopener" href="https://vsupalov.com/docker-latest-tag/" target="_blank">article</a> describes why latest is bad.</p>



<p>For me, in this theoretical example.. An image I was using introduced breaking changes. This is fine, since they tagged the new releases as version 2. But, only if I was actually using a specific image version and not latest would this be okay. Latest is latest. So the latest that was version 1, now turned into version 2. And everything broke.</p>



<p>Now that you will never use latest again, you could still have a problem. All those docker containers you have running are using images with the :latest tag. How do you find what version latest was?</p>



<h2 class="wp-block-heading" id="i-hope-you-re-lucky-trick-1">I hope you&#8217;re Lucky.. Trick #1</h2>



<p>Check the labels on your image. If you&#8217;re lucky, the developer added a label to the image with the version. I&#8217;m using the utility <code>jq</code> below. It&#8217;s very helpful, be sure to install it.</p>



<pre class="wp-block-code"><code>$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
traefik             latest              96c63a7d3e50        2 months ago        85.7MB

$ IMAGE_ID=96c63a7d3e50

$ docker image inspect --format '{{json .}}' "$IMAGE_ID" | jq -r '. | {Id: .Id, Digest: .Digest, RepoDigests: .RepoDigests, Labels: .Config.Labels}'</code></pre>



<p>Output:</p>



<pre class="wp-block-code"><code>{
  "Id": "sha256:96c63a7d3e502fcbbd8937a2523368c22d0edd1788b8389af095f64038318834",
  "Digest": null,
  "RepoDigests": &#91;
    "traefik@sha256:5ec34caf19d114f8f0ed76f9bc3dad6ba8cf6d13a1575c4294b59b77709def39"
  ],
  "Labels": {
    "org.opencontainers.image.description": "A modern reverse-proxy",
    "org.opencontainers.image.documentation": "https://docs.traefik.io/",
    "org.opencontainers.image.title": "Traefik",
    "org.opencontainers.image.url": "https://traefik.io/",
    "org.opencontainers.image.vendor": "Containous",
    "org.opencontainers.image.version": "v1.7.20"
  }
}</code></pre>



<p>Bingo! That&#8217;s version 1.7.20 of Traefik!</p>



<h2 class="wp-block-heading" id="lucky-trick-2">Lucky Trick #2</h2>



<p>Pull a bunch of images and hope the Image ID matches. Not much to this trick..</p>



<h2 class="wp-block-heading" id="lucky-trick-3-1">Lucky Trick #3</h2>



<p>If your image is from Docker Hub, they have a new experimental tool you can use called &#8220;<a href="https://github.com/docker/hub-tool" target="_blank" rel="noreferrer noopener">Docker Hub Tool</a>&#8220;.</p>



<p>But what if you are unlucky? What if there&#8217;s a way to check all version tags of an image?</p>



<h2 class="wp-block-heading" id="find-version-tag-for-latest-docker-image">Find Version Tag for Latest Docker image</h2>



<p>There&#8217;s a way to check all version tags on Docker Hub (for example), against the local docker image&#8217;s &#8220;Image ID&#8221;.</p>



<p>You can get every tag from a Docker Registry (like Docker Hub), then use every tag you found, to get the image ID information from the manifest of every image. </p>



<p>Docker Hub has some quirks compared to a proper Docker Registry, and the API isn&#8217;t well documented. But let&#8217;s focus on Docker Hub, since that&#8217;s a huge public image repository.</p>



<p>If you don&#8217;t want to do all of this manually, you can use my script (on GitHub). Here&#8217;s the script in action:</p>



<pre class="wp-block-code"><code># ./docker_image_find_tag.sh -n traefik -i 96c63a7d3e50 -f 1.7. -l 10 -v

Using IMAGE_NAME: traefik
Using REGISTRY: https://index.docker.io/v2
Found Image ID Source: sha256:96c63a7d3e502fcbbd8937a2523368c22d0edd1788b8389af095f64038318834
Found Total Tags: 610
Found Tags (after filtering): 178
Limiting Tags to: 10
Limit reached, consider increasing limit (-l &#91;number]) or use more specific filter (-f &#91;text])

Found Tags:
v1.7.21-alpine
v1.7.21
v1.7.20-alpine
v1.7.20
v1.7.19-alpine
v1.7.19
v1.7.18-alpine
v1.7.18
v1.7.17-alpine
v1.7.17

Checking for image match..
Found match. tag: v1.7.20
Image ID Target: sha256:96c63a7d3e502fcbbd8937a2523368c22d0edd1788b8389af095f64038318834
Image ID Source: sha256:96c63a7d3e502fcbbd8937a2523368c22d0edd1788b8389af095f64038318834</code></pre>



<p>This example is searching for an image named traefik, with an image ID of  96c63a7d3e50 (which we got from running <code>docker images</code>. </p>



<p>The total number of tags for traefik images is 610! You could use this script to check every one, but that will take a minute or two. Instead, you can filter the results a bit. I *think* I&#8217;m running something in version 1.7.x. I&#8217;m also limiting the search to 10 tags in this example to keep the output small.</p>



<p>And the find version tag script found it! The local image ID matches an image ID on the Docker Registry with a tag of 1.7.20!</p>



<p>You can find the script on GitHub: <a rel="noreferrer noopener" href="https://github.com/ryandaniels/docker-script-find-latest-image-tag" target="_blank">https://github.com/ryandaniels/docker-script-find-latest-image-tag</a></p>



<p>Some issues to note:<br>Issue #1: If the image no longer exists on the Docker Registry. You obviously won&#8217;t find it. <br>Issue #2: The script doesn&#8217;t work for Windows images. There are no manifests available for those.</p>



<p>Side note: In this example I&#8217;m using the traefik image. What is <a rel="noreferrer noopener" href="https://containo.us/traefik/" target="_blank">traefik</a>? It&#8217;s &#8220;The Cloud Native Edge Router&#8221; which means it&#8217;s a reverse proxy and load balancer for HTTP and TCP-based applications. It works really well from my experience! Just be careful when upgrading from version 1 to version 2.</p>



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



<p>In conclusion, we ran the find docker image version script to match all image ID&#8217;s on Docker Hub against the local docker image that&#8217;s only tagged as latest. And we found a match, so we know what version we are running!</p>



<p>Now that we have a versioned image tag, we will update our running containers to use that specific version. And never use latest again!</p>



<p>Check out other interesting articles about <a href="https://ryandaniels.ca/blog/category/docker/">Docker</a>.</p>
<p>The post <a href="https://ryandaniels.ca/blog/find-version-tag-latest-docker-image/">Find Version Tag for Latest Docker Image</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2196</post-id>	</item>
		<item>
		<title>Ansible Role to Test Network Connectivity</title>
		<link>https://ryandaniels.ca/blog/ansible-role-test-network-connectivity/</link>
		
		<dc:creator><![CDATA[Ryan Daniels]]></dc:creator>
		<pubDate>Wed, 08 Jan 2020 01:27:14 +0000</pubDate>
				<category><![CDATA[Ansible]]></category>
		<category><![CDATA[Guide]]></category>
		<category><![CDATA[IT Automation]]></category>
		<category><![CDATA[Linux]]></category>
		<guid isPermaLink="false">https://ryandaniels.ca/?p=2130</guid>

					<description><![CDATA[<p>Ansible is used to do so many things. And if you already use Ansible for your automation tasks then you already have it ready to go. So why not use Ansible to test network connectivity?</p>
<p>The post <a href="https://ryandaniels.ca/blog/ansible-role-test-network-connectivity/">Ansible Role to Test Network Connectivity</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Ansible is used to do so many things. And if you already use Ansible for your automation tasks then you already have it ready to go. So why not use Ansible to test network connectivity?</p>



<p>What if you need to test a bunch of IPs and ports from several different servers. You can actually use Ansible to test the connectivity from multiple servers (which could be in different regions), to multiple tools or services (using their IP and port). Ansible is such a flexible tool for automation!</p>



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



<p>Not sure what Ansible is all about? First, check out the <a href="https://ryandaniels.ca/blog/getting-started-ansible-ubuntu-centos/">Ansible getting started guide</a>.</p>



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



<p>Sometimes you need to do a quick test from one server to a certain IP and port to make sure there is network connectivity. Or maybe from multiple servers to multiple IPs and ports.</p>



<p>Sometimes you need to do this only once (hopefully) to get a new firewall rule implemented. Or perhaps you want to run this every day to ensure network connectivity from multiple servers to a certain tool.</p>



<p>Ansible can help us with this!</p>



<h2 class="wp-block-heading">How does it work?</h2>



<p>The Ansible Role uses a few Linux utilities, mainly netcat (nc), to test the source server(s) can reach the destination IP(s) and port(s).<br>This works with <a rel="noreferrer noopener" aria-label="TCP (opens in a new tab)" href="https://en.wikipedia.org/wiki/Transmission_Control_Protocol" target="_blank">TCP</a> and <a rel="noreferrer noopener" aria-label="UDP (opens in a new tab)" href="https://en.wikipedia.org/wiki/User_Datagram_Protocol" target="_blank">UDP</a> protocols.</p>



<p>In addition, if your Ansible host (source server) has multiple IPs, it uses the <code>ip route get</code> command to determine which IP to use. Note, if that is wrong and you need a custom route added to your host, that is something you will need to fix.</p>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<p>Linux distributions tested:</p>



<ul class="wp-block-list"><li>Ubuntu 18.04 and 16.04</li><li>CentOS and RHEL: 7.x, 6.5, 5.9</li></ul>
</div></div>



<p>The Connectivity Test Ansible Role is on <a rel="noreferrer noopener" aria-label="Ansible Galaxy (opens in a new tab)" href="https://galaxy.ansible.com/ryandaniels/connectivity_test" target="_blank">Ansible Galaxy</a> and <a rel="noreferrer noopener" aria-label="GitHub (opens in a new tab)" href="https://github.com/ryandaniels/ansible-role-connectivity-test" target="_blank">GitHub</a>.</p>



<h2 class="wp-block-heading">Ansible Connectivity Test Role</h2>



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



<p>Add this Ansible Role to your Ansible control node (or Ansible Tower, or Jenkins, etc).</p>



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



<p>Add the variables to your Ansible setup. For example, if you want to test a group of Ansible hosts add this to group_vars where connectivity_test_grp is your group:<br><code>group_vars/connectivity_test_grp/connectivity-test-vars.yml</code></p>



<pre class="wp-block-code"><code>---
connectivity_test_destinations:
  - { ip: 192.168.56.10, port: 22 }
  - { ip: 192.168.56.10, port: 5000 }
  - { ip: 192.168.1.2, port: 53, protocol: udp }</code></pre>



<p>The TCP protocol is used by default so it doesn&#8217;t need to be specified. (But you can if you want).</p>



<p>The above configuration will test 3 IPs and ports from every Ansible host in the group <code>connectivity_test_destinations</code>.<br>The first two lines test the IP 192.168.56.10 on ports 22 and 5000 using the TCP protocol. <br>The last line will test the IP 192.168.1.2 on port 53 using the UDP protocol.</p>



<p>Next, add your Ansible Playbook <code>connectivity-test.yml</code>:</p>



<pre class="wp-block-code"><code>---
- hosts: '{{inventory}}'
  become: yes
  roles:
  - connectivity-test</code></pre>



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



<p>Run the Ansible Playbook (where <code>connectivity_test_grp</code> is a group in your inventory (hosts) file:</p>



<pre class="wp-block-code"><code>ansible-playbook connectivity-test.yml --extra-vars "inventory=connectivity_test_grp" -i hosts</code></pre>



<p>If the requirements are already installed on the Ansible hosts, you can speed up the playbook by skipping that part:</p>



<pre class="wp-block-code"><code>ansible-playbook connectivity-test.yml --extra-vars "inventory=connectivity_test_grp" -i hosts --skip-tags connectivity_install_pkg</code></pre>



<p>To clarify, more details are in the GitHub readme.</p>



<h2 class="wp-block-heading">Conclusion &#8211; Test Network Connectivity</h2>



<p>In conclusion, you can now use Ansible to test network connectivity from one or many Ansible hosts, to one or many different IPs and ports!</p>



<p>This can be helpful for testing firewall issues. Or to ensure a certain tool is reachable from a certain location. If you want you could add this to Ansible Tower or Jenkins as a scheduled task. For example, if you want to know if your lab environment can&#8217;t reach an important tool.</p>



<p>What other interesting things can you do with Ansible? <a href="https://ryandaniels.ca/blog/ansible-user-management/">Manage users with Ansible</a>, <a href="https://ryandaniels.ca/blog/ansible-update-ubuntu-centos-redhat/">keep your servers up to date</a>, and use <a href="https://ryandaniels.ca/blog/ansible-vault-jenkins/">Jenkins as a front-end with Ansible Vault</a>. </p>
<p>The post <a href="https://ryandaniels.ca/blog/ansible-role-test-network-connectivity/">Ansible Role to Test Network Connectivity</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2130</post-id>	</item>
		<item>
		<title>Dockerfile ARG FROM ARG trouble with Docker</title>
		<link>https://ryandaniels.ca/blog/docker-dockerfile-arg-from-arg-trouble/</link>
		
		<dc:creator><![CDATA[Ryan Daniels]]></dc:creator>
		<pubDate>Mon, 30 Dec 2019 15:24:00 +0000</pubDate>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[ci/cd]]></category>
		<category><![CDATA[Guide]]></category>
		<guid isPermaLink="false">https://ryandaniels.ca/?p=2017</guid>

					<description><![CDATA[<figure class="alignleft size-thumbnail"><a href="https://ryandaniels.ca/blog/docker-dockerfile-arg-from-arg-trouble"><img src="https://ryandaniels.ca/wp-content/uploads/2019/12/Dockerfile_ARG-300x266.jpg" alt="Dockerfile ARG" class="wp-image-2033"/></a></figure>
<p>Using a dynamic Dockerfile can have great benefits when used in your CI/CD pipeline. You can use the ARG statement in your Dockerfile to pass in a variable at build time. Even use a variable in the FROM statement!<br />
&#160;</p>
<p>The post <a href="https://ryandaniels.ca/blog/docker-dockerfile-arg-from-arg-trouble/">Dockerfile ARG FROM ARG trouble with Docker</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-image"><figure class="aligncenter size-large"><img decoding="async" width="564" height="500" src="https://ryandaniels.ca/wp-content/uploads/2019/12/Dockerfile_ARG.jpg" alt="Dockerfile ARG" class="wp-image-2033" srcset="https://ryandaniels.ca/wp-content/uploads/2019/12/Dockerfile_ARG.jpg 564w, https://ryandaniels.ca/wp-content/uploads/2019/12/Dockerfile_ARG-300x266.jpg 300w" sizes="(max-width: 564px) 100vw, 564px" /></figure></div>



<p>Using a dynamic <a rel="noreferrer noopener" aria-label="Dockerfile (opens in a new tab)" href="https://docs.docker.com/engine/reference/builder/" target="_blank">Dockerfile</a> can have great benefits when used in your CI/CD pipeline. You can use the <code>ARG</code> statement in your <code>Dockerfile</code> to pass in a variable at build time. Even use a variable in the <code>FROM</code> statement! Dockerfile ARG FROM ARG. That will make more sense later.</p>



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



<p>This post is about <a rel="noreferrer noopener" aria-label="Container virtualization technology (opens in a new tab)" href="https://rancher.com/learning-paths/what-are-containers/" target="_blank">Container virtualization technology</a>, and problems when building a container image using <a rel="noreferrer noopener" aria-label="Docker Engine (opens in a new tab)" href="https://www.docker.com/products/container-runtime" target="_blank">Docker Engine</a>. <br>For some background on a dynamic Dockerfile, check out <a rel="noreferrer noopener" aria-label="Jeff Geerling's post (opens in a new tab)" href="https://www.jeffgeerling.com/blog/2017/use-arg-dockerfile-dynamic-image-specification" target="_blank">Jeff Geerling&#8217;s post</a>.</p>



<p>One problem I&#8217;ve come across with this, is the <code>Dockerfile</code> <code>ARG</code> variable usage isn&#8217;t intuitive. It is actually kind of weird. And I&#8217;m not alone on this! There&#8217;s lots of feedback in <a rel="noreferrer noopener" aria-label="GitHub Issue #34129 (opens in a new tab)" href="https://github.com/moby/moby/issues/34129" target="_blank">GitHub Issue #34129</a>. </p>



<h2 class="wp-block-heading">What&#8217;s the Problem?</h2>



<p>A variable declared at the top of the <code>Dockerfile</code> using <code>ARG</code> doesn&#8217;t work if you try to use it after the <code>FROM</code> statement. Not by default at least. It only works if used in the <code>FROM</code> statement. </p>



<pre class="wp-block-code"><code>ARG TAG=latest
FROM myimage:$TAG # &lt;------ This works!
LABEL BASE_IMAGE="myimage:$TAG" # &lt;------ Does not work!</code></pre>



<p>The <code>FROM</code> above will use the <code>TAG</code> passed in from a build-arg, or default to use the string &#8220;latest&#8221;.<br>But the <code>LABEL</code> won&#8217;t work. The <code>TAG</code> portion will be empty!</p>



<p>This was tested with the most recent version of Docker Engine (version: 19.03.5).</p>



<h2 class="wp-block-heading">How Does it Work?</h2>



<p>To use a variable in the <code>FROM</code> section, you need to put the <code>ARG</code> before the <code>FROM</code>. So far so good. But, now let&#8217;s use that variable again after the <code>FROM</code>? No you can&#8217;t. It&#8217;s not there. Unless you use another <code>ARG</code> statement after the <code>FROM</code>.<br>Wait, it gets more weird. Any <code>ARG</code> before the FIRST <code>FROM</code>, can be used in any <code>FROM</code> (for multi-stage builds). In fact the <code>ARG</code> must be above the first <code>FROM</code> even if you only want to use it in a later <code>FROM</code>. Wow, that&#8217;s a lot of <code>ARG</code>s and <code>FROM</code>s. The <code>ARG</code> is kind of &#8220;global&#8221; but only if you declare it again inside the build stage.</p>



<h2 class="wp-block-heading">Dockerfile ARG FROM ARG</h2>



<p>Let&#8217;s look at an example to make it easier. Below is not a useful Dockerfile. It&#8217;s only an example to illustrate this.</p>



<pre class="wp-block-code"><code>#These ARGs are used in the FROM statements
#Or as global variables if declared again (without the default value)
ARG BUILDER_TAG=latest
ARG BASE_TAG=latest
ARG APP="app.go"

#First build stage
FROM mybuildapp:$BUILDER_TAG AS builder
ARG APP
RUN compile_my_app $APP

#Second build stage
FROM registry.access.redhat.com/ubi8/ubi-minimal:$BASE_TAG
ARG BASE_TAG
ARG APP
LABEL BASE_IMAGE="registry.access.redhat.com/ubi8/ubi-minimal:$BASE_TAG"
COPY --from=builder $APP .</code></pre>



<p>Now, let&#8217;s run the example build:</p>



<pre class="wp-block-code"><code>docker build . \
  --pull
  --build-arg BUILDER_TAG="2.0" \
  --build-arg BASE_TAG="8.1" \
  --build-arg APP="the_best_app.go" \
  -t image_tag</code></pre>



<p>Once the Docker build finishes, this is the result of your command line argument usage inside the docker image:</p>



<pre class="wp-block-code"><code>BUILDER_TAG="2.0"
BASE_TAG="8.1"
APP="the_best_app.go"</code></pre>



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



<p>The <code>BUILDER_TAG</code> and <code>BASE_TAG</code> will be used in the <code>FROM</code> statements. <code>BASE_TAG</code> is also used inside the second build stage. And <code>APP</code> will be used in both build stages. <code>ARG APP="app.go"</code> only needs to be declared if you want to set a default value. In my example we don&#8217;t really need that since we are passing in a build argument.</p>



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



<p>Remember that <code>ARG</code>s at the top of the <code>Dockerfile</code> can be used in the <code>FROM</code> statements. They are &#8220;global&#8221; only if you declare the <code>ARG</code> again in each build stage (after <code>FROM</code> (and before the next <code>FROM</code> if using a multi-stage build)).<br>You can remember it this way: <code>Dockerfile</code> <code>ARG</code> <code>FROM</code> <code>ARG</code><br>But, after wasting an hour on this, it was more like: Dockerfile <em>Arrggh!</em> FROM <em>Arrggh!</em></p>



<p>You can use something like this in your CI/CD, for automatic docker image building. </p>



<p><strong>Side note</strong>: Building an image using <a rel="noreferrer noopener" aria-label="Podman (opens in a new tab)" href="https://podman.io/" target="_blank">Podman</a> does not have the same issue as Docker Engine (tested with Podman version 1.4.4, 1.6.3, and 1.7.0). You do not need to specify the <code>ARG</code> again inside the build stage when Podman creates the container image!</p>



<p>Further reading:<br><a rel="noreferrer noopener" aria-label=" (opens in a new tab)" href="https://docs.docker.com/engine/reference/builder/#understand-how-arg-and-from-interact" target="_blank">Dockerfile Reference: Understand how ARG and FROM interact</a><br><a rel="noreferrer noopener" aria-label="Dockerfile Reference: Scope (opens in a new tab)" href="https://docs.docker.com/engine/reference/builder/#scope" target="_blank">Dockerfile Reference: Scope</a><br><a href="https://docs.docker.com/develop/develop-images/multistage-build" target="_blank" rel="noreferrer noopener" aria-label="Multi-Stage Builds (opens in a new tab)">Multi-Stage Builds</a></p>
<p>The post <a href="https://ryandaniels.ca/blog/docker-dockerfile-arg-from-arg-trouble/">Dockerfile ARG FROM ARG trouble with Docker</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2017</post-id>	</item>
		<item>
		<title>User Management with Ansible</title>
		<link>https://ryandaniels.ca/blog/ansible-user-management/</link>
		
		<dc:creator><![CDATA[Ryan Daniels]]></dc:creator>
		<pubDate>Fri, 02 Mar 2018 13:03:28 +0000</pubDate>
				<category><![CDATA[Ansible]]></category>
		<category><![CDATA[CentOS]]></category>
		<category><![CDATA[Guide]]></category>
		<category><![CDATA[IT Automation]]></category>
		<category><![CDATA[Jenkins]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<guid isPermaLink="false">https://ryandaniels.ca/?p=1251</guid>

					<description><![CDATA[<p>Ansible is a great tool to automate all the things. Another task it can help to automate is user management.  This guide will be talking specifically about user management on Linux servers like Red Hat Enterprise Linux (RHEL), CentOS, or Ubuntu. Ansible can handle this task!</p>
<p>The post <a href="https://ryandaniels.ca/blog/ansible-user-management/">User Management with Ansible</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Ansible is a great tool to automate all the things. Another task it can help to automate is user management.  This guide will be talking specifically about user management on Linux servers like Red Hat Enterprise Linux (RHEL), CentOS, or Ubuntu.</p>
<p><span id="more-1251"></span></p>
<h2>What&#8217;s the problem?</h2>
<p>If you have multiple servers to manage, it can be a pain to manually add a new user, change a password, or lock an old account. Manually logging into all of your servers and performing these tasks is a real pain, and a huge waste of time.</p>
<p>Luckily there are several solutions.</p>
<h2>Solution: Red Hat IDM</h2>
<p>There are many different solutions for user management. <a href="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/linux_domain_identity_authentication_and_policy_guide/index" target="_blank" rel="noopener noreferrer">Red Hat Identity Management</a> (IDM) is a very good solution that works with many Linux servers. IDM is a central location that holds all the user configuration. And it can even connect to Windows Active Directory.</p>
<p>However, if you don&#8217;t have a subscription to Red Hat Enterprise Linux there are other options.</p>
<h2>Solution: FreeIPA</h2>
<p><a href="https://www.freeipa.org/page/About" target="_blank" rel="noopener noreferrer">FreeIPA</a> is the upstream open source project for Red Hat Identify Management. So you can download the FreeIPA package and follow one of many available tutorials for setting up a <a href="https://www.digitalocean.com/community/tutorials/how-to-set-up-centralized-linux-authentication-with-freeipa-on-centos-7" target="_blank" rel="noopener noreferrer">server</a> and <a href="https://www.digitalocean.com/community/tutorials/how-to-configure-a-freeipa-client-on-centos-7" target="_blank" rel="noopener noreferrer">client</a>.</p>
<h2>Solution: Ansible for user management</h2>
<p>If the above solutions seem too complicated there&#8217;s another option. However, you should really take some time to setup user management properly. Use FreeIPA. It&#8217;s free!</p>
<p>But, if you want to use another solution while you are setting up FreeIPA, and you already have Ansible as part of your environment then you have another option. Ansible can do this of course!</p>
<p>The reason Ansible is a decent option for user management is because it is idempotent. This means, Ansible will only make a change if the change is needed to get to the desired state. So you can run the same Ansible Playbook multiple times, and if the Ansible tasks are written properly Ansible will only make a change the first time.</p>
<p>Just keep in mind, I warned you to use FreeIPA. This solution is not &#8220;enterprise&#8221; grade. But it certainly works for certain scenarios, like in a lab environment. And if you want to use Ansible for something new, there is a user management <a href="https://github.com/ryandaniels/ansible-role-create-users" target="_blank" rel="noopener noreferrer">role available on GitHub</a> or on <a href="https://galaxy.ansible.com/ryandaniels/create_users" target="_blank" rel="noopener noreferrer">Ansible Galaxy</a>.</p>
<p>If you aren&#8217;t familiar with Ansible, check out my <a href="https://ryandaniels.ca/blog/getting-started-ansible-ubuntu-centos/">Getting Started with Ansible guide</a>.</p>
<p>This Ansible role is tested on:</p>
<ul>
<li>Ubuntu</li>
<li>Red Hat Enterprise Linux (RHEL) 7.x, 6.5, 5.9</li>
<li>CentOS 7.x, 6.5, 5.9</li>
</ul>
<h3>What this user management Ansible role does</h3>
<p><a href="https://github.com/ryandaniels/ansible-role-create-users" target="_blank" rel="noopener noreferrer">This role</a> will manage users in the user list configuration file (list is in the file vars/lab_users.secret in the example below).<br />
It can add users, change passwords, lock/unlock user accounts, manage sudo access (per user), add ssh key(s) for ssh key based authentication.<br />
This is done on a per &#8220;group&#8221; basis (using Ansible group variables), as set in the configuration file. The group comes from the Ansible group as set for a server in the inventory file.</p>
<p>Note: Deleting users is not done on purpose.</p>
<p>The great thing about Ansible Playbooks, if you don&#8217;t like something it&#8217;s easy enough to modify.</p>
<h3>Install the Ansible user management role</h3>
<p>First let&#8217;s install the Ansible role to manage users into your Ansible control server:</p>
<pre><code>$ su - ansible
$ cd ~/ansible
$ git clone https://github.com/ryandaniels/ansible-role-create-users.git roles/create-users</code></pre>
<p>Or, you can use Ansible Galaxy to install this role:</p>
<pre><code>$ su - ansible
$ ansible-galaxy install ryandaniels.create_users</code></pre>
<h3>Setup Ansible Vault</h3>
<p>If you don&#8217;t already have <a href="https://docs.ansible.com/ansible/latest/vault.html" target="_blank" rel="noopener noreferrer">Ansible Vault</a> configured, you will need to set it up now. Vault uses AES encryption to store your sensitive information. And we need Ansible Vault to encrypt our user configuration file since we don&#8217;t want to be exposing even a hashed password into source control.</p>
<p>First, (if using git), make sure to update your .gitignore file so your Vault password isn&#8217;t saved to your source control. And also add the secret file we will be creating later:</p>
<pre><code>$ vi .gitignore
.vaultpass
secret
*.secret</code></pre>
<p>Next, create a password for your Ansible Vault and save it in your Password Manager (like <a href="https://keepassxc.org/" target="_blank" rel="noopener noreferrer">KeePassXC</a>). Then create the .vaultpass file, add the Vault password, and fix the permissions:</p>
<pre><code>$ vi .vaultpass
#Enter password here

$ chmod 600 .vaultpass</code></pre>
<p>Also you need to update the Ansible config file to reference where the Vault file is located:</p>
<pre><code>$ vi ansible.cfg
[defaults]
vault_password_file = ./.vaultpass
</code></pre>
<h3>Create Ansible Playbook</h3>
<p>Next, create the Playbook file:</p>
<pre><code>$ vi create-users.yml
---
- hosts: '{{inventory}}'
  vars_files:
    - vars/lab_users.secret
  become: yes
  roles:
  - create-users</code></pre>
<h3>Create configuration for user management</h3>
<p>Next, add your users into a configuration file. The below is only an example, don&#8217;t use it in your user management configuration file. Also, make sure the filename matches a .gitignore entry. In this case it will match &#8220;*.secret&#8221;.<br />
Use the special Ansible command to create the encrypted Ansible Vault file:</p>
<pre><code>$ mkdir -p vars
$ ansible-vault create vars/lab_users.secret
---
users:
  - username: alice
    password: $6$/y5RGZnFaD3f$96xVdOAnldEtSxivDY02h.DwPTrJgGQl8/MTRRrFAwKTYbFymeKH/1Rxd3k.RQfpgebM6amLK3xAaycybdc.60
    update_password: on_create
    comment: Test User 100
    shell: /bin/bash
    ssh_key: |
      ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx8crAHG/a9QBD4zO0ZHIjdRXy+ySKviXVCMIJ3/NMIAAzDyIsPKToUJmIApHHHF1/hBllqzBSkPEMwgFbXjyqTeVPHF8V0iq41n0kgbulJG alice@laptop
      ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx8crAHG/a9QBD4zO0ZHIjdRXy+ySKviXVCMIxxxxxxxxxxxxxxxxxxJmIApHHHF1/hBllqzBSkPEMwgFbXjyqTeVPHF8V0iq41n0kgbulJG alice@server1
    exclusive_ssh_key: yes
    use_sudo: no
    use_sudo_nopass: no
    user_state: present
    servers:
      - webserver
      - database
      - monitoring

  - username: bob
    password: $6$XEnyI5UYSw$Rlc6tXtECtqdJ3uFitrbBlec1/8Fx2obfgFST419ntJqaX8sfPQ9xR7vj7dGhQsfX8zcSX3tumzR7/vwlIH6p/
    ssh_key: AAAAB3NzaC1yc2EAAAADAQABAAACAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx8crAHG/a9QBD4zO0ZHIjdRXy+ySKviXVCMIxxxxxxxxxxxxxxxxxxJmIApHHHF1/hBllqbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbulJG bob@laptop
    use_sudo: no
    user_state: lock
    servers:
      - webserver
      - database</code></pre>
<p>In the above example, there are two users. Users: alice and bob. If you are familiar with user management on Linux, then most of these settings are self explanatory. For example, both Alice and Bob have a hashed password and ssh keys. Alice actually has two ssh keys configured. But Bob&#8217;s account is locked so he can&#8217;t log in.</p>
<p>The interesting part is the list of &#8220;servers&#8221; in the configuration. These are groups defined in your Ansible hosts file. So you can give certain users access to a specific group of servers, depending on the user&#8217;s role.</p>
<p>Important note: Be careful with the <code>update_password</code> setting. When set to <code>always</code>, the user&#8217;s password will be changed to what is defined in <code>password</code>. This might not be what they wanted if they&#8217;ve manually changed their password so it&#8217;s usually safer to use <code>on_create</code>.</p>
<p>For details about all the different settings, see the <a href="https://github.com/ryandaniels/ansible-role-create-users/blob/master/README.md#user-settings" target="_blank" rel="noopener noreferrer">README</a> on GitHub.</p>
<p>Going forward, to update the file, instead of the &#8220;create&#8221; command line option, use &#8220;edit&#8221;:</p>
<pre><code>$ ansible-vault edit vars/lab_users.secret</code></pre>
<p>And don&#8217;t forget to save this into your source control (git).</p>
<h3>Run the Ansible Playbook</h3>
<pre><code>$ ansible-playbook create-users.yml --extra-vars "inventory=all-dev" -i hosts-dev</code></pre>
<p>Marvel at the output generated by Ansible. All these users are created, updated, or locked, but only if something needed to change since Ansible is idempotent.</p>
<h3>Bonus: Add this in Jenkins</h3>
<p>If you also use Jenkins for your CI/CD pipeline, you can add this Ansible Playbook into Jenkins.</p>
<p>You just need to setup Jenkins to use Ansible and Ansible Vault. And there is a great Jenkins Plugin to help. Just follow this guide to use <a href="https://ryandaniels.ca/blog/ansible-vault-jenkins/">Ansible Vault with Jenkins</a>. Keep in mind that updating the user configuration file is only possible from the command line, since it&#8217;s encrypted using Ansible Vault.</p>
<h2>Conclusion</h2>
<p>In conclusion, there are many options for user management on Linux servers. From enterprise solutions like Red Hat IDM. Or, using the upstream open source software IDM uses directly, FreeIPA. If you decide to use Ansible, then the above Ansible role will get the job done. And you can also add it into Jenkins.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>The post <a href="https://ryandaniels.ca/blog/ansible-user-management/">User Management with Ansible</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1251</post-id>	</item>
		<item>
		<title>Ansible Vault with Jenkins</title>
		<link>https://ryandaniels.ca/blog/ansible-vault-jenkins/</link>
		
		<dc:creator><![CDATA[Ryan Daniels]]></dc:creator>
		<pubDate>Tue, 13 Feb 2018 13:26:59 +0000</pubDate>
				<category><![CDATA[Ansible]]></category>
		<category><![CDATA[Guide]]></category>
		<category><![CDATA[IT Automation]]></category>
		<category><![CDATA[Jenkins]]></category>
		<category><![CDATA[Security]]></category>
		<guid isPermaLink="false">https://ryandaniels.ca/?p=1253</guid>

					<description><![CDATA[<p>Ansible can use encrypted files, using a feature called Ansible Vault. This is great for sensitive information that you don't want to store as a normal text file since you are able to encrypt this data in your souce control.</p>
<p>The post <a href="https://ryandaniels.ca/blog/ansible-vault-jenkins/">Ansible Vault with Jenkins</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Ansible can use encrypted files, using a feature called Ansible Vault. This is great for sensitive information that you don&#8217;t want to store as a normal text file since you are able to encrypt this data in your source control.</p>
<p><span id="more-1253"></span></p>
<p>If you are new to Ansible, read the <a href="https://ryandaniels.ca/blog/getting-started-ansible-ubuntu-centos/" target="_blank" rel="noopener noreferrer">getting started with Ansible</a> post first.</p>
<h2>Why use Ansible Vault?</h2>
<p>You want to use Ansible Vault when you need to use sensitive data with Ansible, like a login and password, or SSH keys. Instead of storing this sensitive information in plain text, where anyone can read it when you save your <a href="http://docs.ansible.com/ansible/latest/playbooks_vault.html" target="_blank" rel="noopener noreferrer">Ansible Playbooks</a> to your source control (like git), Vault uses an AES cypher to encrypt your data.</p>
<p>For more details, read the <a href="http://docs.ansible.com/ansible/latest/vault.html" target="_blank" rel="noopener noreferrer">documentation</a>.</p>
<h2>Ansible Vault with Jenkins</h2>
<p><a href="https://jenkins.io/" target="_blank" rel="noopener noreferrer">Jenkins</a> is software for Continuous Integration and Continuous Delivery. You can add plugins to Jenkins to extend its base features. And one handy plugin allows you to use Ansible with Jenkins.</p>
<p>Recently, the Ansible Plugin for Jenkins was updated to version 0.8.0, and as a result it now works seamlessly with Ansible Vault.</p>
<h2>Install Ansible plugins for Jenkins</h2>
<p>The first thing you need to install is the <a href="https://plugins.jenkins.io/ansible" target="_blank" rel="noopener noreferrer">Ansible plugin</a> for Jenkins.<br />
Also, install the dependent plugin called <a href="https://plugins.jenkins.io/credentials-binding" target="_blank" rel="noopener noreferrer">Credentials Binding</a>.</p>
<p>One thing to note is you can only read from encrypted Ansible Vault encrypted files. You cannot create or modify them using the Jenkins Ansible plugin. So you will still need to use the CLI to modify your encrypted files.</p>
<h2>Add Vault password to Jenkins</h2>
<p>The simplest way to use Ansible Vault with Jenkins is to add your Vault password into a Jenkins Credential. Then you can bind the credential to an environment variable, or use it directly as a &#8220;Vault Credential&#8221;.</p>
<p>Configure your Jenkins freestyle project that uses an Ansible Playbook. If you have the newest version of the Ansible plugin, under the &#8220;Build&#8221; section you will now see an option for &#8220;Vault Credentials&#8221; since this is a new feature.</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1280" src="https://ryandaniels.ca/wp-content/uploads/2018/02/ansible_vault_jenkins_credentials.png" alt="ansible vault jenkins credentials" width="643" height="289" srcset="https://ryandaniels.ca/wp-content/uploads/2018/02/ansible_vault_jenkins_credentials.png 643w, https://ryandaniels.ca/wp-content/uploads/2018/02/ansible_vault_jenkins_credentials-300x135.png 300w" sizes="auto, (max-width: 643px) 100vw, 643px" /></p>
<p>Add a new Jenkins Credential as &#8220;Secret text&#8221;, and enter your Ansible Vault encryption password.</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1281" src="https://ryandaniels.ca/wp-content/uploads/2018/02/ansible_vault_jenkins_credentials_new.png" alt="ansible vault jenkins new credentials" width="515" height="428" srcset="https://ryandaniels.ca/wp-content/uploads/2018/02/ansible_vault_jenkins_credentials_new.png 515w, https://ryandaniels.ca/wp-content/uploads/2018/02/ansible_vault_jenkins_credentials_new-300x249.png 300w" sizes="auto, (max-width: 515px) 100vw, 515px" /></p>
<p>Next, select the new Vault Credentials and you are ready to use your encrypted files in your Jenkins build job from your Ansible Playbooks.</p>
<h2>Conclusion</h2>
<p>In conclusion, you are now using Ansible Vault encrypted files automatically inside of your Jenkins build jobs. This helps you to keep your sensitive data secured in your source control. And Jenkins is helping you to deploy your Ansible Playbooks, while seamlessly decrypting your files.</p>
<p>Next, you can add a job to Jenkins that requires Ansible Vault. If you want to use Ansible for user management on Linux servers, check out the guide for <a href="https://ryandaniels.ca/blog/ansible-user-management/">User Management with Ansible</a>.</p>
<p>&nbsp;</p>
<p>The post <a href="https://ryandaniels.ca/blog/ansible-vault-jenkins/">Ansible Vault with Jenkins</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1253</post-id>	</item>
		<item>
		<title>Upgrade SSH keys and use gpg-agent with Ed25519 keys</title>
		<link>https://ryandaniels.ca/blog/upgrade-ssh-keys-gpg-agent-ed25519/</link>
		
		<dc:creator><![CDATA[Ryan Daniels]]></dc:creator>
		<pubDate>Sun, 11 Feb 2018 16:30:46 +0000</pubDate>
				<category><![CDATA[Security]]></category>
		<category><![CDATA[Encryption]]></category>
		<category><![CDATA[Guide]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[SSH]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<guid isPermaLink="false">https://ryandaniels.ca/?p=1245</guid>

					<description><![CDATA[<p>SSH keys are convenient and more secure than using a password to authenticate. If you created your SSH key a while ago, it's probably time to generate new RSA 4096 and Ed25519 keys. SSH keys like DSA and RSA 1024 are very old and now insecure. You should even upgrade ssh keys that are RSA 2048.</p>
<p>The post <a href="https://ryandaniels.ca/blog/upgrade-ssh-keys-gpg-agent-ed25519/">Upgrade SSH keys and use gpg-agent with Ed25519 keys</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>SSH keys are very convenient and more secure than using only a password to authenticate. If you created your SSH key a while ago, it&#8217;s probably time to generate new keys. SSH keys like DSA and RSA 1024 are very old and now insecure. You should even upgrade ssh keys that are RSA 2048. But really, it&#8217;s time to start using RSA 4096 for legacy servers, and Ed25519 for servers with modern ssh key support.</p>
<p><span id="more-1245"></span></p>
<p>The below commands are based on the post <a href="https://blog.g3rt.nl/upgrade-your-ssh-keys.html" target="_blank" rel="noopener noreferrer">Upgrade your SSH keys.</a> Check that out for more details.</p>
<h2>Identify and rename old ssh keys</h2>
<p>First, identify your old ssh keys:</p>
<pre>$ cd ~/.ssh
$ for sshkey in $(ls *.pub);do echo $sshkey;ssh-keygen -lf $sshkey;done
/home/ryan/.ssh/id_rsa.pub
2048 SHA256:gIDkzI98pEna3j9+2Ja5di0+k2dCaXtCtx6k71dskA1 ryan@home (RSA)</pre>
<p>From the output, this is showing it is an RSA 2048 key.</p>
<p>Next rename your old public and private ssh keys:</p>
<pre>$ mv id_rsa.pub id_rsa_legacy.pub
$ mv id_rsa id_rsa_legacy</pre>
<h2>Stop using insecure keys</h2>
<p>Use only keys that are greater than RSA 2048, or Ed25519.<br />
Specifically, remove:</p>
<ul>
<li>DSA</li>
<li>RSA 1024 and 2048</li>
<li>ECDSA</li>
</ul>
<p>Just be sure you aren&#8217;t using these ssh keys. Only remove them when you no longer need them and have the new keys setup and working.</p>
<h2>Create or Change your existing password</h2>
<p>If you old RSA ssh key didn&#8217;t use a password, now is the time to set a password. You can upgrade ssh keys that previously existed and didn&#8217;t use a password, without breaking anything. Also adding 100 rounds helps make your old key more secure when at rest if you need to continue using it.</p>
<pre>$ ssh-keygen -f ~/.ssh/id_rsa_legacy -p -o -a 100</pre>
<h2>Upgrade ssh keys &#8211; Generate RSA 4096 ssh keys</h2>
<p>RSA 4096 is good to use for legacy systems which do not yet support the new Ed25519 key.</p>
<p>Generate the RSA 4096 keys, and make sure to use a strong password:</p>
<pre>$ ssh-keygen -t rsa -b 4096 -o -a 100
Generating public/private rsa key pair.
Enter file in which to save the key (/home/ryan/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/ryan/.ssh/id_rsa.
Your public key has been saved in /home/ryan/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:732MQCPPaMS815Y7MFXl4n2WXuawR1Zsat+PEG1TnPA ryan@home
The key's randomart image is:
+---[RSA 4096]----+
|         +. o+.oo|
|        o * .+*..|
|         B oo=Eo.|
|          =o=..oo|
|        S .BoBo+=|
|         .  *.Ooo|
|          .  B =.|
|        .   B * .|
|          .... . |
+----[SHA256]-----+</pre>
<p>The &#8220;<code>-o -a 100</code>&#8221; means it is harder to crack the private key&#8217;s password using brute-force attacks. If your legacy system doesn&#8217;t support this, remove this option.</p>
<h2>Upgrade ssh keys &#8211; Generate Ed25519 ssh keys</h2>
<p><a href="https://en.wikipedia.org/wiki/EdDSA#Ed25519" target="_blank" rel="noopener noreferrer">Ed25519</a> ssh keys work on modern systems (OpenSSH 6.7+) and are much shorter than RSA keys. Note, the &#8220;<code>-o -a 100</code>&#8221; option is implied with Ed25519 key generation.<br />
Generate your new Ed25519 key and use a strong password:</p>
<pre>$ ssh-keygen -t ed25519
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/ryan/.ssh/id_ed25519.
Your public key has been saved in /home/ryan/.ssh/id_ed25519.pub.
The key fingerprint is:
SHA256:oU44/TftLl2/d4IKQla36Z1TMqrcdK1xBcerye78fxM ryan@home
The key's randomart image is:
+--[ED25519 256]--+
|        . .      |
|     . . . . .   |
|    . o .   o o .|
|   .   + . o o = |
|    . + S * + +  |
|     = . = B  .E |
|      + B.=.oo ..|
|       =.=o.o ..=|
|      ..oo=+o..+=|
+----[SHA256]-----+</pre>
<p>Now you have both RSA 4096 and Ed25519 ssh keys ready to go.</p>
<p>Next, add the keys to your ssh agent so it will remember the keys for you.</p>
<h2>Install and configure ssh agent</h2>
<p>Using an ssh agent allows you to type in a password once, and then the agent remembers the ssh keys.</p>
<p>On Ubuntu 16.04 there is one problem though. The built-in Gnome-keyring doesn&#8217;t support Ed25519. To work-around this, you could use the normal ssh-agent. But, I suggest instead to use gpg-agent and disable the gnome-keyring.</p>
<p>The below commands are based on the <a href="https://wiki.archlinux.org/index.php/GnuPG#SSH_agent" target="_blank" rel="noopener noreferrer">Arch wiki</a> and an answer from the <a href="https://askubuntu.com/questions/732581/gpg-agent-and-ssh-no-keys/930105#930105" target="_blank" rel="noopener noreferrer">Ask Ubuntu Forum</a>.</p>
<p>Disable Gnome ssh keyring daemon (<a href="https://wiki.archlinux.org/index.php/GNOME/Keyring#Disable_keyring_daemon_components" target="_blank" rel="noopener noreferrer">reference</a>):</p>
<pre>$ cp -rp /etc/xdg/autostart/gnome-keyring-ssh.desktop ~/.config/autostart
$ echo "Hidden=true" &gt;&gt; ~/.config/autostart/gnome-keyring-ssh.desktop</pre>
<p>Install gpg-agent:</p>
<pre>$ sudo apt-get install gpa gnupg-curl</pre>
<p>Enable ssh support in gpg-agent, and set a timeout to remember the key and password for 1 hour, since this adds some convenience:</p>
<pre>$ echo "enable-ssh-support" &gt;&gt; ~/.gnupg/gpg-agent.conf
$ echo "default-cache-ttl-ssh 3600" &gt;&gt; ~/.gnupg/gpg-agent.conf
$ echo "max-cache-ttl-ssh 3600" &gt;&gt; ~/.gnupg/gpg-agent.conf</pre>
<p>Edit your .bashrc to automatically load gpg-agent when you log in.</p>
<pre>$ vi ~/.bashrc
# Set SSH to use gpg-agent
unset SSH_AGENT_PID
if [ "${gnupg_SSH_AUTH_SOCK_by:-0}" -ne $$ ]; then
export SSH_AUTH_SOCK="~/.gnupg/S.gpg-agent.ssh"
fi</pre>
<p>Reload gpg-agent:</p>
<pre>$ gpg-connect-agent reloadagent /bye</pre>
<p>Next, add your new ssh keys to the gpg-agent:</p>
<pre>$ ssh-add ~/.ssh/id_ed25519 ~/.ssh/id_rsa ~/.ssh/id_rsa_legacy</pre>
<p>You will be prompted to enter your ssh key password. And after you enter that, another prompt will pop-up, from the gpg-agent. It will be used to unlock the gpg-agent&#8217;s key storage. This should be a different password than the password for your ssh keys. You will be prompted to enter this password every time you log in, or after the 1 hour timeout.</p>
<p>Enter the password that you want to use to unlock the gpg-agent key storage. And if you use the same password here for all your ssh keys, you only have to unlock it once:</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1270" src="https://ryandaniels.ca/wp-content/uploads/2018/02/gpg-agent_password_prompt.png" alt="gpg-agent password prompt upgrade ssh keys" width="477" height="277" srcset="https://ryandaniels.ca/wp-content/uploads/2018/02/gpg-agent_password_prompt.png 477w, https://ryandaniels.ca/wp-content/uploads/2018/02/gpg-agent_password_prompt-300x174.png 300w" sizes="auto, (max-width: 477px) 100vw, 477px" /></p>
<p>And now you can list your keys stored in the gpg-agent:</p>
<pre>$ ssh-add -l -E md5 # list fingerprint using md5 hash
$ ssh-add -l        # list fingerprint using sha256 hash
$ ssh-add -L        # list public key parameters</pre>
<h2>Re-deploy the new public keys</h2>
<p>Lastly, you need to add your new public keys to your servers. This command will ssh to your server and add your new public keys to the authorized_keys file.<br />
Change <code>1.2.3.4</code> to your server&#8217;s IP:</p>
<pre>$ ssh 1.2.3.4 "mkdir -p .ssh;echo $(cat ~/.ssh/id_ed25519.pub) &gt;&gt; .ssh/authorized_keys;echo $(cat ~/.ssh/id_rsa.pub) &gt;&gt; .ssh/authorized_keys;chmod 700 .ssh;chmod 640 .ssh/authorized_keys"</pre>
<p>Be sure to do this for ever server you connect to.</p>
<p><strong>Important</strong>: Be sure you <strong>don&#8217;t lock yourself out</strong> of your servers. Have another session open and test to make sure you can log in again after making this change.</p>
<p>Now you can remove your old ssh key from the ssh agent and only use the secure ssh keys:</p>
<pre>$ ssh-add -d 2&gt;/dev/null;ssh-add ~/.ssh/id_ed25519;ssh-add ~/.ssh/id_rsa</pre>
<p>Be sure to add the Ed25519 key first, like above. Since it seems to be a feature that prioritizes RSA keys first. So add the Ed25519 key first.</p>
<p>SSH to your servers to test the new key is working. You can also see in the logs the type of ssh key being used.</p>
<p>Confirm using the new Ed25519 ssh key, on Ubuntu 16.04:</p>
<pre>$ grep " sshd\[" /var/log/auth.log|grep "Accepted publickey"|tail
Feb 11 10:00:00 home sshd[1802]: Accepted publickey for ryan from 192.168.1.100 port 60708 ssh2: ED25519 SHA256:oU44/TftLl2/d4IKQla36Z1TMqrcdK1xBcerye78fxM</pre>
<h2>Conclusion</h2>
<p>Now you have more secure ssh keys since you are using Ed25519 and RSA 4096 keys. You have been able to upgrade ssh keys that are insecure! Next, you should look into updating your ssh server and client settings to use better encryption settings, using <a href="https://stribika.github.io/2015/01/04/secure-secure-shell.html" target="_blank" rel="noopener noreferrer">these</a> <a href="https://wiki.mozilla.org/Security/Guidelines/OpenSSH" target="_blank" rel="noopener noreferrer">references</a>.</p>
<p>And if you don&#8217;t want to manually deploy the new ssh keys to all of your servers, instead you can use <a href="https://ryandaniels.ca/blog/ansible-user-management/">Ansible for user management</a>.</p>
<p>The post <a href="https://ryandaniels.ca/blog/upgrade-ssh-keys-gpg-agent-ed25519/">Upgrade SSH keys and use gpg-agent with Ed25519 keys</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1245</post-id>	</item>
		<item>
		<title>Getting Started with Ansible on Ubuntu or CentOS</title>
		<link>https://ryandaniels.ca/blog/getting-started-ansible-ubuntu-centos/</link>
		
		<dc:creator><![CDATA[Ryan Daniels]]></dc:creator>
		<pubDate>Tue, 06 Feb 2018 13:46:59 +0000</pubDate>
				<category><![CDATA[Ansible]]></category>
		<category><![CDATA[CentOS]]></category>
		<category><![CDATA[Guide]]></category>
		<category><![CDATA[IT Automation]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<guid isPermaLink="false">https://ryandaniels.ca/?p=1133</guid>

					<description><![CDATA[<p><a href="https://ryandaniels.ca/blog/getting-started-ansible-ubuntu-centos/"><img class="alignleft size-thumbnail wp-image-1170" src="https://ryandaniels.ca/wp-content/uploads/2018/02/Ansible_logo-e1517962271957-150x150.png" alt="Setup Ansible - Getting Started with Ansible" width="150" height="150" /></a> This is a guide to getting started with Ansible. By the end of this guide, you will be up and running with Ansible.<br />
Included is an Ansible role that will create a user which is used by Ansible to connect to your remote servers. Let's go! After installing Ansible, you will need to setup Ansible by following these steps.</p>
<p>The post <a href="https://ryandaniels.ca/blog/getting-started-ansible-ubuntu-centos/">Getting Started with Ansible on Ubuntu or CentOS</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>This is a guide to getting started with Ansible. By the end of this guide, you will be up and running with Ansible!<br />
Included is an Ansible role that will create a user which is used by Ansible to connect to your remote servers. After installing Ansible, you will need to setup Ansible by following these steps since there is a bit more to it than you may think.</p>
<p><span id="more-1133"></span></p>
<h2><a id="what-is-ansible" href="#what-is-ansible"></a>What is Ansible?</h2>
<p><img loading="lazy" decoding="async" class="alignright wp-image-1170 size-medium" src="https://ryandaniels.ca/wp-content/uploads/2018/02/Ansible_logo-244x300.png" alt="Setup Ansible - Getting Started with Ansible" width="244" height="300" srcset="https://ryandaniels.ca/wp-content/uploads/2018/02/Ansible_logo-244x300.png 244w, https://ryandaniels.ca/wp-content/uploads/2018/02/Ansible_logo.png 256w" sizes="auto, (max-width: 244px) 100vw, 244px" /></p>
<p>First of all, Ansible is amazing at IT automation. Ansible is a command line IT automation solution that can deploy configuration changes, software, and perform many other tasks all automatically. To get more information about what Ansible is, check out the <a href="http://docs.ansible.com/ansible/latest/index.html" target="_blank" rel="noopener noreferrer">Ansible documentation</a>.</p>
<p>Ansible is modular, so you can create groups of tasks, called roles. And then you can group the roles together to all run sequentially inside of a playbook.<br />
An <a href="http://docs.ansible.com/ansible/latest/playbooks.html" target="_blank" rel="noopener noreferrer">Ansible Playbook</a> can run against one or multiple servers, depending how you reference the servers in your Playbook, and also depending on how you group the servers in your <a href="http://docs.ansible.com/intro_inventory.html" target="_blank" rel="noopener noreferrer">Ansible inventory</a> file.</p>
<h2>Setup Ansible</h2>
<p>Ansible uses ssh to connect to all of your remote servers to perform the tasks you define. After you install Ansible, it&#8217;s a good idea to create a user for Ansible to use. You need to do this on all servers that Ansible will be managing. Instead of doing that manually, use Ansible!</p>
<h3>Install Ansible</h3>
<p>First, let&#8217;s install Ansible on the local machine.</p>
<p>On Ubuntu 16.04 install Ansible using apt-get:</p>
<pre><code>$ sudo apt-get update &amp;&amp; sudo apt-get install ansible</code></pre>
<p>On CentOS/RHEL 7 install Ansible using yum:</p>
<pre><code>$ sudo yum install ansible</code></pre>
<h3>Ansible local user and Ansible directory</h3>
<p>On the local (control) server, all of the below Ansible commands are executed as the local Ansible user.</p>
<p>Create the user if it doesn&#8217;t exist and then run every command from now on as the Ansible user:</p>
<pre><code>$ sudo useradd ansible

$ su - ansible</code></pre>
<p>Create and go into the Ansible base directory:</p>
<pre><code>$ mkdir ~/ansible
$ cd ~/ansible</code></pre>
<h3>Ansible Inventory</h3>
<p>Ansible uses an <a href="http://docs.ansible.com/intro_inventory.html" target="_blank" rel="noopener noreferrer">inventory</a> file which contains all the remote servers you will be connecting to. This is the first thing you need do in order to setup Ansible.</p>
<p>An example of a simple inventory file using a group name &#8220;ubuntu-dev&#8221; with the hostname of two remote servers:</p>
<pre><code>$ cat &gt; ~/ansible/hosts &lt;&lt; 'EOF'
[ubuntu-dev]
ubuntu-web
ubuntu-db
EOF</code></pre>
<h3>Create SSH Key</h3>
<p>Create an ssh key for the local Ansible user using RSA keys, since that is still more common than ed25519:</p>
<pre><code>$ ssh-keygen -t rsa -b 4096</code></pre>
<h3>SSH to all remote servers</h3>
<p>You need to ssh to the servers beforehand, since you need to have the ssh host keys in your known_hosts file for <a href="https://www.symantec.com/connect/articles/ssh-host-key-protection" target="_blank" rel="noopener noreferrer">security reasons</a>. Therefore, make sure you are connecting to the expected servers.</p>
<p>You could do this manually, but instead use Ansible to ssh to all the servers in your Ansible inventory file to populate the known_hosts file. Do not run this in a production environment and make sure you are connecting to the expected servers by verifying the ssh key fingerprints.</p>
<pre><code>$ ansible all -m ping --extra-vars "ansible_ssh_common_args='-o StrictHostKeyChecking=no'" -i hosts</code></pre>
<p>This command is using the Ansible ping module (-m ping) to ssh to <strong>all</strong> servers in your inventory file (-i hosts), and this will create entries in the ~/.ssh/known_hosts file.</p>
<h3>Install Ansible required packages</h3>
<p>Next, you need to install some packages that <a href="https://docs.ansible.com/ansible/latest/intro_installation.html#managed-node-requirements" target="_blank" rel="noopener noreferrer">Ansible requires on the remote servers</a>. Currently, Ansible uses Python 2 by default. So your remote servers will need to have Python 2 installed.</p>
<p>Use Ansible to install Python 2 on a remote Ubuntu server:</p>
<pre><code>$ ansible ubuntu-dev -m raw -a "apt-get update &amp;&amp; apt-get install -y python-minimal python-simplejson" -i hosts</code></pre>
<p>If using CentOS 7 or RHEL 7 you don&#8217;t need to install Python 2 since it is already installed by default.</p>
<p>But, if using an old version like CentOS 5 or RHEL 5, you will need to <a href="https://github.com/ryandaniels/ansible-role-create-user-ansible#rhel5" target="_blank" rel="noopener noreferrer">run these commands</a>. And if using SELinux with CentOS 5 or RHEL 5, <a href="https://github.com/ryandaniels/ansible-role-create-user-ansible#selinux" target="_blank" rel="noopener noreferrer">run these commands</a> to allow the Ansible copy/file/template modules.</p>
<h3>Create Ansible user on remote servers</h3>
<p>You can use my Ansible role on <a href="https://github.com/ryandaniels/ansible-role-create-user-ansible" target="_blank" rel="noopener noreferrer">GitHub</a> called create-user-ansible to have Ansible create its own user.</p>
<p>This new user will then use password-less sudo by default. But you can change this with a <a href="https://github.com/ryandaniels/ansible-role-create-user-ansible#default-settings" target="_blank" rel="noopener noreferrer">variable</a> if you want to be prompted for a password every time you run Ansible.</p>
<p>Clone the git repository:</p>
<pre><code>$ git clone https://github.com/ryandaniels/ansible-role-create-user-ansible.git ~/ansible/roles/create-user-ansible</code></pre>
<p>Create the Ansible Playbook file:</p>
<pre><code>$ cat &gt; ~/ansible/create-user-ansible.yml &lt;&lt; 'EOF'
---
- hosts: '{{inventory}}'
  become: yes
  roles:
  - create-user-ansible
EOF
</code></pre>
<p>Now the most important step, run the Ansible playbook.</p>
<p>This assumes you have a way to log in via ssh to your servers. (How else would you remotely connect?)<br />
Change &#8220;remote_existing_user&#8221; to the username you already have on your servers.<br />
Change &#8220;username&#8221; to your local Ansible username. This should be the same user as the local Ansible user since this makes things easier.</p>
<p>As a result, this will create a new user on all your servers named: ansible<br />
More options are available, see the <a href="https://github.com/ryandaniels/ansible-role-create-user-ansible" target="_blank" rel="noopener noreferrer">README on GitHub</a>.</p>
<p>If your existing user uses a password for ssh authentication and does not use password-less sudo:</p>
<pre><code>$ ansible-playbook create-user-ansible.yml --ask-pass --become --become-method=su --ask-become-pass --extra-vars "inventory=all ansible_ssh_user=remote_existing_user username=ansible" -i hosts
</code></pre>
<p>If your existing user uses password-less ssh using ssh keys and no password for sudo:</p>
<pre><code>$ ansible-playbook create-user-ansible.yml --become --become-method=sudo --extra-vars "inventory=all ansible_ssh_user=remote_existing_user username=ansible" -i hosts</code></pre>
<h2>Conclusion</h2>
<p>In conclusion, now you have an Ansible user created on all of your servers. You have installed and setup Ansible, and this is the first step! Next, write your own <a href="http://docs.ansible.com/ansible/latest/playbooks.html" target="_blank" rel="noopener noreferrer">Playbook</a>. Or use one of mine to <a href="https://ryandaniels.ca/blog/ansible-update-ubuntu-centos-redhat/">update all of your Ubuntu or CentOS servers and automatically reboot them</a>.</p>
<p>This guide is a quick way to get started with Ansible. Keep in mind, Ansible can be complex. You should plan out how you want to setup Ansible&#8217;s directory structure by following their <a href="https://docs.ansible.com/ansible/latest/playbooks_best_practices.html#alternative-directory-layout" target="_blank" rel="noopener noreferrer">best practices</a>. And take some time to read their <a href="http://docs.ansible.com/ansible/latest/index.html" target="_blank" rel="noopener noreferrer">documentation</a>!</p>
<p>The post <a href="https://ryandaniels.ca/blog/getting-started-ansible-ubuntu-centos/">Getting Started with Ansible on Ubuntu or CentOS</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1133</post-id>	</item>
		<item>
		<title>How to setup OpenVPN with ad blocking on Raspberry Pi or a VPS</title>
		<link>https://ryandaniels.ca/blog/openvpn-ad-blocking/</link>
		
		<dc:creator><![CDATA[Ryan Daniels]]></dc:creator>
		<pubDate>Sun, 04 Feb 2018 14:18:33 +0000</pubDate>
				<category><![CDATA[Ansible]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[Guide]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[OpenVPN]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<guid isPermaLink="false">https://ryandaniels.ca/?p=1117</guid>

					<description><![CDATA[<p><a href="https://ryandaniels.ca/blog/openvpn-ad-blocking/"><img src="https://ryandaniels.ca/wp-content/uploads/2018/02/ad_overload-300x144.jpg" alt="Ad Overload happens.. Is Ad Blocking possible in NYC?" width="300" height="144" class="alignleft size-medium wp-image-1174" /></a> Using a VPN can help to protect your privacy. You can use a VPN to appear like you are in another country to reach a website that was previously blocked, to stop your ISP from restricting you to certain websites, and when travelling to protect your data while using insecure WiFi. There's another: ad blocking.</p>
<p>The post <a href="https://ryandaniels.ca/blog/openvpn-ad-blocking/">How to setup OpenVPN with ad blocking on Raspberry Pi or a VPS</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1174" src="https://ryandaniels.ca/wp-content/uploads/2018/02/ad_overload.jpg" alt="Ad Overload happens.. Is Ad Blocking possible in NYC?" width="800" height="383" srcset="https://ryandaniels.ca/wp-content/uploads/2018/02/ad_overload.jpg 800w, https://ryandaniels.ca/wp-content/uploads/2018/02/ad_overload-300x144.jpg 300w, https://ryandaniels.ca/wp-content/uploads/2018/02/ad_overload-768x368.jpg 768w" sizes="auto, (max-width: 800px) 100vw, 800px" /></p>
<p>Using a VPN (Virtual Private Network) can help to protect your privacy. You can use a VPN to appear like you are in another country so you can reach a website that was previously blocked. You can also use a VPN to stop your ISP from restricting you to certain websites, and when travelling to protect your data while using insecure WiFi. There are many many more reason. However, there can be an extra benefit to using a VPN that people don&#8217;t usually think about: Automatic content blocking (also known as ad blocking).</p>
<p><span id="more-1117"></span></p>
<h2>Why?</h2>
<p>Ad <a href="https://en.wikipedia.org/wiki/Ad_blocking" target="_blank" rel="noopener noreferrer">blocking</a> is now a necessity because of dangerous ads. Some ad networks have had problems with ads containing malicious JavaScript which is actually malware. Even recently <a href="https://arstechnica.com/information-technology/2018/01/now-even-youtube-serves-ads-with-cpu-draining-cryptocurrency-miners/" target="_blank" rel="noopener noreferrer">YouTube was showing ads that contained a cryptocurrency miner</a>. An add-on like <a href="https://addons.mozilla.org/en-US/firefox/addon/ublock-origin/" target="_blank" rel="noopener noreferrer">uBlock Origin for Firefox</a> or <a href="https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm?hl=en" target="_blank" rel="noopener noreferrer">Chrome</a> can help. And customizing your <a href="https://ryandaniels.ca/blog/firefox-privacy-settings-made-easy/">Firefox privacy settings</a> will also help. But what if apps on your phone are showing dangerous ads? Or, what if you have an old phone that&#8217;s no longer getting updates and you want better protection from the recent Meltdown vulnerability? A browser add-on alone will not help you.</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1179" src="https://ryandaniels.ca/wp-content/uploads/2018/02/openvpn.png" alt="OpenVPN with ad blocking" width="208" height="54" /></p>
<p>Now, combine the benefits of a VPN, and ad blocking into one solution. This is where OpenVPN with ad blocking using dnsmasq comes in. For this to work you need control of the OpenVPN server configuration. So using a VPN provider is not an option. But, this way is cheaper! Plus you get the satisfaction of setting up your own VPN!</p>
<h2>Setup a Raspberry Pi with OpenVPN</h2>
<p>You can create your own VPN with a <a href="https://www.raspberrypi.org/products/" target="_blank" rel="noopener noreferrer">Raspberry Pi</a>. If you live in Canada, a good way to get started is with the <a href="http://amzn.to/2FI0IuW" target="_blank" rel="nofollow noopener noreferrer">Raspberry Pi 3 CanaKit</a>. There are many <a href="https://github.com/pivpn/pivpn" target="_blank" rel="noopener noreferrer">guides</a> for setting up a Raspberry Pi with OpenVPN.</p>
<p>However, this method won&#8217;t help if a website restricts your country, or if your ISP blocks you from certain content, since you will have the Raspberry Pi at home. But, you can still use this method to protect you when using open WiFi while travelling, or when at home to get the benefit of ad blocking on your mobile devices.</p>
<h2>Setup a VPS with OpenVPN</h2>
<p>If using a Raspberry Pi isn&#8217;t your thing, you can buy an inexpensive VPS (Virtual Private Server) and host your VPN from there. This may seem like more work, but it&#8217;s pretty easy. And with a VPS you don&#8217;t need to worry about exposing your home network to the public internet. Also, when using a VPS that is only for OpenVPN, you can use common ports to have a better chance of being able to connect to your VPN.</p>
<p><a href="https://ryandaniels.ca/go/linode/" target="_blank" rel="nofollow noopener noreferrer">Linode</a> is a great VPS provider for $5 per month. Or, <a href="https://ryandaniels.ca/go/vultr/" target="_blank" rel="nofollow noopener noreferrer">Vultr</a> offers a VPS for $2.50 per month! (For IPv6 only, IPv4 is $3.50). Whichever VPS provider you choose, make sure to create your VPS in a country that&#8217;s right for you. For example, if you need to access a website usually only available to a certain country. Also make sure you obey their TOS.  I&#8217;m not responsible for anything you do from following this guide!</p>
<p>When using your own VPS, I suggest setting it up with OpenVPN using the <a href="https://github.com/StreisandEffect/streisand" target="_blank" rel="noopener noreferrer">Streisand</a> project. It has many options to bypass blocking if you live in an oppressive country. Note that the commands below will only install OpenVPN (with stunnel) if using Streisand. Plus, Streisand does a good job at protecting your VPS with security tweaks and automatically updating packages.</p>
<h2>Install OpenVPN</h2>
<p>You can install OpenVPN many different ways. Here are two ways I recommend:</p>
<p>To install OpenVPN via PiVPN, follow these <a href="https://github.com/pivpn/pivpn#installation" target="_blank" rel="noopener noreferrer">steps</a>.</p>
<p>To install (only) OpenVPN (also with stunnel) via Streisand, follow the <a href="https://github.com/StreisandEffect/streisand#prerequisites" target="_blank" rel="noopener noreferrer">prerequisites</a> steps, and then run:</p>
<pre><code>$ remote_server_IP=1.2.3.4  # Change IP to your VPS/remote server IP
$ git clone https://github.com/ryandaniels/ansible-role-dnsmasq-adblock.git ~/ansible/roles/dnsmasq-adblock
$ git clone https://github.com/StreisandEffect/streisand.git &amp;&amp; cd streisand
$ ~/streisand/deploy/streisand-existing-cloud-server.sh --ip-address $remote_server_IP --ssh-user username123 --site-config ~/ansible/roles/dnsmasq-adblock/files/streisand-local-site.yml</code></pre>
<p>Change &#8220;remote_server_IP&#8221; to your server&#8217;s IP.<br />
This will use the user &#8220;username123&#8221; with ssh keys for a <a href="https://www.tecmint.com/ssh-passwordless-login-using-ssh-keygen-in-5-easy-steps/" target="_blank" rel="noopener noreferrer">passwordless ssh connection</a>. Be sure to use a use that you&#8217;ve setup with ssh keys.</p>
<h2>Setup ad blocking for OpenVPN using dnsmasq</h2>
<p>Now that you have OpenVPN setup on a RaspberryPi or your own VPS you are ready for the last step, ad blocking. For this you can use a program called dnsmasq. It performs DNS lookups and you can modify the dnsmasq behaviour to block certain domains.</p>
<h3>Manually install and configure dnsmasq on Ubuntu</h3>
<p>These steps were modified from <a href="https://github.com/BobNisco/adblocking-vpn" target="_blank" rel="noopener noreferrer">this github project by Bob Nisco</a> and also uses <a href="https://github.com/StevenBlack/hosts" target="_blank" rel="noopener noreferrer">Steve Black&#8217;s host project</a>.</p>
<p>Install and configure dnsmasq using the DNS servers from OpenDNS:</p>
<pre><code>$ sudo apt-get -y install dnsmasq
$ sudo wget https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts -O /etc/hosts_blocked

$ sudo cat &gt; /etc/dnsmasq.conf &lt;&lt; 'EOF'
domain-needed
bogus-priv
no-resolv
server=208.67.222.222
server=208.67.220.220
listen-address=127.0.0.1
listen-address=10.8.0.1
addn-hosts=/etc/hosts_blocked
EOF</code></pre>
<p>Configure OpenVPN:</p>
<pre><code>$ sudo vi /etc/openvpn/server.conf</code></pre>
<p>Add below, and make sure no other lines have &#8220;dhcp-option DNS&#8221;:</p>
<pre><code>push "dhcp-option DNS 10.8.0.1"</code></pre>
<p>Create a script to update the domains being blocked. And have it run every week:</p>
<pre><code>$ sudo cat &gt; /etc/cron.weekly/adblock_dl_hosts &lt;&lt; 'EOF'
#!/bin/bash
wget https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts -O /etc/hosts_blocked &amp;&amp; systemctl restart dnsmasq.service
EOF

$ sudo chmod +x /etc/cron.weekly/adblock_dl_hosts</code></pre>
<p>Restart dnsmasq and OpenVPN:</p>
<pre><code>$ sudo systemctl restart dnsmasq.service 
$ sudo systemctl restart openvpn.service</code></pre>
<h3>Using Ansible to automatically install and configure dnsmasq on Ubuntu</h3>
<p>If you are familiar with Ansible, then you can add a new role to handle the installation and configuration of dnsmasq for ad blocking automatically. If you are not familiar with Ansible but want to know more, check out my post explaining <a href="https://ryandaniels.ca/blog/getting-started-ansible-ubuntu-centos/">what is Ansible</a>.</p>
<p>I&#8217;ve created this <a href="https://github.com/ryandaniels/ansible-role-dnsmasq-adblock" target="_blank" rel="noopener noreferrer">Ansible role</a> to configure dnsmasq on Ubuntu or Raspbian.</p>
<p>Create the Ansible Playbook:</p>
<pre><code>$ cat &gt; ~/ansible/install-dnsmasq-adblock.yml &lt;&lt; 'EOF'
---
- hosts: '{{inventory}}'
  become: yes
  roles:
  - dnsmasq-adblock
EOF</code></pre>
<p>If using PiVPN or a normal OpenVPN installation (and not Streisand), clone the git repository and run the Ansible Playbook:</p>
<pre><code>$ git clone https://github.com/ryandaniels/ansible-role-dnsmasq-adblock.git ~/ansible/roles/dnsmasq-adblock
$ ansible-playbook install-dnsmasq-adblock.yml --extra-vars "inventory=openvpn-server" -i hosts</code></pre>
<p>If you are using Streisand, then you already cloned the git repositories. Just run the Ansible Playbook:</p>
<pre><code>$ ansible-playbook install-dnsmasq-adblock.yml --extra-vars "inventory=streisand-host adblock_manage_openvpn=false" -i ~/streisand/inventories/inventory-existing</code></pre>
<h2>Conclusion</h2>
<p>In conclusion, now you are more secure by using OpenVPN with ad blocking on your own Raspberry Pi or VPS. And if you are using your own VPS you can use the Streisand project to secure your installation and also to expose common ports to have a higher chance of being able to connect to your VPN from anywhere.</p>
<p>The post <a href="https://ryandaniels.ca/blog/openvpn-ad-blocking/">How to setup OpenVPN with ad blocking on Raspberry Pi or a VPS</a> appeared first on <a href="https://ryandaniels.ca/">Ryan Daniels</a>.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1117</post-id>	</item>
	</channel>
</rss>
