<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Arpit's Blog]]></title><description><![CDATA[Arpit's Blog]]></description><link>https://arpitzelawat.com</link><generator>RSS for Node</generator><lastBuildDate>Wed, 15 Apr 2026 05:09:59 GMT</lastBuildDate><atom:link href="https://arpitzelawat.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How to Get Started with Ansible Vault]]></title><description><![CDATA[Goal: With this short blog, my aim is to give the reader all the information he needs to successfully implement Ansible Vault in his DevOps project.
Assumption: This blog assumes that you already have a working knowledge of ansible concepts, such as ...]]></description><link>https://arpitzelawat.com/how-to-get-started-with-ansible-vault</link><guid isPermaLink="true">https://arpitzelawat.com/how-to-get-started-with-ansible-vault</guid><category><![CDATA[ansible]]></category><category><![CDATA[Ansible Vault]]></category><category><![CDATA[ansible-playbook]]></category><category><![CDATA[Ansible variables]]></category><dc:creator><![CDATA[Arpit Zelawat]]></dc:creator><pubDate>Thu, 27 Jun 2024 04:52:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1719463860462/e22b7fd0-886c-4f93-971c-35d19e6c54db.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>Goal:</strong> With this short blog, my aim is to give the reader all the information he needs to successfully implement Ansible Vault in his DevOps project.</p>
<p><strong>Assumption:</strong> This blog assumes that you already have a working knowledge of ansible concepts, such as roles, variables, inventory, playbooks etc.</p>
<h2 id="heading-what-is-ansible-vault">What is Ansible Vault?</h2>
<p>According the <a target="_blank" href="https://docs.ansible.com/ansible/latest/vault_guide/vault.html">official documentation</a>:</p>
<blockquote>
<p>Ansible Vault encrypts variables and files so you can protect sensitive content such as passwords or keys rather than leaving it visible as plaintext in playbooks or roles.</p>
</blockquote>
<p>Let me expand on the 'encrypted variable and files' part. You can keep all your sensitive information inside a single encrypted file, or you can encrypt individual variables/strings, and use them right inside your <code>playbook</code> or <code>vars</code> files.</p>
<h3 id="heading-choosing-between-encrypted-variables-or-encrypted-files">Choosing between encrypted variables or encrypted files</h3>
<h4 id="heading-encrypted-files">Encrypted Files</h4>
<p><strong>Pros:</strong></p>
<ul>
<li><p>Easy to manage/share a file</p>
</li>
<li><p>Easy to exclude encrypted files using <code>.gitignore</code></p>
</li>
<li><p>Easy to change <code>rekey</code> / change password.</p>
</li>
</ul>
<p><strong>Cons:</strong></p>
<ul>
<li><p>Every time you need to update the contents of your encrypted file, you have to decrypt it, make your changes, and the encrypt it again.</p>
</li>
<li><p>Updating your encrypted files, creates unnecessary changes to your <code>git</code> repository.</p>
</li>
</ul>
<h4 id="heading-encrypted-variables">Encrypted Variables</h4>
<p><strong>Pros:</strong></p>
<ul>
<li><p>Easy to update. You don't have to update a file containing other variables, but just your intended variable.</p>
</li>
<li><p>Doesn't create unnecessary changes to your <code>git</code> repository.</p>
</li>
</ul>
<p><strong>Cons:</strong></p>
<ul>
<li><p>Difficult to <code>rekey</code> / change password. If you have 20 encrypted variables, then you have to re-encrypt all 20 variables to change your password.</p>
</li>
<li><p>Impossible to exclude them out of your <code>git</code> repository. Encrypted variables are used within your playbook/vars files. Excluding these files means excluding your playbook/vars from the repository.</p>
</li>
</ul>
<p>Personally, I prefer encrypted files as they are easy to manage and can be excluded from the repository, even though, they are a hassle to update.</p>
<h3 id="heading-the-ansible-vault-command-line-tool">The <code>ansible-vault</code> command line tool</h3>
<p>Here's an oversimplified syntax of the <code>ansible-vault</code> command line tool:</p>
<pre><code class="lang-bash">ansible-vault &lt;password <span class="hljs-built_in">source</span>&gt; &lt;<span class="hljs-built_in">command</span>&gt;
</code></pre>
<p>There are three ways to provide password to the <code>ansible-vault</code> tool:</p>
<ul>
<li><p>A password prompt using the <code>--ask-vault-pass</code> option.</p>
</li>
<li><p>A password file provided by the <code>--vault-password-file path/to/password/file</code> option.</p>
</li>
<li><p>Third party secrets manager</p>
</li>
</ul>
<p>There are 7 commands for the tool, namely create, decrypt, edit, view, encrypt, encrypt_string, and rekey. Lets look at them.</p>
<h3 id="heading-create-an-encrypted-variable">Create an encrypted variable</h3>
<p>Just execute one of the following commands to create an encrypted variable:</p>
<pre><code class="lang-bash">ansible-vault encrypt_string --ask-vault-pass <span class="hljs-string">'mysupersecretpassword'</span> --name <span class="hljs-string">'password_vars'</span>

Or 

ansible-vault encrypt_string --vault-password-file path/to/password/file <span class="hljs-string">'mysupersecretpassword'</span> --name <span class="hljs-string">'password_vars'</span>
</code></pre>
<p>You'll get an output similar to this:</p>
<pre><code class="lang-plaintext">password: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          35633434356139363131363933356438316561666431313862383231393364633564343862636330
          6136366435313165626637326238326432316264383562620a356664393361373230326339323934
          32653462343235633738336332623437393434333137333634363437346234356635363734623030
          3761363238656131330a386536393665653034636337343733376437316536306666376638616432
          3761
</code></pre>
<p>You can use this encrypted string directly in your YAML files.</p>
<h3 id="heading-create-an-encrypted-file">Create an encrypted file</h3>
<p>This command will create new file named <code>vault.yml</code> :</p>
<pre><code class="lang-bash">ansible-vault create vault.yml
</code></pre>
<p>This command will encrypt an existing file named <code>vault.yml</code> :</p>
<pre><code class="lang-bash">ansible-vault encrypt vault.yml
</code></pre>
<h3 id="heading-view-an-encrypted-file">View an encrypted file</h3>
<pre><code class="lang-bash">ansible-vault --ask-vault-pass view vault.yml
</code></pre>
<h3 id="heading-edit-an-encrypted-file">Edit an encrypted file</h3>
<pre><code class="lang-bash">ansible-vault --ask-vault-pass edit vault.yml
</code></pre>
<p>Set environment variable $EDITOR to <code>nano</code> if you don't want to use <code>vi</code>.</p>
<h3 id="heading-decrypt-a-file">Decrypt a file</h3>
<pre><code class="lang-bash">ansible-vault --ask-vault-pass decrypt vault.yml
</code></pre>
<h3 id="heading-change-password-for-a-file">Change password for a file</h3>
<pre><code class="lang-bash">ansible-vault rekey vault.yml
</code></pre>
<h3 id="heading-using-ansible-vault-in-an-ansible-playbook">Using ansible vault in an ansible playbook</h3>
<p>Let's implement what we have learned so far using an example.</p>
<p>In this example we'll try to ping a server using an ansible playbook. But since the server's IP address and user name is sensitive information, we'll keep them encrypted. We'll keep the IP address in an encrypted file and the username as an encrypted variable.</p>
<p>Lets start by creating a password file:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> <span class="hljs-string">'my_vault_password'</span> &gt; .vault_pass
</code></pre>
<p>Make sure you don't upload the password in a <code>git</code> repository:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> <span class="hljs-string">'.vault_pass'</span> &gt;&gt; .gitignore
</code></pre>
<p>There are two ways to use this vault password file:</p>
<ol>
<li><p>Passing it as an argument <code>--vault-password-file</code></p>
<pre><code class="lang-bash"> ansible-vault view --vault-password-file .vault_pass vault.yml
</code></pre>
</li>
<li><p>Setting path to this file in environment variable</p>
<pre><code class="lang-bash"> <span class="hljs-built_in">export</span> ANSIBLE_VAULT_PASSWORD_FILE=path/to/.vault_pass
</code></pre>
</li>
</ol>
<p>To encrypt the username <code>ubuntu</code>:</p>
<pre><code class="lang-bash">ansible-vault encrypt_string --vault-password-file .vault_pass <span class="hljs-string">'ubuntu'</span> --name <span class="hljs-string">'vault_ansible_user'</span>
</code></pre>
<p>You'll get an output similar to the one below. Save it.</p>
<blockquote>
<pre><code class="lang-bash">vault_ansible_user: !vault |
          <span class="hljs-variable">$ANSIBLE_VAULT</span>;1.1;AES256
          64653062636463306663313065646238616638623039316562643765363635653065623031643463
          3636386430323964626135366563313162623263656434650a386538343233333764383236626266
          62313635383962383461663861313663613932643666333234333666393134303964626463346539
          3237666531393736660a323031346264613339613037366232343263386530663365366139653333
          6331
</code></pre>
</blockquote>
<p>Now, let's create an encrypted file <code>vault.yml</code> to store our server's IP address.</p>
<pre><code class="lang-bash">ansible-vault create --vault-password-file .vault_pass vault.yml
</code></pre>
<p>Paste the following content inside the editor:</p>
<pre><code class="lang-plaintext">---
vault_ansible_host: 1.1.1.1
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719460846905/16f0af6e-1d66-41e7-9cc9-e03e3cf8b0ae.png" alt class="image--center mx-auto" /></p>
<p>Next, we'll define the <code>inventory.yml</code> file.</p>
<pre><code class="lang-yaml"><span class="hljs-meta">---</span>
<span class="hljs-attr">server:</span>
  <span class="hljs-attr">hosts:</span>
    <span class="hljs-attr">server01:</span>
      <span class="hljs-attr">ansible_host:</span> <span class="hljs-string">"<span class="hljs-template-variable">{{ vault_ansible_host }}</span>"</span>
      <span class="hljs-attr">ansible_user: vault_ansible_user:</span> <span class="hljs-type">!vault</span> <span class="hljs-string">|
          $ANSIBLE_VAULT;1.1;AES256
          35633434356139363131363933356438316561666431313862383231393364633564343862636330
          6136366435313165626637326238326432316264383562620a356664393361373230326339323934
          32653462343235633738336332623437393434333137333634363437346234356635363734623030
          3761363238656131330a386536393665653034636337343733376437316536306666376638616432
          3761</span>
</code></pre>
<p>Finally, we'll write our <code>playbook.yml</code>.</p>
<pre><code class="lang-yaml"><span class="hljs-meta">---</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Playbook</span>
  <span class="hljs-attr">hosts:</span> <span class="hljs-string">server</span>
  <span class="hljs-attr">vars_files:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">vault.yml</span>
  <span class="hljs-attr">tasks:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">ping</span> <span class="hljs-string">task</span>
      <span class="hljs-attr">ansible.builtin.ping:</span>
</code></pre>
<p>Here's my directory structure:</p>
<pre><code class="lang-plaintext">.
├── .vault_pass
├── inventory.yml
├── playbook.yml
└── vault.yml
</code></pre>
<p>To run the playbook, execute the following command:</p>
<pre><code class="lang-bash">ansible-playbook --vault-password-file .vault_pass -i inventory/hosts.yml playbook.yml
</code></pre>
<p>This is how to use ansible vault. For more information, please refer the <a target="_blank" href="https://docs.ansible.com/ansible/latest/vault_guide/vault.html">official documentation</a>. Thank you!</p>
]]></content:encoded></item><item><title><![CDATA[Setting up Ansible with Molecule]]></title><description><![CDATA[If you're like me and are trying to learn Ansible, you know how cumbersome it is to test. To test your playbook, you setup a cloud instance, run your ansible playbook, verify everything and then delete the instance either to save money or get a clean...]]></description><link>https://arpitzelawat.com/setting-up-ansible-with-molecule</link><guid isPermaLink="true">https://arpitzelawat.com/setting-up-ansible-with-molecule</guid><category><![CDATA[ansible]]></category><category><![CDATA[Beginner Developers]]></category><category><![CDATA[Devops]]></category><dc:creator><![CDATA[Arpit Zelawat]]></dc:creator><pubDate>Tue, 28 May 2024 16:00:52 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1716912423686/75ba63b5-0af0-46af-be2e-e7c27f8de9d5.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you're like me and are trying to learn Ansible, you know how cumbersome it is to test. To test your playbook, you setup a cloud instance, run your ansible playbook, verify everything and then delete the instance either to save money or get a clean slate for your next testing scenario.</p>
<p>However, there is a better way. Ansible comes with its own testing framework called Molecule. To test ansible playbooks, Molecule first creates one or more virtual environments on your system, runs the ansible playbook against them, verifies everything using another ansible playbook and finally destroys the virtual environments.</p>
<p>In this blog, I'm going to share how to setup an ansible development environment with Molecule. This blog is heavily inspired by the <a target="_blank" href="https://ansible.readthedocs.io/projects/molecule/">official ansible molecule documentation.</a></p>
<h4 id="heading-requirements">Requirements:</h4>
<p>Python installed on your system.</p>
<h4 id="heading-step-1-create-python-virtual-environment">Step 1: Create python virtual environment</h4>
<p>a.) In your project directory, create a folder. We'll name it <code>pyvenv</code>. Then create the python virtual environment using <code>python -m venv /path/to/your/directory</code></p>
<pre><code class="lang-bash">mkdir pyvenv
python3 -m venv pyvenv
</code></pre>
<p>b.) Activate the python venv</p>
<p><code>source pyvenv/bin/activate</code></p>
<h4 id="heading-step-2-install-molecule-and-dependencies">Step 2: Install molecule and dependencies</h4>
<p>a.) Install required packages in the <code>pyvenv</code> environment</p>
<pre><code class="lang-bash">pip3 install molecule
</code></pre>
<p>Installing <code>molecule</code> will automatically install <code>ansible</code> as its a dependency.</p>
<p>b. ) Check everything:</p>
<pre><code class="lang-bash">molecule --version
</code></pre>
<p>Result:</p>
<pre><code class="lang-plaintext">molecule 24.2.1 using python 3.12
    ansible:2.17.0
    default:24.2.1 from molecule
</code></pre>
<h4 id="heading-step-3-create-ansible-collection-and-role">Step 3: Create ansible collection and role</h4>
<p>In older blogs, you might see the command <code>molecule init role example-role</code> to create ansible roles. This command basically executed <code>ansible-galaxy</code> command in the background to create a proper directory structure for the role, but later ansible removed it because it was redundant.</p>
<p>a.) Create new collection</p>
<p><strong>IMPORTANT:</strong> According the official documentation, a new collection must be placed under a <code>collections/ansible_collections</code> directory. If your collection is not in this directory structure, <code>molecule</code> won't be able to find your collection.</p>
<p>We'll name our collection <code>my.cloud</code></p>
<pre><code class="lang-bash">mkdir collections
<span class="hljs-built_in">cd</span> collections
mkdir ansible_collections
<span class="hljs-built_in">cd</span> ansible_collections
ansible-galaxy collection init my.cloud
</code></pre>
<p>b.) Create role</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> my/cloud/roles
ansible-galaxy role init test_role
</code></pre>
<p>c.) Add the following test task in the <code>test_role/tasks/main.yml</code> file:</p>
<pre><code class="lang-yaml"><span class="hljs-meta">---</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Task</span> <span class="hljs-string">is</span> <span class="hljs-string">running</span> <span class="hljs-string">from</span> <span class="hljs-string">within</span> <span class="hljs-string">the</span> <span class="hljs-string">role</span>
  <span class="hljs-attr">ansible.builtin.debug:</span>
    <span class="hljs-attr">msg:</span> <span class="hljs-string">"This is a task from test_role."</span>
</code></pre>
<h4 id="heading-step-4-create-a-playbook">Step 4: Create a playbook</h4>
<p>a.) Create <code>playbook.yml</code> file in the collection root i.e. the <code>cloud</code> folder</p>
<pre><code class="lang-bash">mkdir playbooks
<span class="hljs-built_in">cd</span> playbooks
touch playbook.yml
</code></pre>
<p>b.) Edit the <code>playbook.yml</code> file and add the following:</p>
<pre><code class="lang-yaml"><span class="hljs-meta">---</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Test</span> <span class="hljs-string">new</span> <span class="hljs-string">role</span> <span class="hljs-string">from</span> <span class="hljs-string">within</span> <span class="hljs-string">this</span> <span class="hljs-string">playbook</span>
  <span class="hljs-attr">hosts:</span> <span class="hljs-string">localhost</span>
  <span class="hljs-attr">gather_facts:</span> <span class="hljs-literal">false</span>
  <span class="hljs-attr">tasks:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Testing</span> <span class="hljs-string">role</span>
      <span class="hljs-attr">ansible.builtin.include_role:</span>
        <span class="hljs-attr">name:</span> <span class="hljs-string">test_role</span>
        <span class="hljs-attr">tasks_from:</span> <span class="hljs-string">main.yml</span>
</code></pre>
<h4 id="heading-step-5-adding-molecule-to-the-collection">Step 5: Adding molecule to the collection</h4>
<p>a.) Create new folder <code>extensions</code> in the collection root and initiate molecule</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> ..
mkdir extensions
<span class="hljs-built_in">cd</span> extensions
molecule init scenario test_scenario
</code></pre>
<p>Inside the molecule directory a folder called <code>test_scenario</code> was created. That’s the name of the scenario we defined. If we don’t specify a scenario name, the directory will be called <code>default</code> .</p>
<pre><code class="lang-plaintext">.
└── molecule
    └── test_scenario
        ├── converge.yml
        ├── create.yml
        ├── destroy.yml
        └── molecule.yml
</code></pre>
<p>Make sure your final directory structure is similar to the one shown below, if not, you might get issues running Molecule.</p>
<pre><code class="lang-plaintext">.
└── collections
    └── ansible_collections
        └── my
            └── cloud
                ├── docs
                ├── extensions
                │   └── molecule
                │       └── test_scenario
                ├── meta
                ├── playbooks
                ├── plugins
                └── roles
                    └── test_role
                        ├── defaults
                        ├── files
                        ├── handlers
                        ├── meta
                        ├── tasks
                        ├── templates
                        ├── tests
                        └── vars
</code></pre>
<h4 id="heading-step-6-configuring-molecule">Step 6: Configuring molecule</h4>
<p>a.) Edit the <code>molecule.yml</code> to configure docker</p>
<pre><code class="lang-yaml"><span class="hljs-meta">---</span>
<span class="hljs-attr">driver:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">default</span>
<span class="hljs-attr">platforms:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">instance</span>
    <span class="hljs-comment"># you might want to add your own variables here based on what provisioning</span>
    <span class="hljs-comment"># you are doing like:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">ubuntu:latest</span>
</code></pre>
<p>b.) Update <code>converge.yml</code> to test our playbook/role</p>
<p><code>converge.yml</code> is where you tell molecule what to test. Add <strong>one</strong> of the following in the <code>converge.yml</code></p>
<p>To test the whole playbook:</p>
<pre><code class="lang-yaml"><span class="hljs-meta">---</span>
<span class="hljs-comment"># To test the whole playbook</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Include</span> <span class="hljs-string">a</span> <span class="hljs-string">playbook</span> <span class="hljs-string">from</span> <span class="hljs-string">a</span> <span class="hljs-string">collection</span>
  <span class="hljs-attr">ansible.builtin.import_playbook:</span> <span class="hljs-string">my.cloud.playbook</span>
</code></pre>
<p>To test just a role:</p>
<pre><code class="lang-yaml"><span class="hljs-meta">---</span>
<span class="hljs-comment"># To test a role</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Test</span> <span class="hljs-string">new</span> <span class="hljs-string">role</span> <span class="hljs-string">from</span> <span class="hljs-string">within</span> <span class="hljs-string">this</span> <span class="hljs-string">playbook</span>
  <span class="hljs-attr">hosts:</span> <span class="hljs-string">localhost</span>
  <span class="hljs-attr">gather_facts:</span> <span class="hljs-literal">false</span>
  <span class="hljs-attr">tasks:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Testing</span> <span class="hljs-string">role</span>
      <span class="hljs-attr">ansible.builtin.include_role:</span>
        <span class="hljs-attr">name:</span> <span class="hljs-string">my.cloud.test_role</span>
        <span class="hljs-attr">tasks_from:</span> <span class="hljs-string">main.yml</span>
</code></pre>
<p>c.) Run molecule test</p>
<p><code>molecule test -s test_scenario</code></p>
]]></content:encoded></item></channel></rss>