<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">



  <title><![CDATA[stafwag Blog]]></title>
  <link href="https://stafwag.github.io/blog/atom.xml" rel="self"/>
  <link rel="alternate" href="https://blog.wagemakers.be/atom.xml" /> <link href="https://blog.wagemakers.be }}"/>
  <link rel="self" type="application/atom+xml" href="https://stafwag.github.io/blog/atom.xml" />
  <link rel="alternate" type="application/atom+xml" href="https://blog.wagemakers.be/atom.xml" />
  <link rel="self" type="application/rss+xml" href="https://stafwag.github.io/blog/atom.xml" />
  <link rel="alternate" type="application/rss+xml" href="https://blog.wagemakers.be/atom.xml" />
  <updated>2026-01-26T19:13:17+00:00</updated>
  <id>https://stafwag.github.io</id>
  <author>
    <name><![CDATA[Staf Wagemakers]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[Moved my blog to [blog.wagemakers.be](https://blog.wagemakers.be)]]></title>
    <link href="https://stafwag.github.io/blog/blog/2026/01/26/blog-wagemakers-be/"/>
    <updated>2026-01-26T17:26:00+00:00</updated>
    <id>https://stafwag.github.io/blog/blog/2026/01/26/blog-wagemakers-be</id>
    <content type="html"><![CDATA[<p><strong>
If you follow my blog posts with an RSS reader, update the rss feed to: <a href="https://blog.wagemakers.be/atom.xml">https://blog.wagemakers.be/atom.xml </a> <br /> …If you want to continue to follow me off-course ;-)
</strong></p>

<p>I moved my blog from GitHub to my own hosting ( powered by <a href="https://procolix.eu">Procolix</a> ).<br />
Procolix sponsored my hosting for 20 years, till I decided to start my company <a href="https://mask27.dev">Mask27.dev</a>.</p>

<p>One reason is that Microsoft seems to like to put “copilot everywhere”, including on repositories hosted on github. While I don’t dislike AI ( artificial intelligence ), LLM ( Large Language Models ) are a nice piece of technology. The security, privacy, and other issues are overlooked or even just ignored.</p>

<p>The migration was a bit more complicated as usual, as nothing “is easy” ;-)</p>

<p>You’ll find the pitfalls of moving my blog below as they might be useful for somebody else ( including the future me ).</p>

<!--more-->

<h1 id="html-redirect">Html redirect</h1>

<p>I use <a href="https://jekyllrb.com/">Jekyll</a> to generate my webpages on my blog. I might switch to <a href="https://gohugo.io/">HUGO</a> in the future.</p>

<p>While there’re Jekyll plugins available to preform a redirect, I decide to keep it simple and added a http header to <code class="language-plaintext highlighter-rouge">_includes/head.html</code></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&lt;meta http-equiv="refresh" content="0; url=https://blog.wagemakers.be/blog/2026/01/26/blog-wagemakers-be/" /&gt;
</code></pre></div></div>

<h1 id="hardcoded-links">Hardcoded links</h1>

<p>I had some hardcoded links for <code class="language-plaintext highlighter-rouge">image</code>, <code class="language-plaintext highlighter-rouge">url</code>, etc on my blog posts.</p>

<p>I used the script below to update the links in my <code class="language-plaintext highlighter-rouge">_post</code> directory.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/sh</span>

<span class="nb">set</span> <span class="nt">-o</span> errexit
<span class="nb">set</span> <span class="nt">-o</span> pipefail
<span class="nb">set</span> <span class="nt">-o</span> nounset

<span class="k">for </span>file <span class="k">in</span> <span class="k">*</span><span class="p">;</span> <span class="k">do

  </span><span class="nb">echo</span> <span class="s2">"... Processing file: </span><span class="k">${</span><span class="nv">file</span><span class="k">}</span><span class="s2">"</span>

  <span class="nb">sed</span> <span class="nt">-i</span> <span class="k">${</span><span class="nv">file</span><span class="k">}</span> <span class="nt">-e</span> s@https://stafwag.github.io/blog/blog/@https://blog.wagemakers.be/blog/@g
  <span class="nb">sed</span> <span class="nt">-i</span> <span class="k">${</span><span class="nv">file</span><span class="k">}</span> <span class="nt">-e</span> s@https://stafwag.github.io/blog/images/@https://blog.wagemakers.be/images/@g
  <span class="nb">sed</span> <span class="nt">-i</span> <span class="k">${</span><span class="nv">file</span><span class="k">}</span> <span class="nt">-e</span> s@<span class="se">\(</span>https://stafwag.github.io/blog<span class="se">\)</span>@<span class="se">\(</span>https://blog.wagemakers.be<span class="se">\)</span>@

<span class="k">done</span>
</code></pre></div></div>

<h1 id="disqus">Disqus</h1>

<p>I use <a href="https://disqus.com/">DISQUS</a> as the comment system on my blog. As the HTML pages got a proper redirect, I could ask Disqus to reindex the pages so the old comments became available again.</p>

<p>More information is available at: <a href="https://help.disqus.com/en/articles/1717126-redirect-crawler">https://help.disqus.com/en/articles/1717126-redirect-crawler</a></p>

<p>Without a redirect, you can download the URL in a csv and add a migration URL to the csv file and upload it to Disqus. You can find information about it in the link below.</p>

<p><a href="https://help.disqus.com/en/articles/1717129-url-mapper">https://help.disqus.com/en/articles/1717129-url-mapper</a></p>

<h1 id="rss-redirect">RSS redirect</h1>

<p>I didn’t find a good way to redirect for RSS feeds, which RSS readers use correctly.<br />
If you know a good way to handle it, please let me know.</p>

<p>I tried to add an XML redirect as suggested at: <a href="https://www.rssboard.org/redirect-rss-feed">https://www.rssboard.org/redirect-rss-feed</a>.
But this doesn’t seem to work with the RSS readers I tested (NewsFlash, Akregator).</p>

<p>These are the steps I took.</p>

<h2 id="html-header">HTML header</h2>

<p>I added the following headers to <code class="language-plaintext highlighter-rouge">_includes/head.html</code></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&lt;link rel="self" type="application/atom+xml"  href="{{ site.url }}{{ site.baseurl }}/atom.xml" /&gt;
&lt;link rel="alternate" type="application/atom+xml" title="Wagemakers Atom Feed" href="https://wagemakers.be/atom.xml"&gt;


&lt;&lt;link rel="self" type="application/rss+xml"  href="{{ site.url }}{{ site.baseurl }}/atom.xml" /&gt;
&lt;link rel="alternate" type="application/rss+xml" title="Wagemakers Atom Feed" href="https://wagemakers.be/atom.xml"&gt;
</code></pre></div></div>

<h2 id="custom-feedxml">Custom feed.xml</h2>

<p>When I switched from <a href="http://octopress.org/">Octopress</a> to “plain jekyll” I started to use the <code class="language-plaintext highlighter-rouge">jekyll-feed</code>plugin. But I still had the old RSS page from Octopress available, so I decided to use it to generate <code class="language-plaintext highlighter-rouge">atom.xml</code> and <code class="language-plaintext highlighter-rouge">feed.xml</code> in the <code class="language-plaintext highlighter-rouge">link rel=self</code> and <code class="language-plaintext highlighter-rouge">link rel="alternate"</code> directives.</p>

<p>Full code below or on GitHub: <a href="https://github.com/stafwag/blog/blob/gh-pages/feed.xml">https://github.com/stafwag/blog/blob/gh-pages/feed.xml</a></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>---
layout: null
---
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;feed xmlns="http://www.w3.org/2005/Atom"&gt;



  &lt;title&gt;&lt;![CDATA[stafwag Blog]]&gt;&lt;/title&gt;
  &lt;link href="https://stafwag.github.io/blog/atom.xml" rel="self"/&gt;
  &lt;link rel="alternate" href="https://blog.wagemakers.be/atom.xml" /&gt; &lt;link href="https://blog.wagemakers.be }}"/&gt;
  &lt;link rel="self" type="application/atom+xml" href="https://stafwag.github.io/blog/atom.xml" /&gt;
  &lt;link rel="alternate" type="application/atom+xml" href="https://blog.wagemakers.be/atom.xml" /&gt;
  &lt;link rel="self" type="application/rss+xml" href="https://stafwag.github.io/blog/atom.xml" /&gt;
  &lt;link rel="alternate" type="application/rss+xml" href="https://blog.wagemakers.be/atom.xml" /&gt;
  &lt;updated&gt;2026-01-26T19:13:17+00:00&lt;/updated&gt;
  &lt;id&gt;https://stafwag.github.io&lt;/id&gt;
  &lt;author&gt;
    &lt;name&gt;&lt;![CDATA[Staf Wagemakers]]&gt;&lt;/name&gt;
    
  &lt;/author&gt;
  &lt;generator uri="http://octopress.org/"&gt;Octopress&lt;/generator&gt;

{% for post in site.posts limit: 10000 %}
  &lt;entry&gt;
&lt;title type="html"&gt;&lt;![CDATA[{% if site.titlecase %}{{ post.title | titlecase | cdata_escape }}{% else %}{{ post.title | cdata_escape }}{% endif %}]]&gt;&lt;/title&gt;
 &lt;link href="{{ site.url }}{{ site.baseurl }}{{ post.url }}"/&gt;
    &lt;updated&gt;&lt;/updated&gt;
    &lt;id&gt;https://stafwag.github.io/blog&lt;/id&gt;
    &lt;content type="html"&gt;&lt;![CDATA[]]&gt;&lt;/content&gt;
  &lt;/entry&gt;
{% endfor %}
&lt;/feed&gt;
</code></pre></div></div>

<h1 id="notify-users">Notify users</h1>

<p>I created this blog post to notify the users ;-)</p>

<p><strong><em>Have fun!</em></strong></p>

<h1 id="links">Links</h1>

<ul>
  <li><a href="https://help.disqus.com/en/articles/1717129-url-mapper">https://help.disqus.com/en/articles/1717129-url-mapper</a></li>
  <li><a href="https://help.disqus.com/en/articles/1717126-redirect-crawler">https://help.disqus.com/en/articles/1717126-redirect-crawler</a></li>
  <li><a href="https://www.heerentanna.com/blog/move-disqus-comment-old-url-new.html">https://www.heerentanna.com/blog/move-disqus-comment-old-url-new.html</a></li>
  <li><a href="https://www.rssboard.org/redirect-rss-feed">https://www.rssboard.org/redirect-rss-feed</a></li>
</ul>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Best wishes 2026!]]></title>
    <link href="https://stafwag.github.io/blog/blog/2026/01/04/best_wishes_2026/"/>
    <updated>2026-01-04T09:26:00+00:00</updated>
    <id>https://stafwag.github.io/blog/blog/2026/01/04/best_wishes_2026</id>
    <content type="html"><![CDATA[<p><a href="https://stafwag.github.io/blog/images/2026/2026.jpg"><img src="https://stafwag.github.io/blog/images/2026/2026s.jpg" class="left" width="1000" height="481" alt="2026" /> </a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[ansible-k3s-on-vms updated to Debian 13 (Trixie)]]></title>
    <link href="https://stafwag.github.io/blog/blog/2025/11/13/ansible-k3s-trixie/"/>
    <updated>2025-11-13T04:30:00+00:00</updated>
    <id>https://stafwag.github.io/blog/blog/2025/11/13/ansible-k3s-trixie</id>
    <content type="html"><![CDATA[<p>I use the lightweight <a href="https://kubernetes.io/">Kubernetes</a> <a href="https://k3s.io/">K3s</a> on a 3-node <a href="https://www.raspberrypi.com/products/raspberry-pi-4-model-b/">Raspberry Pi 4</a> cluster.</p>

<p>And created a few ansible roles to provision the virtual machines with cloud image with cloud-init and deploy k3s on it.</p>

<p>I updated the roles below to be compatible with the latest Debian release: Debian 13 Trixie.</p>

<p>With this release comes a new movie ;-)</p>

<p><a href="https://www.youtube.com/watch?v=4K6D_wzETpQ" title="Deploy k3s on ips"><img src="https://stafwag.github.io/blog/images/ansible-k3s-on-vms/ansible-k3s-pi-deployment_1440.jpg" alt="Deploy k3s on ips" /></a></p>

<!--more-->

<p>The latest version 1.3.0 is available at: <a href="https://github.com/stafwag/ansible-k3s-on-vms">https://github.com/stafwag/ansible-k3s-on-vms</a></p>

<p><br /></p>

<p><strong><em>Have fun!</em></strong></p>

<h1 id="delegated_vm_install-211">delegated_vm_install 2.1.1</h1>

<p>stafwag.delegated_vm_install  is available at:
<a href="https://github.com/stafwag/ansible-role-delegated_vm_install">https://github.com/stafwag/ansible-role-delegated_vm_install</a></p>

<h3 id="211">2.1.1</h3>
<h4 id="changelog">Changelog</h4>

<ul>
  <li>Added stafwag.libvirt to requirements</li>
  <li>Added stafwag.package_update to requirements</li>
</ul>

<h3 id="210">2.1.0</h3>
<h4 id="changelog-1">Changelog</h4>

<ul>
  <li>Added Debian 13 template</li>
  <li>Added Debian 13 single node examples</li>
  <li>Updated 3 node example to Debian 13</li>
</ul>

<p><br /></p>

<h1 id="virt_install_vm-120">virt_install_vm 1.2.0</h1>

<p>stafwag.virt_install_vm 1.1.0 is available at: <a href="https://github.com/stafwag/ansible-role-virt_install_vm">https://github.com/stafwag/ansible-role-virt_install_vm</a></p>

<h3 id="120">1.2.0</h3>
<h4 id="changelog-2">Changelog</h4>

<ul>
  <li>Added Debian 13 template and example</li>
  <li>Set graphics to VNC</li>
</ul>

<p><br /></p>

<h1 id="qemu_img">qemu_img</h1>

<p>stafwag.qemu_img 2.3.3 available at: <a href="https://github.com/stafwag/ansible-role-qemu_img">https://github.com/stafwag/ansible-role-qemu_img</a></p>

<h3 id="120-1">1.2.0</h3>
<h4 id="changelog-3">Changelog</h4>

<ul>
  <li>Corrected ansible lint errors</li>
  <li>Updated convert to array
    <ul>
      <li>Updated conversion to array to be compatible with the latest ansible versions</li>
      <li>Added debugging</li>
    </ul>
  </li>
</ul>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Lookat 2.1.0 released]]></title>
    <link href="https://stafwag.github.io/blog/blog/2025/09/14/lookat-2-dot-1-0-released/"/>
    <updated>2025-09-14T18:04:00+00:00</updated>
    <id>https://stafwag.github.io/blog/blog/2025/09/14/lookat-2-dot-1-0-released</id>
    <content type="html"><![CDATA[<p><a href="https://stafwag.github.io/blog/images/lookat/lookat_2_1_0.png"><img src="https://stafwag.github.io/blog/images/lookat/lookat_2_1_0.png" class="right" width="600" height="320" alt="lookat 2.1.0" /> </a></p>

<p>Lookat 2.1.0 is the latest stable release of Lookat/Bekijk, a user-friendly Unix file browser/viewer that supports colored man pages.</p>

<p>The focus of the 2.1.0 release is to add ANSI Color support.</p>

<p><br /> <br /></p>

<h2 id="news">News</h2>

<h3 id="14-sep-2025-lookat-210-released"><strong>14 Sep 2025</strong> Lookat 2.1.0 Released</h3>

<p>Lookat / Bekijk 2.1.0rc2 has been released as Lookat / Bekijk 2.1.0</p>

<h3 id="3-aug-2025-lookat-210rc2-released"><strong>3 Aug 2025</strong> Lookat 2.1.0rc2 Released</h3>

<p>Lookat 2.1.0rc2 is the second release candicate of Lookat 2.1.0</p>

<h4 id="changelog">ChangeLog</h4>

<h5 id="lookat--bekijk-210rc2">Lookat / Bekijk 2.1.0rc2</h5>

<ul>
  <li>Corrected italic color</li>
  <li>Don’t reset the search offset when cursor mode is enabled</li>
  <li>Renamed strsize to charsize ( ansi_strsize -&gt; ansi_charsize, utf8_strsize -&gt; utf8_charsize) to be less confusing</li>
  <li>Support for multiple ansi streams in ansi_utf8_strlen()</li>
  <li>Update default color theme to green for this release</li>
  <li>Update manpages &amp; documentation</li>
  <li>Reorganized contrib directory
    <ul>
      <li>Moved ci/cd related file from contrib/* to contrib/cicd</li>
      <li>Moved debian dir to contrib/dist</li>
      <li>Moved support script to contrib/scripts</li>
    </ul>
  </li>
</ul>

<!--more-->

<h4 id="lookat-210-is-available-at">Lookat 2.1.0 is available at:</h4>

<ul>
  <li><a href="https://www.wagemakers.be/english/programs/lookat/">https://www.wagemakers.be/english/programs/lookat/</a></li>
  <li>Download it directly from <a href="https://download-mirror.savannah.gnu.org/releases/lookat/">https://download-mirror.savannah.gnu.org/releases/lookat/</a></li>
  <li>Or at the Git repository at GNU savannah <a href="https://cgit.git.savannah.gnu.org/cgit/lookat.git/">https://git.savannah.gnu.org/cgit/lookat.git/</a></li>
</ul>

<p><strong><em>Have fun!</em></strong></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Lookat 2.1.0rc2 released]]></title>
    <link href="https://stafwag.github.io/blog/blog/2025/08/03/lookat-2-dot-1-0rc2-released/"/>
    <updated>2025-08-03T09:48:50+00:00</updated>
    <id>https://stafwag.github.io/blog/blog/2025/08/03/lookat-2-dot-1-0rc2-released</id>
    <content type="html"><![CDATA[<p><a href="https://stafwag.github.io/blog/images/lookat/lookat_2_1_0rc2.png"><img src="https://stafwag.github.io/blog/images/lookat/lookat_2_1_0rc2.png" class="right" width="600" height="320" alt="lookat 2.1.0rc1" /> </a></p>

<p>Lookat 2.1.0rc2 is the second release candicate of release of Lookat/Bekijk 2.1.0, a user-friendly Unix file browser/viewer that supports colored man pages.</p>

<p>The focus of the 2.1.0 release is to add ANSI Color support.</p>

<p><br /> <br /></p>

<h2 id="news">News</h2>

<h3 id="3-aug-2025-lookat-210rc2-released"><strong>3 Aug 2025</strong> Lookat 2.1.0rc2 Released</h3>

<p>Lookat 2.1.0rc2 is the second release candicate of Lookat 2.1.0</p>

<h4 id="changelog">ChangeLog</h4>

<h5 id="lookat--bekijk-210rc2">Lookat / Bekijk 2.1.0rc2</h5>

<ul>
  <li>Corrected italic color</li>
  <li>Don’t reset the search offset when cursor mode is enabled</li>
  <li>Renamed strsize to charsize ( ansi_strsize -&gt; ansi_charsize, utf8_strsize -&gt; utf8_charsize) to be less confusing</li>
  <li>Support for multiple ansi streams in ansi_utf8_strlen()</li>
  <li>Update default color theme to green for this release</li>
  <li>Update manpages &amp; documentation</li>
  <li>Reorganized contrib directory
    <ul>
      <li>Moved ci/cd related file from contrib/* to contrib/cicd</li>
      <li>Moved debian dir to contrib/dist</li>
      <li>Moved support script to contrib/scripts</li>
    </ul>
  </li>
</ul>

<!--more-->

<h4 id="lookat-210rc2-is-available-at">Lookat 2.1.0rc2 is available at:</h4>

<ul>
  <li><a href="https://www.wagemakers.be/english/programs/lookat/">https://www.wagemakers.be/english/programs/lookat/</a></li>
  <li>Download it directly from <a href="https://download-mirror.savannah.gnu.org/releases/lookat/">https://download-mirror.savannah.gnu.org/releases/lookat/</a></li>
  <li>Or at the Git repository at GNU savannah <a href="https://cgit.git.savannah.gnu.org/cgit/lookat.git/">https://git.savannah.gnu.org/cgit/lookat.git/</a></li>
</ul>

<p><strong><em>Have fun!</em></strong></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Using OpenTofu/Terraform to create a disposable Tails virtual machine]]></title>
    <link href="https://stafwag.github.io/blog/blog/2025/06/22/using-opentofu-to-create-tails-environment/"/>
    <updated>2025-06-22T06:37:00+00:00</updated>
    <id>https://stafwag.github.io/blog/blog/2025/06/22/using-opentofu-to-create-tails-environment</id>
    <content type="html"><![CDATA[<p><a href="https://stafwag.github.io/blog/images/opentofu/opentofu_square.png"><img src="https://stafwag.github.io/blog/images/opentofu/opentofu_square.png" class="left" width="264" height="191" alt="OpenTofu" /> </a></p>

<h2 id="opentofu">OpenTofu</h2>

<p><a href="https://developer.hashicorp.com/terraform">Terraform</a> or <a href="https://opentofu.org/">OpenTofu</a> (the open-source fork <a href="https://www.linuxfoundation.org/press/announcing-opentofu">supported by the Linux Foundation</a>) is a nice tool to setup the infrastructure
on different cloud environments. There is also a provider that supports <a href="https://libvirt.org/">libvirt</a>.</p>

<ul>
  <li><a href="https://github.com/dmacvicar/terraform-provider-libvirt">https://github.com/dmacvicar/terraform-provider-libvirt</a></li>
</ul>

<p>If you want to get started with OpenTofu there is a free training available from the Linux foundation:</p>

<ul>
  <li><a href="https://training.linuxfoundation.org/express-learning/getting-started-with-opentofu-lfel1009/">https://training.linuxfoundation.org/express-learning/getting-started-with-opentofu-lfel1009/</a></li>
</ul>

<p>I also joined the talk about OpenTofu and <a href="https://en.wikipedia.org/wiki/Infrastructure_as_code">Infrastructure As Code</a>, in general, this year in the <a href="https://fosdem.org/2025/schedule/track/virtualization/">Virtualization and Cloud Infrastructure</a> DEV Room at <a href="https://fosdem.org">FOSDEM</a> this year:</p>

<ul>
  <li><a href="https://fosdem.org/2025/schedule/event/fosdem-2025-6057-the-iac-tooling-multiverse-and-the-future-of-iac/">https://fosdem.org/2025/schedule/event/fosdem-2025-6057-the-iac-tooling-multiverse-and-the-future-of-iac/</a></li>
</ul>

<!--more-->

<p>I’ll not start to explain “Declarative” vs “Imperative” in this blog post, there’re already enough blog posts or websites that’re (trying) to explain this in more detail (the links above are a good start).</p>

<p>The default behaviour of OpenTofu is not to try to update an existing environment. This makes it usable to create disposable environments.</p>

<p><a href="https://stafwag.github.io/blog/images/tails/tails_description.png"><img src="https://stafwag.github.io/blog/images/tails/tails_description.png" class="right" width="320" height="135" alt="Tails description" /> </a></p>

<h2 id="tails">Tails</h2>

<p><a href="https://tails.net/">Tails</a> is a nice GNU/Linux distribution to connect to the <a href="https://www.torproject.org/">Tor network</a>.</p>

<p>Personally, I’m less into the “privacy” aspect of the Tor network (although being aware that you’re tracked and followed is important), probably because I’m lucky to live in the “Free world”.</p>

<p>For people who are less lucky (People who live in a country where freedom of speech isn’t valued) or journalists for example, there’re good reasons to use the Tor network and hide their internet traffic.</p>

<h2 id="tailslibvirt-terraformopentofu-module">tails/libvirt Terraform/OpenTofu module</h2>

<p><a href="https://stafwag.github.io/blog/images/tails/terraform-libvirt-tails.png"><img src="https://stafwag.github.io/blog/images/tails/terraform-libvirt-tails.png" class="right" width="484" height="142" alt="OpenTofu" /> </a></p>

<p>To make it easier to spin up a virtual machine with the latest tail environment I created a Terraform/OpenTofu module to spin up a virtual machine with the latest Tails version on
libvirt.</p>

<p>There’re security considerations when you run tails in a virtual machine.
See</p>

<ul>
  <li><a href="https://tails.net/doc/advanced_topics/virtualization/index.en.html">https://tails.net/doc/advanced_topics/virtualization/index.en.html</a></li>
</ul>

<p>for more information.</p>

<p>The source code of the module is available at the git repository:</p>

<ul>
  <li><a href="https://github.com/stafwag/terraform-libvirt-tails">https://github.com/stafwag/terraform-libvirt-tails</a></li>
</ul>

<p>The module is published on the <a href="https://registry.terraform.io/">Terraform Registry</a> and
the <a href="https://opentofu.org/registry/">OpenTofu Registry</a>.</p>

<p><strong><em>Have fun!</em></strong></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Lookat 2.1.0rc1 released]]></title>
    <link href="https://stafwag.github.io/blog/blog/2025/06/08/lookat-2-dot-1-0rc1-released/"/>
    <updated>2025-06-08T09:48:50+00:00</updated>
    <id>https://stafwag.github.io/blog/blog/2025/06/08/lookat-2-dot-1-0rc1-released</id>
    <content type="html"><![CDATA[<p><a href="https://stafwag.github.io/blog/images/lookat/lookat_2_1_0rc1.png"><img src="https://stafwag.github.io/blog/images/lookat/lookat_2_1_0rc1.png" class="left" width="600" height="300" alt="lookat 2.1.0rc1" /> </a></p>

<p>Lookat 2.1.0rc1 is the latest development release of Lookat/Bekijk, a user-friendly Unix file browser/viewer that supports colored man pages.</p>

<p>The focus of the 2.1.0 release is to add ANSI Color support.</p>

<p><br /> <br /></p>

<h2 id="news">News</h2>

<h3 id="8-jun-2025-lookat-210rc1-released"><strong>8 Jun 2025</strong> Lookat 2.1.0rc1 Released</h3>

<p>Lookat 2.1.0rc1 is the first release candicate of Lookat 2.1.0</p>

<h4 id="changelog">ChangeLog</h4>

<h5 id="lookat--bekijk-210rc1">Lookat / Bekijk 2.1.0rc1</h5>
<ul>
  <li>ANSI Color support</li>
</ul>

<!--more-->

<h4 id="lookat-210rc1-is-available-at">Lookat 2.1.0rc1 is available at:</h4>

<ul>
  <li><a href="https://www.wagemakers.be/english/programs/lookat/">https://www.wagemakers.be/english/programs/lookat/</a></li>
  <li>Download it directly from <a href="https://download-mirror.savannah.gnu.org/releases/lookat/">https://download-mirror.savannah.gnu.org/releases/lookat/</a></li>
  <li>Or at the Git repository at GNU savannah <a href="https://cgit.git.savannah.gnu.org/cgit/lookat.git/">https://git.savannah.gnu.org/cgit/lookat.git/</a></li>
</ul>

<p><strong><em>Have fun!</em></strong></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[#eXit : Goodbye twitter. Hi Mastodon...]]></title>
    <link href="https://stafwag.github.io/blog/blog/2025/05/11/leaving_twitter/"/>
    <updated>2025-05-11T09:29:07+00:00</updated>
    <id>https://stafwag.github.io/blog/blog/2025/05/11/leaving_twitter</id>
    <content type="html"><![CDATA[<p><a href="https://stafwag.github.io/blog/images/mastodon/welcome.jpg"><img src="https://stafwag.github.io/blog/images/mastodon/welcome.jpg" class="left" width="400" height="300" alt="Plushtodon" /> </a></p>

<p>I decided to leave <a href="https://www.twitter">twitter</a>.
<br /> <br />
Yes, this has something to do with the change of ownership, the name change to x, …
<br /> <br />
There is only 1 X to me, and that’s <a href="https://www.x.org/">X.org</a></p>

<p>Twitter has become a platform that doesn’t value #freedomofspeech anymore.</p>

<p>My account even got flagged as possible spam to “factchecking” #fakenews</p>

<p>The mean reason is that there is a better alternative in the form of the
<a href="https://en.wikipedia.org/wiki/Fediverse">Fediverse</a> #Fediverse is the protocol that 
<a href="https://mastodon.social/">Mastodon</a> uses.</p>

<p>It allows for a truly decentralised social media platform.</p>

<p>It allows organizations to set up their own Mastodon instance and take ownership and accountability for their content and accounts.</p>

<p>Mastodon is a nice platform; you probably feel at home there.</p>

<p>People who follow me on twitter can continue to follow me at Mastodon if they want.</p>

<p><a href="https://mastodon.social/@stafwag">https://mastodon.social/@stafwag</a></p>

<p>I’ll post this message a couple of times to twitter before I close my twitter account, so people can decide if they want to follow me on
Mastodon …or not ;-).</p>

<p><strong><em>Have fun!</em></strong></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[docker-stafwag-unbound v2.1.0 released: Use unbound as an DNS-over-TLS resolver and authoritative DNS server]]></title>
    <link href="https://stafwag.github.io/blog/blog/2025/05/04/use-unbound-as-dns-over-tls-and-authoritative-dns-server_v2.1.0/"/>
    <updated>2025-05-04T15:01:01+00:00</updated>
    <id>https://stafwag.github.io/blog/blog/2025/05/04/use-unbound-as-dns-over-tls-and-authoritative-dns-server_v2.1.0</id>
    <content type="html"><![CDATA[<p><a href="https://stafwag.github.io/blog/images/unbound/Unbound_FC_Shaded_cropped.svg"><img src="https://stafwag.github.io/blog/images/unbound/Unbound_FC_Shaded_cropped.svg" class="left" width="400" height="91" alt="Unbound" /> </a></p>

<p><a href="https://www.nlnetlabs.nl/projects/unbound/about/">Unbound</a> is a popular DNS resolver, that has native DNS-over-TLS support.
<br /> <br /></p>

<p>Unbound and <a href="https://dnsprivacy.org/dns_privacy_daemon_-_stubby/">Stubby</a> were among the first resolvers to implement DNS-over-TLS.</p>

<p>I wrote a few blog posts on how to use Stubby on GNU/Linux and FreeBSD.</p>

<ul>
  <li><a href="https://stafwag.github.io/blog/blog/2018/09/09/dns-privacy-with-stubby-part1-gnulinux/">https://stafwag.github.io/blog/blog/2018/09/09/dns-privacy-with-stubby-part1-gnulinux/</a></li>
  <li><a href="https://stafwag.github.io/blog/blog/2018/10/07/dns-privacy-with-stubby-part-2-freebsd/">https://stafwag.github.io/blog/blog/2018/10/07/dns-privacy-with-stubby-part-2-freebsd/</a></li>
</ul>

<p>The implementation status of DNS-over-TLS and other DNS privacy options is available at: <a href="https://dnsprivacy.org/">https://dnsprivacy.org/</a>.</p>

<p>See <a href="https://dnsprivacy.org/implementation_status/">https://dnsprivacy.org/implementation_status/</a> for more details.</p>

<p>It’s less known that it can also be used as authoritative DNS server (aka a real DNS server).
Since I discovered this feature and Unbound got native DNS-over-TLS support I started to it as my DNS server.</p>

<p>I created a docker container for it a couple of years back to use it as an authoritative DNS server.</p>

<p>I recently updated the container, the latest version (2.1.0) is available at: <a href="https://github.com/stafwag/docker-stafwag-unbound">https://github.com/stafwag/docker-stafwag-unbound</a></p>

<h1 id="changelog">ChangeLog</h1>
<h2 id="version-210">Version 2.1.0</h2>
<h3 id="upgrade-to-debianbookworm">Upgrade to debian:bookworm</h3>

<ul>
  <li>Updated BASE_IMAGE to debian:bookworm</li>
  <li>Add ARG DEBIAN_FRONTEND=noninteractive</li>
  <li>Run unbound-control-setup to generate the default certificate</li>
  <li>Documentation updated</li>
</ul>

<!--more-->

<h2><br /> <br /></h2>

<h1 id="docker-stafwag-unbound">docker-stafwag-unbound</h1>

<p><code class="language-plaintext highlighter-rouge">Dockerfile</code> to run unbound inside a docker container.
The unbound daemon will run as the unbound user. The uid/gid is mapped to
5000153.</p>

<h2 id="installation">Installation</h2>

<h3 id="clone-the-git-repo">clone the git repo</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ git clone https://github.com/stafwag/docker-stafwag-unbound.git
$ cd docker-stafwag-unbound
</code></pre></div></div>

<h3 id="configuration">Configuration</h3>

<h4 id="port">Port</h4>

<p>The default DNS port is set to <code class="language-plaintext highlighter-rouge">5353</code> this port is mapped with the docker command to the default port 53 (see below).
If you want to use another port, you can edit <code class="language-plaintext highlighter-rouge">etc/unbound/unbound.conf.d/interface.conf</code>.</p>

<h4 id="scriptscreate_zone_configsh-helper-script"><code class="language-plaintext highlighter-rouge">scripts/create_zone_config.sh</code> helper script</h4>

<p>The <code class="language-plaintext highlighter-rouge">create_zone_config.sh</code> helper script, can help you to create the <code class="language-plaintext highlighter-rouge">zones.conf</code> configuration file.
It’s executed during the container build and creates the zones.conf from the datafiles in <code class="language-plaintext highlighter-rouge">etc/unbound/zones</code>.</p>

<p>If you want to use a docker volume or configmaps/persistent volumes on Kubernetes. You can use this script to
generate the <code class="language-plaintext highlighter-rouge">zones.conf</code> a zones data directory.</p>

<p><code class="language-plaintext highlighter-rouge">create_zone_config.sh</code> has following arguments:</p>

<ul>
  <li><strong>-f</strong> Default: /etc/unbound/unbound.conf.d/zones.conf
The zones.conf file to create</li>
  <li><strong>-d</strong> Default: /etc/unbound/zones/
The zones data source files</li>
  <li><strong>-p</strong> Default: the realpath of zone files</li>
  <li><strong>-s</strong> Skip chown/chmod</li>
</ul>

<h4 id="use-unbound-as-an-authoritative-dns-server">Use unbound as an authoritative DNS server</h4>

<p>To use unbound as an authoritative authoritive DNS server - a DNS server that hosts DNS zones - add your zones file <code class="language-plaintext highlighter-rouge">etc/unbound/zones/</code>.</p>

<p>During the creation of the image <code class="language-plaintext highlighter-rouge">scripts/create_zone_config.sh</code> is executed to create the zones configuration file.</p>

<p>Alternatively, you can also use a docker volume to mount <code class="language-plaintext highlighter-rouge">/etc/unbound/zones/</code> to your zone files. And a volume mount for the <code class="language-plaintext highlighter-rouge">zones.conf</code>
configuration file.</p>

<p>You can use subdirectories. The zone file needs to have <code class="language-plaintext highlighter-rouge">$ORIGIN</code> set to our zone origin.</p>

<h4 id="use-dns-over-tls">Use DNS-over-TLS</h4>

<p>The default configuration uses <a href="https://www.quad9.net/">quad9</a> to forward the DNS queries over TLS. 
If you want to use another vendor or you want to use the root DNS servers director you can remove this file.</p>

<h3 id="build-the-image">Build the image</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ docker build -t stafwag/unbound . 
</code></pre></div></div>

<p>To use a different BASE_IMAGE, you can use the –build-arg BASE_IMAGE=your_base_image.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ docker build --build-arg BASE_IMAGE=stafwag/debian:bookworm -t stafwag/unbound .
</code></pre></div></div>

<h2 id="run">Run</h2>

<h3 id="recursive-dns-server-with-dns-over-tls">Recursive DNS server with DNS-over-TLS</h3>

<p>Run</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ docker run -d --rm --name myunbound -p 127.0.0.1:53:5353 -p 127.0.0.1:53:5353/udp stafwag/unbound
</code></pre></div></div>

<p>Test</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ dig @127.0.0.1 www.wagemakers.be
</code></pre></div></div>

<h3 id="authoritative-dns-server">Authoritative dns server.</h3>

<p>If you want to use unbound as an authoritative dns server you can use the steps below.</p>

<h4 id="create-a-directory-with-your-zone-files">Create a directory with your zone files:</h4>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@vicky ~]$ mkdir -p ~/docker/volumes/unbound/zones/stafnet
[staf@vicky ~]$ 
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@vicky stafnet]$ cd ~/docker/volumes/unbound/zones/stafnet
[staf@vicky ~]$ 
</code></pre></div></div>

<h4 id="create-the-zone-files">Create the zone files</h4>

<h5 id="zone-files">Zone files</h5>

<p>stafnet.zone:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$TTL  86400 ; 24 hours
$ORIGIN stafnet.local.
@  1D  IN  SOA @  root (
            20200322001 ; serial
            3H ; refresh
            15 ; retry
            1w ; expire
            3h ; minimum
           )
@  1D  IN  NS @ 

stafmail IN A 10.10.10.10
</code></pre></div></div>

<p>stafnet-rev.zone:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$TTL    86400 ;
$ORIGIN 10.10.10.IN-ADDR.ARPA.
@       IN      SOA     stafnet.local. root.localhost.  (
                        20200322001; Serial
                        3h      ; Refresh
                        15      ; Retry
                        1w      ; Expire
                        3h )    ; Minimum
        IN      NS      localhost.
10      IN      PTR     stafmail.
</code></pre></div></div>

<p>Make sure that the volume directoy and zone files have the correct permissions.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo chmod 750 ~/docker/volumes/unbound/zones/stafnet/
$ sudo chmod 640 ~/docker/volumes/unbound/zones/stafnet/*
$ sudo chown -R root:5000153 ~/docker/volumes/unbound/
</code></pre></div></div>

<p>Create the zones.conf configuration file.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@vicky stafnet]$ cd ~/github/stafwag/docker-stafwag-unbound/
[staf@vicky docker-stafwag-unbound]$ 
</code></pre></div></div>

<p>The script will execute a <code class="language-plaintext highlighter-rouge">chown</code> and <code class="language-plaintext highlighter-rouge">chmod</code> on the generated <code class="language-plaintext highlighter-rouge">zones.conf</code> file and is excute with sudo for this reason.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@vicky docker-stafwag-unbound]$ sudo scripts/create_zone_config.sh -f ~/docker/volumes/unbound/zones.conf -d ~/docker/volumes/unbound/zones/stafnet -p /etc/unbound/zones
Processing: /home/staf/docker/volumes/unbound/zones/stafnet/stafnet.zone
origin=stafnet.local
Processing: /home/staf/docker/volumes/unbound/zones/stafnet/stafnet-rev.zone
origin=1.168.192.IN-ADDR.ARPA
[staf@vicky docker-stafwag-unbound]$ 
</code></pre></div></div>

<p>Verify the generated <code class="language-plaintext highlighter-rouge">zones.conf</code></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@vicky docker-stafwag-unbound]$ sudo cat ~/docker/volumes/unbound/zones.conf
auth-zone:
  name: stafnet.local
  zonefile: /etc/unbound/zones/stafnet.zone

auth-zone:
  name: 1.168.192.IN-ADDR.ARPA
  zonefile: /etc/unbound/zones/stafnet-rev.zone

[staf@vicky docker-stafwag-unbound]$ 
</code></pre></div></div>

<h4 id="run-the-container">run the container</h4>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ docker run --rm --name myunbound -v ~/docker/volumes/unbound/zones/stafnet:/etc//unbound/zones/ -v ~/docker/volumes/unbound/zones.conf:/etc/unbound/unbound.conf.d/zones.conf -p 127.0.0.1:53:5353 -p 127.0.0.1:53:5353/udp stafwag/unbound
</code></pre></div></div>

<h4 id="test">Test</h4>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@vicky ~]$ dig @127.0.0.1 soa stafnet.local

; &lt;&lt;&gt;&gt; DiG 9.16.1 &lt;&lt;&gt;&gt; @127.0.0.1 soa stafnet.local
; (1 server found)
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; -&gt;&gt;HEADER&lt;&lt;- opcode: QUERY, status: NOERROR, id: 37184
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;stafnet.local.     IN  SOA

;; ANSWER SECTION:
stafnet.local.    86400 IN  SOA stafnet.local. root.stafnet.local. 3020452817 10800 15 604800 10800

;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Sun Mar 22 19:41:09 CET 2020
;; MSG SIZE  rcvd: 83

[staf@vicky ~]$ 
</code></pre></div></div>

<p>Test reverse lookup.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@vicky ~]$ dig -x 10.10.10.10 @127.0.0.1

; &lt;&lt;&gt;&gt; DiG 9.16.21 &lt;&lt;&gt;&gt; -x 10.10.10.10 @127.0.0.1
;; global options: +cmd
;; Got answer:
;; -&gt;&gt;HEADER&lt;&lt;- opcode: QUERY, status: NOERROR, id: 36250
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;10.10.10.10.in-addr.arpa.	IN	PTR

;; ANSWER SECTION:
10.10.10.10.in-addr.arpa. 86400	IN	PTR	stafmail.

;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Tue Oct 19 19:51:47 CEST 2021
;; MSG SIZE  rcvd: 75

[staf@vicky ~]$ 
</code></pre></div></div>

<p><strong><em>Have fun!</em></strong></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[docker-stafwag-hello_nginx v1.0.0 released]]></title>
    <link href="https://stafwag.github.io/blog/blog/2025/04/27/docker-stafwag-hello_nginx_v1.0.0/"/>
    <updated>2025-04-27T07:08:00+00:00</updated>
    <id>https://stafwag.github.io/blog/blog/2025/04/27/docker-stafwag-hello_nginx_v1.0.0</id>
    <content type="html"><![CDATA[<p><a href="https://stafwag.github.io/blog/images/openshift/OpenShift-LogoType.svg"><img src="https://stafwag.github.io/blog/images/openshift/OpenShift-LogoType.svg" class="right" width="400" height="427" alt="2025" /> </a></p>

<p>While the code ( if you call <a href="https://en.wikipedia.org/wiki/YAML">YAML</a> “code” ) is already more than 5 years old.
I finally took the take the make a proper release of my test “hello” <a href="https://opencontainers.org">OCI</a> container.</p>

<p>I use this container to demo a container build and how to deploy it with helm on a Kubernetes cluster. Some test tools (ping, DNS, curl, wget) are included to execute some tests on the deployed pod.</p>

<p>It also includes a <a href="https://en.wikipedia.org/wiki/Make_(software)#Makefile">Makefile</a> to build the container and deploy it on a
<a href="https://developers.redhat.com/products/openshift-local/overview]">Red Hat OpenShift Local (formerly Red Hat CodeReady Containers)</a> cluster.</p>

<p>To deploy the container with the included helm charts to OpenShift local (Code Ready Containers), execute make <code class="language-plaintext highlighter-rouge">crc_deploy</code>.</p>

<p>This will:</p>

<ol>
  <li>Build the container image</li>
  <li>Login to the internal OpenShift registry</li>
  <li>Push the image to the internal OpenShift register</li>
  <li>Deploy the helm chart in the tsthelm namespace, the helm chart will also create a route for the application.</li>
</ol>

<p>I might include support for other <a href="https://en.wikipedia.org/wiki/Kubernetes">Kubernetes</a> in the future when I find the time.</p>

<!--more-->

<p>docker-stafwag-hello_nginx v1.0.0 is available at:</p>

<p><a href="https://github.com/stafwag/docker-stafwag-hello_nginx">https://github.com/stafwag/docker-stafwag-hello_nginx</a></p>

<h1 id="changelog">ChangeLog</h1>

<h2 id="v100-initial-stable-release">v1.0.0 Initial stable release</h2>

<ul>
  <li>Included dns utilities and documentation update by @stafwag in #3</li>
  <li>Updated Run section by @stafwag in #4</li>
</ul>

<p><strong><em>Have fun!</em></strong></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Ansible k3s on vms 1.2.0  and delegated_vm_install 2.0.3 released]]></title>
    <link href="https://stafwag.github.io/blog/blog/2025/04/06/ansible-k3s-on-vms_and_delegated_vm_install_released/"/>
    <updated>2025-04-06T17:08:00+00:00</updated>
    <id>https://stafwag.github.io/blog/blog/2025/04/06/ansible-k3s-on-vms_and_delegated_vm_install_released</id>
    <content type="html"><![CDATA[<p><a href="https://stafwag.github.io/blog/images/cloud-init/cloud-init-primary.svg"><img src="https://stafwag.github.io/blog/images/cloud-init/cloud-init-primary.svg" class="right" width="600" height="121" alt="cloud-init" /> </a></p>

<p>I prepared a few update releases of some ansible roles related to provision virtual machines with <a href="https://libvirt.org/">libvirt</a> over the last weeks.</p>

<p>Mainly clean up releases and makes sure that everything works on 
different GNU/Linux distributions out of the box.</p>

<p>One “big” change is the removal of the dependency on the <code class="language-plaintext highlighter-rouge">cloud-localds</code>
utility to provision virtual machines with <a href="https://cloud-init.io/">cloud-init</a>. This enables the usage of the roles on Linux distributions that don’t provide this utility.</p>

<hr />
<h1 id="ansible-k3s-on-vms-v120">Ansible-k3s-on-vms v1.2.0</h1>

<p><em>An Ansible playbook to deploy virtual machines and deploy K3s.</em></p>

<p><a href="https://github.com/stafwag/ansible-k3s-on-vms">https://github.com/stafwag/ansible-k3s-on-vms</a></p>

<!--more-->

<h2 id="changelog">ChangeLog</h2>

<h3 id="added-communitylibvirt-to-requirementsyml">Added community.libvirt to requirements.yml</h3>

<ul>
  <li>Added community.libvirt to requirements.yml</li>
  <li>Added required Suse packages installation</li>
  <li>Documentation update</li>
  <li>This release removes the dependency on the cloud-locals utility. On the distributes that don’t provide the cloud-localds utility GNU xorriso is used.</li>
</ul>

<hr />
<h1 id="stafwagdelegated_vm_install-v203">stafwag.delegated_vm_install v2.0.3</h1>

<p><em>An Ansible role to install a virtual machine with <code class="language-plaintext highlighter-rouge">virt-install</code> and <code class="language-plaintext highlighter-rouge">cloud-init</code> (Delegated).</em></p>

<p><a href="https://github.com/stafwag/ansible-role-delegated_vm_install">https://github.com/stafwag/ansible-role-delegated_vm_install</a></p>

<h2 id="changelog-1">ChangeLog</h2>

<h3 id="gather-facts-on-kvm-hosts-only-once">Gather facts on kvm hosts only once</h3>

<ul>
  <li>Gather facts on kvm hosts only once</li>
  <li>Corrected ansible-lint errors</li>
  <li>Remove the cloud-localds requirement in README</li>
</ul>

<hr />
<h1 id="stafwagvirt_install_vm-v111">stafwag.virt_install_vm v1.1.1</h1>

<p><em>An Ansible role to install a libvirt virtual machine with virt-install and cloud-init. It “designed” to be flexible.</em></p>

<p><a href="https://github.com/stafwag/ansible-role-virt_install_vm">https://github.com/stafwag/ansible-role-virt_install_vm</a></p>

<h2 id="changelog-2">ChangeLog</h2>

<h3 id="cleanup-release">CleanUp Release</h3>

<ul>
  <li>Corrected ansible-lint errors</li>
  <li>Updated documentation</li>
  <li>Avoid ansible error during check vm status check</li>
</ul>

<hr />
<h1 id="stafwaglibvirt-v200">stafwag.libvirt v2.0.0</h1>

<p><em>An ansible role to install libvirt/KVM packages and enable the libvirtd service.</em></p>

<p><a href="https://github.com/stafwag/ansible-role-libvirt">https://github.com/stafwag/ansible-role-libvirt</a></p>

<h2 id="changelog-3">ChangeLog</h2>

<h3 id="use-general-vars-instead-of-tasks">Use general vars instead of tasks</h3>

<ul>
  <li>Reorganized the role to use vars and package install install the packages</li>
  <li>This version works from the Ansible version that is included in Ubuntu 24.x</li>
  <li>Corrected ansible-lint errors</li>
</ul>

<hr />
<h1 id="stafwagcloud_localds-v302">stafwag.cloud_localds v3.0.2</h1>

<p><em>An ansible role to create cloud-init config disk images.</em></p>

<p><a href="https://github.com/stafwag/ansible-role-cloud_localds">https://github.com/stafwag/ansible-role-cloud_localds</a></p>

<h2 id="changelog-4">ChangeLog</h2>

<h3 id="execute-installation-tasks-only-once">Execute installation tasks only once</h3>

<ul>
  <li>Added run_one: true to only execute the installation tasks only once.</li>
  <li>Move “name: Set OS related variables” to main, to have the provider settings when the install phase isn’t executed e.g. With –skip-tags install.</li>
  <li>Added apply tags install to support –tags install</li>
</ul>

<hr />
<h1 id="stafwagqemu_img-v232">stafwag.qemu_img v2.3.2</h1>

<p><em>An ansible role create qemu images.</em></p>

<p><a href="https://github.com/stafwag/ansible-role-qemu_img">https://github.com/stafwag/ansible-role-qemu_img</a></p>

<h2 id="changelog-5">ChangeLog</h2>

<h3 id="enable-run_once-on-installation-tasks">Enable run_once on installation tasks</h3>

<ul>
  <li>Execute installation tasks only once to allow parallel execution of roles on the same host e.g. With delegate_to</li>
</ul>

<p><strong><em>Have fun!</em></strong></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Best wishes 2025!]]></title>
    <link href="https://stafwag.github.io/blog/blog/2025/01/02/best_wishes_2025/"/>
    <updated>2025-01-02T15:08:00+00:00</updated>
    <id>https://stafwag.github.io/blog/blog/2025/01/02/best_wishes_2025</id>
    <content type="html"><![CDATA[<p><a href="https://stafwag.github.io/blog/images/2025/2025.jpg"><img src="https://stafwag.github.io/blog/images/2025/2025s.jpg" class="left" width="1000" height="505" alt="2025" /> </a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Use a GPG smartcard with Thunderbird. Part 3: Setup Thunderbird]]></title>
    <link href="https://stafwag.github.io/blog/blog/2024/09/10/use-a-gpg-smartcard-with-thunderbird-part_3-setup-thunderbird/"/>
    <updated>2024-09-10T15:05:00+00:00</updated>
    <id>https://stafwag.github.io/blog/blog/2024/09/10/use-a-gpg-smartcard-with-thunderbird-part_3-setup-thunderbird</id>
    <content type="html"><![CDATA[<p>In previous blog posts, we discussed setting up a GPG smartcard on <a href="https://www.gnu.org">GNU</a>/<a href="https://www.kernel.org">Linux</a> and <a href="https://www.freebsd.org">FreeBSD</a>.</p>

<p>In this blog post, we will configure <a href="https://www.thunderbird.net">Thunderbird</a> to work with an external smartcard reader and our <a href="https://gnupg.org/">GPG</a>-compatible smartcard.</p>

<p><a href="https://stafwag.github.io/blog/images/gpg/thunderbird/beastie_gnu_tux.jpg"><img src="https://stafwag.github.io/blog/images/gpg/thunderbird/beastie_gnu_tux_s.jpg" class="left" width="400" height="267" alt="beastie gnu tux" /> </a></p>

<p>Before Thunderbird 78, if you wanted to use OpenPGP email encryption, you had to use a third-party add-on such as <a href="Enigmail">https://enigmail.net/</a>.</p>

<p>Thunderbird’s recent versions natively support OpenPGP.  The Enigmail addon for Thunderbird has been discontinued.
See: <a href="https://enigmail.net/index.php/en/home/news">https://enigmail.net/index.php/en/home/news</a>.</p>

<p>I didn’t find good documentation on how to set up Thunderbird with a GnuPG smartcard when I moved to a new <a href="https://www.coreboot.org/">coreboot</a> laptop, so this was the reason I created this blog post series.</p>

<!--more-->

<h1 id="gnupg-configuration">GnuPG configuration</h1>

<p>We’ll not go into too much detail on how to set up GnuPG. This was already explained in the previous blog posts.</p>

<ul>
  <li><a href="https://stafwag.github.io/blog/blog/2024/04/21/use-a-gpg-smartcard-with-thunderbird-part_1-setup-gpg/">Use a GPG smartcard with Thunderbird. Part 1: setup GnuPG</a></li>
  <li><a href="https://stafwag.github.io/blog/blog/2024/07/28/use-a-gpg-smartcard-with-thunderbird-part_2-setup-gpg-on-freebsd/">Use a GPG smart card with Thunderbird. Part 2: setup GnuPG on FreeBSD</a></li>
</ul>

<p>If you want to use a <a href="https://en.wikipedia.org/wiki/Hardware_security_module">HSM</a> with GnuPG you can use the <code class="language-plaintext highlighter-rouge">gnupg-pkcs11-scd</code> agent <a href="https://github.com/alonbl/gnupg-pkcs11-scd">https://github.com/alonbl/gnupg-pkcs11-scd</a> that translates the <code class="language-plaintext highlighter-rouge">pkcs11</code> interface to GnuPG. A previous blog post describes how this can be configured with <a href="https://www.smartcard-hsm.com/">SmartCard-HSM</a>.</p>

<ul>
  <li><a href="https://stafwag.github.io/blog/blog/2020/05/02/using-smartcardhsm-with-gpg/">https://stafwag.github.io/blog/blog/2020/05/02/using-smartcardhsm-with-gpg/</a></li>
</ul>

<p>We’ll go over some steps to make sure that the GnuPG is set up correctly before we continue with the Thunderbird configuration. The <code class="language-plaintext highlighter-rouge">pinentry</code> command must be
 configured with graphical support to type our pin code in the Graphical user environment.</p>

<h2 id="import-public-key">Import Public Key</h2>

<p>Make sure that your public key - or the public key of the reciever(s) - is/are imported.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@snuffel ~]$ gpg --list-keys
[staf@snuffel ~]$ 
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@snuffel ~]$ gpg --import &lt;snip&gt;.asc
gpg: key XXXXXXXXXXXXXXXX: public key "XXXX XXXXXXXXXX &lt;XXX@XXXXXX&gt;" imported
gpg: Total number processed: 1
gpg:               imported: 1
[staf@snuffel ~]$ 
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@snuffel ~]$  gpg --list-keys
/home/staf/.gnupg/pubring.kbx
-----------------------------
pub   xxxxxxx YYYYY-MM-DD [SC]
      XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
uid           [ xxxxxxx] xxxx xxxxxxxxxx &lt;xxxx@xxxxxxxxxx.xx&gt;
sub   xxxxxxx xxxx-xx-xx [A]
sub   xxxxxxx xxxx-xx-xx [E]

[staf@snuffel ~]$ 
</code></pre></div></div>

<h2 id="pinentry">Pinentry</h2>

<p>Thunderbird will not ask for your smartcard’s pin code.</p>

<p>This must be done on your smartcard reader if it has a pin pad or an external <code class="language-plaintext highlighter-rouge">pinentry</code> program.</p>

<p>The <code class="language-plaintext highlighter-rouge">pinentry</code> is configured in the <code class="language-plaintext highlighter-rouge">gpg-agent.conf</code> configuration file. As we’re using Thunderbird is a graphical environment we’ll configure it to use a graphical version.</p>

<h3 id="installation">Installation</h3>

<p>I’m testing KDE plasma 6 on FreeBSD, so I installed the Qt version of pinentry.</p>

<p>On GNU/Linux you can check the documentation of your favourite Linux distribution to install a graphical <code class="language-plaintext highlighter-rouge">pinentry</code>. If you use a Graphical user environment there is probably already a graphical-enabled <code class="language-plaintext highlighter-rouge">pinentry</code> installed.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@snuffel ~]$ sudo pkg install -y pinentry-qt6
Updating FreeBSD repository catalogue...
FreeBSD repository is up to date.
All repositories are up to date.
The following 1 package(s) will be affected (of 0 checked):

New packages to be INSTALLED:
        pinentry-qt6: 1.3.0

Number of packages to be installed: 1

76 KiB to be downloaded.
[1/1] Fetching pinentry-qt6-1.3.0.pkg: 100%   76 KiB  78.0kB/s    00:01    
Checking integrity... done (0 conflicting)
[1/1] Installing pinentry-qt6-1.3.0...
[1/1] Extracting pinentry-qt6-1.3.0: 100%
==&gt; Running trigger: desktop-file-utils.ucl
Building cache database of MIME types
[staf@snuffel ~]$ 
</code></pre></div></div>

<h3 id="configuration">Configuration</h3>

<p>The <code class="language-plaintext highlighter-rouge">gpg-agent</code> is responsible for starting the <code class="language-plaintext highlighter-rouge">pinentry</code> program. Let’s reconfigure it to start the <code class="language-plaintext highlighter-rouge">pinentry</code> that we like to use.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@snuffel ~]$ cd .gnupg/
[staf@snuffel ~/.gnupg]$ 
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@snuffel ~/.gnupg]$ vi gpg-agent.conf
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">pinentry</code> is configured in the  <code class="language-plaintext highlighter-rouge">pinentry-program</code> directive. You’ll find the complete <code class="language-plaintext highlighter-rouge">gpg-agent.conf</code> that I’m using below.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>debug-level expert
verbose
verbose
log-file /home/staf/logs/gpg-agent.log
pinentry-program /usr/local/bin/pinentry-qt
</code></pre></div></div>

<p>Reload the <code class="language-plaintext highlighter-rouge">sdaemon</code> and <code class="language-plaintext highlighter-rouge">gpg-agent</code> configuration.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>staf@freebsd-gpg3:~/.gnupg $ gpgconf --reload scdaemon
staf@freebsd-gpg3:~/.gnupg $ gpgconf --reload gpg-agent
staf@freebsd-gpg3:~/.gnupg $ 
</code></pre></div></div>

<h2 id="test">Test</h2>

<p>To verify that <code class="language-plaintext highlighter-rouge">gpg</code> works correctly and that the <code class="language-plaintext highlighter-rouge">pinentry</code> program works in our graphical environment we sign a file.</p>

<p>Create a new file.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ cd /tmp
[staf@snuffel /tmp]$ 
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@snuffel /tmp]$ echo "foobar" &gt; foobar
[staf@snuffel /tmp]$ 
</code></pre></div></div>

<p>Try to sign it.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@snuffel /tmp]$ gpg --sign foobar
[staf@snuffel /tmp]$ 
</code></pre></div></div>

<p>If everything works fine, the <code class="language-plaintext highlighter-rouge">pinentry</code> program will ask for the pincode to sign it.</p>

<p><img src="https://stafwag.github.io/blog/images/gpg/thunderbird/pin-entry_a.png" alt="image info" /></p>

<h1 id="thunderbird">Thunderbird</h1>

<p>In this section we’ll (finally) configure Thunderbird to use GPG with a smartcard reader.</p>

<h2 id="allow-external-smartcard-reader">Allow external smartcard reader</h2>

<div style="clear: both;">

<a href="https://stafwag.github.io/blog/images/gpg/thunderbird/tb0000.png"><img src="https://stafwag.github.io/blog/images/gpg/thunderbird/tb0000.png" class="right" width="100" height="157" alt="open settings" /> </a>

<p>
Open the global settings, click on the "Hamburger" icon and select <b>settings</b>.
</p>

<p>
Or press <b>[F10]</b> to bring-up the "Menu bar" in Thunderbird and select <b>[Edit]</b> and <b>Settings</b>.
</p>

</div>

<div style="clear: both;padding-top: 20px;">
<a href="https://stafwag.github.io/blog/images/gpg/thunderbird/tb0001.png"><img src="https://stafwag.github.io/blog/images/gpg/thunderbird/tb0001.png" class="left" width="300" height="225" alt="open settings" /> </a>

<p>

In the settings window click on <b>[Config Editor]</b>.

</p>

<p>This will open the <i>Advanced Preferences</i> window.</p>

</div>

<div style="clear: both;padding-top: 20px;">
<a href="https://stafwag.github.io/blog/images/gpg/thunderbird/tb0002.png"><img src="https://stafwag.github.io/blog/images/gpg/thunderbird/tb0002.png" class="left" width="300" height="225" alt="allow external gpg" /> </a>

<p>
In the <i>Advanced Preferences</i> window search for "external_gnupg" settings and set <b><i>mail.indenity.allow_external_gnupg</i></b> to <b><i>true</i></b>.
</p>
</div>

<div style="clear: both;">
<br />&nbsp;<br />
</div>

<h2 id="setup-end-to-end-encryption">Setup End-To-End Encryption</h2>

<p>The next step is to configure the GPG keypair that we’ll use for our user account.</p>

<div style="clear: both;padding-top: 20px;">

<a href="https://stafwag.github.io/blog/images/gpg/thunderbird/tb0003.png"><img src="https://stafwag.github.io/blog/images/gpg/thunderbird/tb0003.png" class="left" width="300" height="225" alt="open settings" /> </a>

<p>
Open the account setting by pressing on the "Hamburger" icon and select <b>Account Settings</b> or press <b>[F10]</b> to open the menu bar and select <b>Edit</b>, <b>Account Settings</b>.
</p>

<p>
Select <b>End-to-End Encryption</b> at <b>OpenPG</b> section select <b>[ Add Key ]</b>.
</p>

</div>

<div style="clear: both;padding-top: 20px;">
<a href="https://stafwag.github.io/blog/images/gpg/thunderbird/tb0004.png"><img src="https://stafwag.github.io/blog/images/gpg/thunderbird/tb0004.png" class="right" width="300" height="225" alt="open settings" /> </a>
<p>
Select the <b>( * ) Use your external key though GnuPG (e.g. from a smartcard)</b>
</p>
<p>
And click on <b>[Continue]</b>
</p>
<p>
The next window will ask you for the <i>Secret Key ID</i>.
</p>
</div>
<div style="clear: both;padding-top: 20px;">
<a href="https://stafwag.github.io/blog/images/gpg/thunderbird/tb0004b.png"><img src="https://stafwag.github.io/blog/images/gpg/thunderbird/tb0004b.png" class="right" width="300" height="225" alt="open settings" /> </a>

<p>
Execute <code>gpg --list-keys</code> to get your secret key id.
</p>
<p>
Copy/paste your key id and click on <b>[ Save key ID ]</b>.
</p>
</div>

<div style="clear: both;padding-top: 20px;">
<p>
I found that it is sometimes required to restart Thunderbird to reload the configuration when a new key id is added.
So restart Thunderbird or restart it fails to find your key id  in the keyring.
</p>
</div>

<h2 id="test-1">Test</h2>

<div style="clear: both;">

<a href="https://stafwag.github.io/blog/images/gpg/thunderbird/tb0005.png"><img src="https://stafwag.github.io/blog/images/gpg/thunderbird/tb0005.png" class="left" width="300" height="225" alt="open settings" /> </a>

<p>
As a test we send an email to our own email address.
</p>

<p>
Open a new message window and enter your email address into the <b>To:</b> field.
</p>
<p>
Click on <b>[OpenPGP]</b> and <b>Encrypt</b>.
</p>

</div>

<div style="clear: both;padding-top: 20px; ">

<a href="https://stafwag.github.io/blog/images/gpg/thunderbird/tb0006.png"><img src="https://stafwag.github.io/blog/images/gpg/thunderbird/tb0006.png" class="right" width="300" height="225" alt="open settings" /> </a>

<p>
Thunderbird will show a warning message that it doesn't know the public key to set up the encryption.
</p>

<p>
Click on <b>[Resolve]</b>. 
</p>

</div>

<div style="clear: both;padding-top: 20px; ">
<a href="https://stafwag.github.io/blog/images/gpg/thunderbird/tb0007.png"><img src="https://stafwag.github.io/blog/images/gpg/thunderbird/tb0007.png" class="left" width="300" height="225" alt="discover keys" /> </a>

In the next window Thunderbird will ask to <i>Discover Public Keys online</i> or to import the <i>Public Keys From File</i>, we'll import our public key from a file.

</div>

<div style="clear: both;padding-top: 20px; ">
<a href="https://stafwag.github.io/blog/images/gpg/thunderbird/tb0008.png"><img src="https://stafwag.github.io/blog/images/gpg/thunderbird/tb0008.png" class="left" width="300" height="225" alt="open key file" /> </a>

In the <i>Import OpenPGP key File</i> window select your public key file, and click on <b>[ Open ]</b>.

</div>

<div style="clear: both;padding-top: 20px; ">
<a href="https://stafwag.github.io/blog/images/gpg/thunderbird/tb0009.png"><img src="https://stafwag.github.io/blog/images/gpg/thunderbird/tb0009.png" class="right" width="300" height="225" alt="open settings" /> </a>

<p>
Thunderbird will show a window with the key fingerprint. Select <i>( * ) Accepted</i>.
</p>

<p>
Click on <b>[ Import ]</b> to import the public key.
</p>
</div>

<div style="clear: both;padding-top: 20px; ">

<a href="https://stafwag.github.io/blog/images/gpg/thunderbird/tb0010.png"><img src="https://stafwag.github.io/blog/images/gpg/thunderbird/tb0010.png" class="right" width="300" height="225" alt="open settings" /> </a>

<p>
With our public key imported, the warning about the <i>End-to-end encryption requires resolving key</i> issue should be resolved.
</p>

<p>
Click on the <b>[ Send ]</b> button to send the email.
</p>

</div>

<div style="clear: both;padding-top: 20px; ">

<a href="https://stafwag.github.io/blog/images/gpg/thunderbird/tb0011.png"><img src="https://stafwag.github.io/blog/images/gpg/thunderbird/tb0011.png" class="left" width="300" height="225" alt="open settings" /> </a>

<p>
To encrypt the message, Thunderbird will start a <code>gpg</code> session that invokes the <code>pinentry</code> command type in your pincode. gpg will encrypt the message file and if everything works fine the email is sent.
</p>

</div>
<div style="clear: both;padding-top: 20px; ">
&nbsp;
</div>
<p><strong><em>Have fun!</em></strong></p>

<h1 id="links">Links</h1>

<ul>
  <li><a href="https://wiki.mozilla.org/Thunderbird:OpenPGP">https://wiki.mozilla.org/Thunderbird:OpenPGP</a></li>
  <li><a href="https://wiki.mozilla.org/Thunderbird:OpenPGP:Smartcards">https://wiki.mozilla.org/Thunderbird:OpenPGP:Smartcards</a></li>
  <li><a href="https://support.mozilla.org/en-US/kb/openpgp-thunderbird-howto-and-faq">https://support.mozilla.org/en-US/kb/openpgp-thunderbird-howto-and-faq</a></li>
  <li><a href="https://addons.thunderbird.net/nl/thunderbird/addon/enigmail/">https://addons.thunderbird.net/nl/thunderbird/addon/enigmail/</a></li>
  <li><a href="https://wiki.debian.org/Smartcards/OpenPGP">https://wiki.debian.org/Smartcards/OpenPGP</a></li>
  <li><a href="https://www.floss-shop.de/en/security-privacy/smartcards/13/openpgp-smart-card-v3.4?c=11">https://www.floss-shop.de/en/security-privacy/smartcards/13/openpgp-smart-card-v3.4?c=11</a></li>
  <li><a href="https://www.gnupg.org/howtos/card-howto/en/smartcard-howto-single.html">https://www.gnupg.org/howtos/card-howto/en/smartcard-howto-single.html</a></li>
  <li><a href="https://support.nitrokey.com/t/nk3-mini-gpg-selecting-card-failed-no-such-device-gpg-card-setup/5057/7">https://support.nitrokey.com/t/nk3-mini-gpg-selecting-card-failed-no-such-device-gpg-card-setup/5057/7</a></li>
  <li><a href="https://security.stackexchange.com/questions/233916/gnupg-connecting-to-specific-card-reader-when-multiple-reader-available#233918">https://security.stackexchange.com/questions/233916/gnupg-connecting-to-specific-card-reader-when-multiple-reader-available#233918</a></li>
  <li><a href="https://www.fsij.org/doc-gnuk/stop-scdaemon.html">https://www.fsij.org/doc-gnuk/stop-scdaemon.html</a></li>
  <li><a href="https://wiki.debian.org/Smartcards">https://wiki.debian.org/Smartcards</a></li>
  <li><a href="https://github.com/OpenSC/OpenSC/wiki/Overview/c70c57c1811f54fe3b3989d01708b45b86fafe11">https://github.com/OpenSC/OpenSC/wiki/Overview/c70c57c1811f54fe3b3989d01708b45b86fafe11</a></li>
  <li><a href="https://superuser.com/questions/1693289/gpg-warning-not-using-as-default-key-no-secret-key">https://superuser.com/questions/1693289/gpg-warning-not-using-as-default-key-no-secret-key</a></li>
  <li><a href="https://stackoverflow.com/questions/46689885/how-to-get-public-key-from-an-openpgp-smart-card-without-using-key-servers">https://stackoverflow.com/questions/46689885/how-to-get-public-key-from-an-openpgp-smart-card-without-using-key-servers</a></li>
</ul>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[New release Ansible role stafwag.ntpd, and clean up Ansible roles]]></title>
    <link href="https://stafwag.github.io/blog/blog/2024/08/25/ansible-role-ntpd-released/"/>
    <updated>2024-08-25T06:01:00+00:00</updated>
    <id>https://stafwag.github.io/blog/blog/2024/08/25/ansible-role-ntpd-released</id>
    <content type="html"><![CDATA[<p>I made some time to give some love to my own projects and spent some time rewriting the Ansible role <a href="https://galaxy.ansible.com/ui/standalone/roles/stafwag/ntpd/">stafwag.ntpd</a> and cleaning up some other Ansible roles.</p>

<p>There is some work ongoing for some other Ansible roles/projects,
but this might be a topic for some other blog post(s) ;-)</p>

<p><a href="https://stafwag.github.io/blog/images/ansible/ansible-collaborative-hero-img.svg"><img src="https://stafwag.github.io/blog/images/ansible/ansible-collaborative-hero-img.svg" class="left" width="458" height="274" alt="freebsd with smartcard" /> </a></p>

<h1 id="stafwagntpd">stafwag.ntpd</h1>

<hr style="background-color: #eee; border-top: 1px solid #ddd;" />

<p><em>An ansible role to configure ntpd/chrony/systemd-timesyncd.</em></p>
<hr style="background-color: #eee; border-top: 1px solid #ddd;" />

<p>This might be controversial, but I decided to add support for <a href="https://chrony-project.org/">chrony</a> and <a href="https://www.freedesktop.org/software/systemd/man/latest/systemd-timesyncd.service.html">systemd-timesyncd</a>.  Ntpd is still supported and the default on the BSDs ( <a href="https://www.freebsd.org">FreeBSD</a>, <a href="https://www.netbsd.org">NetBSD</a>, <a href="https://www.openbsd.org">OpenBSD</a>).</p>

<p>It’s possible to switch from the ntp implementation by using the <code class="language-plaintext highlighter-rouge">ntpd.provider</code> directive.</p>

<p>The Ansible role stafwag.ntpd v2.0.0 is available at:</p>

<ul>
  <li><a href="https://github.com/stafwag/ansible-role-ntpd">https://github.com/stafwag/ansible-role-ntpd</a></li>
  <li><a href="https://galaxy.ansible.com/ui/standalone/roles/stafwag/ntpd/">https://galaxy.ansible.com/ui/standalone/roles/stafwag/ntpd/</a></li>
</ul>

<h2 id="release-notes">Release notes</h2>
<h3 id="v200">V2.0.0</h3>

<ul>
  <li><strong>Added support for chrony and systemd-timesyncd on GNU/Linux</strong>
    <ul>
      <li>systemd-timesynced is the default on Debian GNU/Linux 12+ and Archlinux</li>
      <li>ntpd is the default on all operating systems (BSDs, Solaris) and Debian GNU/Linux 10 and 11</li>
      <li>chrony is the default on all other GNU/Linux distributes</li>
      <li>For ntpd hash as the input for the role.</li>
      <li>Updated README</li>
      <li>CleanUp</li>
    </ul>
  </li>
</ul>

<!--more-->
<hr style="border-top: 1px solid black; padding-top: 10px; padding-bottom: 30px;" />

<h1 id="stafwagntpdate">stafwag.ntpdate</h1>

<hr style="background-color: #eee; border-top: 1px solid #ddd;" />

<p><em>An ansible role to activate the ntpdate service on FreeBSD and NetBSD.</em></p>
<hr style="background-color: #eee; border-top: 1px solid #ddd;" />

<p>The <code class="language-plaintext highlighter-rouge">ntpdate</code> service is used on FreeBSD and NetBSD to sync the time during the system boot-up. On most Linux distributions this is handled by <code class="language-plaintext highlighter-rouge">chronyd</code> or <code class="language-plaintext highlighter-rouge">systemd-timesyncd</code> now. The OpenBSD ntpd implementation <a href="https://www.openntpd.org/">OpenNTPD</a> also has support to sync the time during the system boot-up.</p>

<p>The role is available at:</p>

<ul>
  <li><a href="https://github.com/stafwag/ansible-role-ntpdate">https://github.com/stafwag/ansible-role-ntpdate</a></li>
  <li><a href="https://galaxy.ansible.com/ui/standalone/roles/stafwag/ntpdate/">https://galaxy.ansible.com/ui/standalone/roles/stafwag/ntpdate/</a></li>
</ul>

<h2 id="release-notes-1">Release notes</h2>
<h3 id="v100">V1.0.0</h3>
<ul>
  <li><strong>Initial release on Ansible Galaxy</strong>
    <ul>
      <li>Added support for NetBSD</li>
    </ul>
  </li>
</ul>

<hr style="border-top: 1px solid black; padding-top: 10px; padding-bottom: 30px;" />

<h1 id="stafwaglibvirt">stafwag.libvirt</h1>

<hr style="background-color: #eee; border-top: 1px solid #ddd;" />

<p><em>An ansible role to install libvirt/KVM packages and enable the libvirtd service.</em></p>
<hr style="background-color: #eee; border-top: 1px solid #ddd;" />

<p>The role is available at:</p>

<ul>
  <li><a href="https://github.com/stafwag/ansible-role-libvirt">https://github.com/stafwag/ansible-role-libvirt</a></li>
  <li><a href="https://galaxy.ansible.com/ui/standalone/roles/stafwag/libvirt/">https://galaxy.ansible.com/ui/standalone/roles/stafwag/libvirt/</a></li>
</ul>

<h2 id="release-notes-2">Release notes</h2>
<h3 id="v113">V1.1.3</h3>
<ul>
  <li><strong>Force <code class="language-plaintext highlighter-rouge">bash</code> for shell execution on Ubuntu.</strong>
    <ul>
      <li>Force <code class="language-plaintext highlighter-rouge">bash</code> for shell execution on Ubuntu. As the default <code class="language-plaintext highlighter-rouge">dash</code> shell doesn’t support <code class="language-plaintext highlighter-rouge">pipefail</code>.</li>
    </ul>
  </li>
</ul>

<h3 id="v112">V1.1.2</h3>
<ul>
  <li><strong>CleanUp</strong>
    <ul>
      <li>Corrected ansible-lint errors</li>
      <li>Removed install task “install/.yml’”;
        <ul>
          <li>This was introduced to support Kali Linux, Kali Linux is reported as “Debian” now.</li>
          <li>It isn’t used in this role</li>
        </ul>
      </li>
      <li>Removed invalid CentOS-8.yml softlink
        <ul>
          <li>Removed invalid soft link, Centos 8 should be catched by</li>
          <li>RedHat-yum.yml</li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

<hr style="border-top: 1px solid black; padding-top: 10px; padding-bottom: 20px;" />

<h1 id="stafwagcloud_localds">stafwag.cloud_localds</h1>

<hr style="background-color: #eee; border-top: 1px solid #ddd;" />

<p><em>An ansible role to create cloud-init config disk images. This role is a wrapper around the cloud-localds command.</em></p>
<hr style="background-color: #eee; border-top: 1px solid #ddd;" />

<p>It’s still planned to add support for distributions that don’t have <code class="language-plaintext highlighter-rouge">cloud-localds</code> as part of their official package repositories like RedHat 8+.</p>

<p>See the GitHub issue: <a href="https://github.com/stafwag/ansible-role-cloud_localds/issues/7">https://github.com/stafwag/ansible-role-cloud_localds/issues/7</a></p>

<p>The role is available at:</p>

<ul>
  <li><a href="https://github.com/stafwag/ansible-role-cloud_localds/">https://github.com/stafwag/ansible-role-cloud_localds/</a></li>
  <li><a href="https://galaxy.ansible.com/ui/standalone/roles/stafwag/cloud_localds/">https://galaxy.ansible.com/ui/standalone/roles/stafwag/cloud_localds/</a></li>
</ul>

<h2 id="release-notes-3">Release notes</h2>
<h3 id="v213">V2.1.3</h3>
<ul>
  <li><strong>CleanUp</strong>
    <ul>
      <li>Switched to vars and package to install the required packages</li>
      <li>Corrected ansible-lint errors</li>
      <li>Added more examples</li>
    </ul>
  </li>
</ul>

<hr style="border-top: 1px solid black; padding-top: 10px; padding-bottom: 30px;" />

<h1 id="stafwagqemu_img">stafwag.qemu_img</h1>

<hr style="background-color: #eee; border-top: 1px solid #ddd;" />

<p><em>An ansible role to create QEMU disk images.</em></p>
<hr style="background-color: #eee; border-top: 1px solid #ddd;" />

<p>The role is available at:</p>

<ul>
  <li><a href="https://github.com/stafwag/ansible-role-qemu_img">https://github.com/stafwag/ansible-role-qemu_img</a></li>
  <li><a href="https://galaxy.ansible.com/ui/standalone/roles/stafwag/qemu_img/">https://galaxy.ansible.com/ui/standalone/roles/stafwag/qemu_img/</a></li>
</ul>

<h2 id="release-notes-4">Release notes</h2>
<h3 id="v230">V2.3.0</h3>
<ul>
  <li><strong>CleanUp Release</strong>
    <ul>
      <li>Added doc/examples</li>
      <li>Updated meta data</li>
      <li>Switched to vars and package to install the required packages</li>
      <li>Corrected ansible-lint errors</li>
    </ul>
  </li>
</ul>

<hr style="border-top: 1px solid black; padding-top: 10px; padding-bottom: 30px;" />

<h1 id="stafwagvirt_install_import">stafwag.virt_install_import</h1>

<hr style="background-color: #eee; border-top: 1px solid #ddd;" />

<p><em>An ansible role to import virtual machine with the virt-install import command</em></p>
<hr style="background-color: #eee; border-top: 1px solid #ddd;" />

<p>The role is available at:</p>

<ul>
  <li><a href="https://github.com/stafwag/ansible-role-virt_install_import">https://github.com/stafwag/ansible-role-virt_install_import</a></li>
  <li><a href="https://galaxy.ansible.com/ui/standalone/roles/stafwag/virt_install_import/">https://galaxy.ansible.com/ui/standalone/roles/stafwag/virt_install_import/</a></li>
</ul>

<h2 id="release-notes-5">Release notes</h2>

<ul>
  <li><strong>Use var and package to install pkgs</strong>
    <ul>
      <li>v1.2.1 wasn’t merged correctly. The release should fix it…</li>
      <li>Switched to var and package to install the required packages</li>
      <li>Updated meta data</li>
      <li>Updated documentation and include examples</li>
      <li>Corrected ansible-lint errors</li>
    </ul>
  </li>
</ul>

<p><br />
<br />
<strong><em>Have fun!</em></strong></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Use a GPG smart card with Thunderbird. Part 2: setup GnuPG on FreeBSD]]></title>
    <link href="https://stafwag.github.io/blog/blog/2024/07/28/use-a-gpg-smartcard-with-thunderbird-part_2-setup-gpg-on-freebsd/"/>
    <updated>2024-07-28T09:09:00+00:00</updated>
    <id>https://stafwag.github.io/blog/blog/2024/07/28/use-a-gpg-smartcard-with-thunderbird-part_2-setup-gpg-on-freebsd</id>
    <content type="html"><![CDATA[<hr />

<p><em>Updated @ Mon Sep  2 07:55:20 PM CEST 2024: Added devfs section</em><br />
<em>Updated @ Wed Sep  4 07:48:56 PM CEST 2024 : Corrected gpg-agent.conf</em></p>

<hr />

<p>I use <a href="https://www.freebsd.org">FreeBSD</a> and <a href="https://www.gnu.org">GNU</a>/<a href="https://www.kernel.org">Linux</a>.
<a href="https://stafwag.github.io/blog/images/gpg/freebsd_with_smartcard.jpg"><img src="https://stafwag.github.io/blog/images/gpg/freebsd_with_smartcard_s.jpg" class="left" width="500" height="333" alt="freebsd with smartcard" /> </a></p>

<p>In a <a href="https://stafwag.github.io/blog/blog/2024/04/21/use-a-gpg-smartcard-with-thunderbird-part_1-setup-gpg/">previous blog post</a>, we set up <a href="https://gnupg.org/">GnuPG</a> with <a href="https://en.wikipedia.org/wiki/Smart_card">smartcard</a> support on <a href="https://www.debian.org">Debian</a> <a href="https://www.gnu.org">GNU</a>/<a href="https://www.kernel.org">Linux</a>.</p>

<p>In this blog post, we’ll install and configure GnuPG with smartcard support on <a href="https://www.freebsd.org">FreeBSD</a>.</p>

<p>The <a href="https://stafwag.github.io/blog/blog/2024/04/21/use-a-gpg-smartcard-with-thunderbird-part_1-setup-gpg/">GNU/Linux blog post</a> provides more details about GnuPG, so it might be useful for the FreeBSD users to read it first.</p>

<p>Likewise, Linux users are welcome to read this blog post if they’re interested in how it’s done on FreeBSD ;-)</p>

<!--more-->

<h1 id="install-the-required-packages">Install the required packages</h1>

<p>To begin, we need to install the required packages on FreeBSD.</p>

<h2 id="update-the-package-database">Update the package database</h2>

<p>Execute <code class="language-plaintext highlighter-rouge">pkg update</code> to update the package database.</p>

<h2 id="thunderbird">Thunderbird</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@monty ~]$ sudo pkg install -y thunderbird
Password:
Updating FreeBSD repository catalogue...
FreeBSD repository is up to date.
All repositories are up to date.
Checking integrity... done (0 conflicting)
The most recent versions of packages are already installed
[staf@monty ~]$ 
</code></pre></div></div>

<h2 id="lsusb">lsusb</h2>

<p>You can verify the USB devices on FreeBSD using the <a href="https://man.freebsd.org/cgi/man.cgi?usbconfig">usbconfig</a> command or <a href="https://www.man7.org/linux/man-pages/man8/lsusb.8.html">lsusb</a> which is also available on FreeBSD as part of the <code class="language-plaintext highlighter-rouge">usbutils</code> package.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@monty ~/git/stafnet/blog]$ sudo pkg install usbutils
Password:
Updating FreeBSD repository catalogue...
FreeBSD repository is up to date.
All repositories are up to date.
The following 3 package(s) will be affected (of 0 checked):

New packages to be INSTALLED:
	usbhid-dump: 1.4
	usbids: 20240318
	usbutils: 0.91

Number of packages to be installed: 3

301 KiB to be downloaded.

Proceed with this action? [y/N]: y
[1/3] Fetching usbutils-0.91.pkg: 100%   54 KiB  55.2kB/s    00:01    
[2/3] Fetching usbhid-dump-1.4.pkg: 100%   32 KiB  32.5kB/s    00:01    
[3/3] Fetching usbids-20240318.pkg: 100%  215 KiB 220.5kB/s    00:01    
Checking integrity... done (0 conflicting)
[1/3] Installing usbhid-dump-1.4...
[1/3] Extracting usbhid-dump-1.4: 100%
[2/3] Installing usbids-20240318...
[2/3] Extracting usbids-20240318: 100%
[3/3] Installing usbutils-0.91...
[3/3] Extracting usbutils-0.91: 100%
[staf@monty ~/git/stafnet/blog]$
</code></pre></div></div>

<h2 id="gnupg">GnuPG</h2>

<p>We’ll need GnuPG ( of course ), so ensure that it is installed.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@monty ~]$ sudo pkg install gnupg
Updating FreeBSD repository catalogue...
FreeBSD repository is up to date.
All repositories are up to date.
Checking integrity... done (0 conflicting)
The most recent versions of packages are already installed
[staf@monty ~]$ 
</code></pre></div></div>

<h2 id="smartcard-packages">Smartcard packages</h2>

<p>To enable smartcard support on FreeBSD, we’ll need to install the smartcard packages. The same software as on GNU/Linux - <a href="https://github.com/OpenSC/OpenSC/wiki">opensc</a> - is available on FreeBSD.</p>

<h3 id="pkg-provides">pkg provides</h3>

<p>It’s handy to be able to check which packages provide certain files. On FreeBSD this is provided by the <code class="language-plaintext highlighter-rouge">provides</code> plugin. This plugin is not enabled by default in the <a href="https://man.freebsd.org/cgi/man.cgi?pkg">pkg</a> command.</p>

<p>To install in the <code class="language-plaintext highlighter-rouge">provides</code> plugin install the <code class="language-plaintext highlighter-rouge">pkg-provides</code> package.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@monty ~]$ sudo pkg install pkg-provides
Updating FreeBSD repository catalogue...
FreeBSD repository is up to date.
All repositories are up to date.
The following 1 package(s) will be affected (of 0 checked):

New packages to be INSTALLED:
        pkg-provides: 0.7.3_3

Number of packages to be installed: 1

12 KiB to be downloaded.

Proceed with this action? [y/N]: y
[1/1] Fetching pkg-provides-0.7.3_3.pkg: 100%   12 KiB  12.5kB/s    00:01    
Checking integrity... done (0 conflicting)
[1/1] Installing pkg-provides-0.7.3_3...
[1/1] Extracting pkg-provides-0.7.3_3: 100%
=====
Message from pkg-provides-0.7.3_3:

--
In order to use the pkg-provides plugin you need to enable plugins in pkg.
To do this, uncomment the following lines in /usr/local/etc/pkg.conf file
and add pkg-provides to the supported plugin list:

PKG_PLUGINS_DIR = "/usr/local/lib/pkg/";
PKG_ENABLE_PLUGINS = true;
PLUGINS [ provides ];

After that run `pkg plugins' to see the plugins handled by pkg.
[staf@monty ~]$ 
</code></pre></div></div>
<p>Edit the pkg configuration to enable the provides plug-in.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>staf@freebsd-gpg:~ $ sudo vi /usr/local/etc/pkg.conf
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PKG_PLUGINS_DIR = "/usr/local/lib/pkg/";
PKG_ENABLE_PLUGINS = true;
PLUGINS [ provides ];
</code></pre></div></div>

<p>Verify that the plugin is enabled.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>staf@freebsd-gpg:~ $ sudo pkg plugins
NAME       DESC                                          VERSION   
provides   A plugin for querying which package provides a particular file 0.7.3     
staf@freebsd-gpg:~ $ 
</code></pre></div></div>

<p>Update the <code class="language-plaintext highlighter-rouge">pkg-provides</code> database.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>staf@freebsd-gpg:~ $ sudo pkg provides -u
Fetching provides database: 100%   18 MiB   9.6MB/s    00:02    
Extracting database....success
staf@freebsd-gpg:~ $
</code></pre></div></div>

<h3 id="install-the-required-packages-1">Install the required packages</h3>

<p>Let’s check which packages provide the tools to set up the smartcard reader on FreeBSD.
And install the required packages.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>staf@freebsd-gpg:~ $ pkg provides "pkcs15-tool"
Name    : opensc-0.25.1
Comment : Libraries and utilities to access smart cards
Repo    : FreeBSD
Filename: usr/local/share/man/man1/pkcs15-tool.1.gz
          usr/local/etc/bash_completion.d/pkcs15-tool
          usr/local/bin/pkcs15-tool
staf@freebsd-gpg:~ $ 
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>staf@freebsd-gpg:~ $ pkg provides "bin/pcsc"
Name    : pcsc-lite-2.2.2,2
Comment : Middleware library to access a smart card using SCard API (PC/SC)
Repo    : FreeBSD
Filename: usr/local/sbin/pcscd
          usr/local/bin/pcsc-spy
staf@freebsd-gpg:~ $ 
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@monty ~]$ sudo pkg install opensc pcsc-lite
Password:
Updating FreeBSD repository catalogue...
FreeBSD repository is up to date.
All repositories are up to date.
Checking integrity... done (0 conflicting)
The most recent versions of packages are already installed
[staf@monty ~]$ 
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>staf@freebsd-gpg:~ $ sudo pkg install -y pcsc-tools
Updating FreeBSD repository catalogue...
FreeBSD repository is up to date.
All repositories are up to date.
Checking integrity... done (0 conflicting)
The most recent versions of packages are already installed
staf@freebsd-gpg:~ $ 
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>staf@freebsd-gpg:~ $ sudo pkg install -y ccid
Password:
Updating FreeBSD repository catalogue...
FreeBSD repository is up to date.
All repositories are up to date.
Checking integrity... done (0 conflicting)
The most recent versions of packages are already installed
staf@freebsd-gpg:~ $ 
</code></pre></div></div>

<h1 id="usb">USB</h1>

<p>To use the smartcard reader we will need access to the USB devices as the user we use for our desktop environment. (No, this shouldn’t be the <code class="language-plaintext highlighter-rouge">root</code> user :-) )</p>

<h2 id="permissions">permissions</h2>

<h3 id="verify">verify</h3>

<p>Execute the <code class="language-plaintext highlighter-rouge">usbconfig</code> command to verify that you can access the USB devices.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@snuffel ~]$ usbconfig
No device match or lack of permissions.
[staf@snuffel ~]$ 
</code></pre></div></div>

<p>If you don’t have access, verify the permissions of the USB devices.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@snuffel ~]$ ls -l /dev/usbctl
crw-r--r--  1 root operator 0x5b Sep  2 19:17 /dev/usbctl
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@snuffel ~]$  ls -l /dev/usb/
total 0
crw-------  1 root operator 0x34 Sep  2 19:17 0.1.0
crw-------  1 root operator 0x4f Sep  2 19:17 0.1.1
crw-------  1 root operator 0x36 Sep  2 19:17 1.1.0
crw-------  1 root operator 0x53 Sep  2 19:17 1.1.1
crw-------  1 root operator 0x7e Sep  2 19:17 1.2.0
crw-------  1 root operator 0x82 Sep  2 19:17 1.2.1
crw-------  1 root operator 0x83 Sep  2 19:17 1.2.2
crw-------  1 root operator 0x76 Sep  2 19:17 1.3.0
crw-------  1 root operator 0x8a Sep  2 19:17 1.3.1
crw-------  1 root operator 0x8b Sep  2 19:17 1.3.2
crw-------  1 root operator 0x8c Sep  2 19:17 1.3.3
crw-------  1 root operator 0x8d Sep  2 19:17 1.3.4
crw-------  1 root operator 0x38 Sep  2 19:17 2.1.0
crw-------  1 root operator 0x56 Sep  2 19:17 2.1.1
crw-------  1 root operator 0x3a Sep  2 19:17 3.1.0
crw-------  1 root operator 0x51 Sep  2 19:17 3.1.1
crw-------  1 root operator 0x3c Sep  2 19:17 4.1.0
crw-------  1 root operator 0x55 Sep  2 19:17 4.1.1
crw-------  1 root operator 0x3e Sep  2 19:17 5.1.0
crw-------  1 root operator 0x54 Sep  2 19:17 5.1.1
crw-------  1 root operator 0x80 Sep  2 19:17 5.2.0
crw-------  1 root operator 0x85 Sep  2 19:17 5.2.1
crw-------  1 root operator 0x86 Sep  2 19:17 5.2.2
crw-------  1 root operator 0x87 Sep  2 19:17 5.2.3
crw-------  1 root operator 0x40 Sep  2 19:17 6.1.0
crw-------  1 root operator 0x52 Sep  2 19:17 6.1.1
crw-------  1 root operator 0x42 Sep  2 19:17 7.1.0
crw-------  1 root operator 0x50 Sep  2 19:17 7.1.1
</code></pre></div></div>

<h3 id="devfs">devfs</h3>

<p>When the <code class="language-plaintext highlighter-rouge">/dev/usb*</code> are only accessible by the <code class="language-plaintext highlighter-rouge">root</code> user. You probably want to create <code class="language-plaintext highlighter-rouge">devfs.rules</code> that to grant permissions to the <code class="language-plaintext highlighter-rouge">operator</code> or another group.</p>

<p>See <a href="https://man.freebsd.org/cgi/man.cgi?devfs.rules">https://man.freebsd.org/cgi/man.cgi?devfs.rules</a> for more details.</p>

<h4 id="etcrcconf"><code class="language-plaintext highlighter-rouge">/etc/rc.conf</code></h4>

<p>Update the <code class="language-plaintext highlighter-rouge">/etc/rc.conf</code> to apply custom <code class="language-plaintext highlighter-rouge">devfs</code> permissions.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@snuffel /etc]$ sudo vi rc.conf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>devfs_system_ruleset="localrules"
</code></pre></div></div>

<h4 id="etcdevfsrules"><code class="language-plaintext highlighter-rouge">/etc/devfs.rules</code></h4>

<p>Create or update the <code class="language-plaintext highlighter-rouge">/dev/devfs.rules</code> with the update permissions to grant read/write access to the <code class="language-plaintext highlighter-rouge">operator</code> group.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@snuffel /etc]$ sudo vi devfs.rules
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[localrules=10]
add path 'usbctl*' mode 0660 group operator
add path 'usb/*' mode 0660 group operator
</code></pre></div></div>

<p>Restart the <code class="language-plaintext highlighter-rouge">devfs</code> service to apply the custom <code class="language-plaintext highlighter-rouge">devfs</code> ruleset.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@snuffel /etc]$ sudo -i
root@snuffel:~ #
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@snuffel:~ # service devfs restart
</code></pre></div></div>

<p>The operator group should have read/write permissions now.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@snuffel:~ # ls -l /dev/usb/
total 0
crw-rw----  1 root operator 0x34 Sep  2 19:17 0.1.0
crw-rw----  1 root operator 0x4f Sep  2 19:17 0.1.1
crw-rw----  1 root operator 0x36 Sep  2 19:17 1.1.0
crw-rw----  1 root operator 0x53 Sep  2 19:17 1.1.1
crw-rw----  1 root operator 0x7e Sep  2 19:17 1.2.0
crw-rw----  1 root operator 0x82 Sep  2 19:17 1.2.1
crw-rw----  1 root operator 0x83 Sep  2 19:17 1.2.2
crw-rw----  1 root operator 0x76 Sep  2 19:17 1.3.0
crw-rw----  1 root operator 0x8a Sep  2 19:17 1.3.1
crw-rw----  1 root operator 0x8b Sep  2 19:17 1.3.2
crw-rw----  1 root operator 0x8c Sep  2 19:17 1.3.3
crw-rw----  1 root operator 0x8d Sep  2 19:17 1.3.4
crw-rw----  1 root operator 0x38 Sep  2 19:17 2.1.0
crw-rw----  1 root operator 0x56 Sep  2 19:17 2.1.1
crw-rw----  1 root operator 0x3a Sep  2 19:17 3.1.0
crw-rw----  1 root operator 0x51 Sep  2 19:17 3.1.1
crw-rw----  1 root operator 0x3c Sep  2 19:17 4.1.0
crw-rw----  1 root operator 0x55 Sep  2 19:17 4.1.1
crw-rw----  1 root operator 0x3e Sep  2 19:17 5.1.0
crw-rw----  1 root operator 0x54 Sep  2 19:17 5.1.1
crw-rw----  1 root operator 0x80 Sep  2 19:17 5.2.0
crw-rw----  1 root operator 0x85 Sep  2 19:17 5.2.1
crw-rw----  1 root operator 0x86 Sep  2 19:17 5.2.2
crw-rw----  1 root operator 0x87 Sep  2 19:17 5.2.3
crw-rw----  1 root operator 0x40 Sep  2 19:17 6.1.0
crw-rw----  1 root operator 0x52 Sep  2 19:17 6.1.1
crw-rw----  1 root operator 0x42 Sep  2 19:17 7.1.0
crw-rw----  1 root operator 0x50 Sep  2 19:17 7.1.1
root@snuffel:~ # 
</code></pre></div></div>

<h3 id="make-sure-that-youre-part-of-the-operator-group">Make sure that you’re part of the operator group</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>staf@freebsd-gpg:~ $ ls -l /dev/usbctl 
crw-rw----  1 root operator 0x5a Jul 13 17:32 /dev/usbctl
staf@freebsd-gpg:~ $ ls -l /dev/usb/
total 0
crw-rw----  1 root operator 0x31 Jul 13 17:32 0.1.0
crw-rw----  1 root operator 0x53 Jul 13 17:32 0.1.1
crw-rw----  1 root operator 0x33 Jul 13 17:32 1.1.0
crw-rw----  1 root operator 0x51 Jul 13 17:32 1.1.1
crw-rw----  1 root operator 0x35 Jul 13 17:32 2.1.0
crw-rw----  1 root operator 0x52 Jul 13 17:32 2.1.1
crw-rw----  1 root operator 0x37 Jul 13 17:32 3.1.0
crw-rw----  1 root operator 0x54 Jul 13 17:32 3.1.1
crw-rw----  1 root operator 0x73 Jul 13 17:32 3.2.0
crw-rw----  1 root operator 0x75 Jul 13 17:32 3.2.1
crw-rw----  1 root operator 0x76 Jul 13 17:32 3.3.0
crw-rw----  1 root operator 0x78 Jul 13 17:32 3.3.1
staf@freebsd-gpg:~ $ 
</code></pre></div></div>

<p>You’ll need to be part of the <code class="language-plaintext highlighter-rouge">operator</code> group to access the USB devices.</p>

<p>Execute the <a href="https://man.freebsd.org/cgi/man.cgi?query=vigr">vigr</a> command and add the user to the operator group.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>staf@freebsd-gpg:~ $ sudo vigr
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>operator:*:5:root,staf
</code></pre></div></div>

<p>Relogin and check that you are in the operator group.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>staf@freebsd-gpg:~ $ id
uid=1001(staf) gid=1001(staf) groups=1001(staf),0(wheel),5(operator)
staf@freebsd-gpg:~ $ 
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">usbconfig</code> command should work now.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>staf@freebsd-gpg:~ $ usbconfig
ugen1.1: &lt;Intel UHCI root HUB&gt; at usbus1, cfg=0 md=HOST spd=FULL (12Mbps) pwr=SAVE (0mA)
ugen2.1: &lt;Intel UHCI root HUB&gt; at usbus2, cfg=0 md=HOST spd=FULL (12Mbps) pwr=SAVE (0mA)
ugen0.1: &lt;Intel UHCI root HUB&gt; at usbus0, cfg=0 md=HOST spd=FULL (12Mbps) pwr=SAVE (0mA)
ugen3.1: &lt;Intel EHCI root HUB&gt; at usbus3, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=SAVE (0mA)
ugen3.2: &lt;QEMU Tablet Adomax Technology Co., Ltd&gt; at usbus3, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=ON (100mA)
ugen3.3: &lt;QEMU Tablet Adomax Technology Co., Ltd&gt; at usbus3, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=ON (100mA)
staf@freebsd-gpg:~ $ 
</code></pre></div></div>

<h1 id="smartcard-configuration">SmartCard configuration</h1>

<h2 id="verify-the-usb-connection">Verify the USB connection</h2>

<p>The first step is to ensure your smartcard reader is detected on a USB level. Execute <code class="language-plaintext highlighter-rouge">usbconfig</code> and <code class="language-plaintext highlighter-rouge">lsusb</code> and make sure your smartcard reader is listed.</p>

<h3 id="usbconfig">usbconfig</h3>

<p>List the USB devices.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@monty ~/git]$ usbconfig
ugen1.1: &lt;Intel EHCI root HUB&gt; at usbus1, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=SAVE (0mA)
ugen0.1: &lt;Intel XHCI root HUB&gt; at usbus0, cfg=0 md=HOST spd=SUPER (5.0Gbps) pwr=SAVE (0mA)
ugen2.1: &lt;Intel EHCI root HUB&gt; at usbus2, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=SAVE (0mA)
ugen2.2: &lt;Integrated Rate Matching Hub Intel Corp.&gt; at usbus2, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=SAVE (0mA)
ugen1.2: &lt;Integrated Rate Matching Hub Intel Corp.&gt; at usbus1, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=SAVE (0mA)
ugen0.2: &lt;AU9540 Smartcard Reader Alcor Micro Corp.&gt; at usbus0, cfg=0 md=HOST spd=FULL (12Mbps) pwr=ON (50mA)
ugen0.3: &lt;VFS 5011 fingerprint sensor Validity Sensors, Inc.&gt; at usbus0, cfg=0 md=HOST spd=FULL (12Mbps) pwr=ON (100mA)
ugen0.4: &lt;Centrino Bluetooth Wireless Transceiver Intel Corp.&gt; at usbus0, cfg=0 md=HOST spd=FULL (12Mbps) pwr=ON (0mA)
ugen0.5: &lt;SunplusIT INC. Integrated Camera&gt; at usbus0, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=ON (500mA)
ugen0.6: &lt;X-Rite Pantone Color Sensor X-Rite, Inc.&gt; at usbus0, cfg=0 md=HOST spd=LOW (1.5Mbps) pwr=ON (100mA)
ugen0.7: &lt;GemPC Key SmartCard Reader Gemalto (was Gemplus)&gt; at usbus0, cfg=0 md=HOST spd=FULL (12Mbps) pwr=ON (50mA)
[staf@monty ~/git]$ 
</code></pre></div></div>

<h3 id="lsusb-1">lsusb</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@monty ~/git/stafnet/blog]$ lsusb
Bus /dev/usb Device /dev/ugen0.7: ID 08e6:3438 Gemalto (was Gemplus) GemPC Key SmartCard Reader
Bus /dev/usb Device /dev/ugen0.6: ID 0765:5010 X-Rite, Inc. X-Rite Pantone Color Sensor
Bus /dev/usb Device /dev/ugen0.5: ID 04f2:b39a Chicony Electronics Co., Ltd 
Bus /dev/usb Device /dev/ugen0.4: ID 8087:07da Intel Corp. Centrino Bluetooth Wireless Transceiver
Bus /dev/usb Device /dev/ugen0.3: ID 138a:0017 Validity Sensors, Inc. VFS 5011 fingerprint sensor
Bus /dev/usb Device /dev/ugen0.2: ID 058f:9540 Alcor Micro Corp. AU9540 Smartcard Reader
Bus /dev/usb Device /dev/ugen1.2: ID 8087:8008 Intel Corp. Integrated Rate Matching Hub
Bus /dev/usb Device /dev/ugen2.2: ID 8087:8000 Intel Corp. Integrated Rate Matching Hub
Bus /dev/usb Device /dev/ugen2.1: ID 0000:0000  
Bus /dev/usb Device /dev/ugen0.1: ID 0000:0000  
Bus /dev/usb Device /dev/ugen1.1: ID 0000:0000  
[staf@monty ~/git/stafnet/blog]$ 
</code></pre></div></div>

<h2 id="check-the-gnupg-smartcard-status">Check the GnuPG smartcard status</h2>

<p>Let’s check if we get access to our smart card with <code class="language-plaintext highlighter-rouge">gpg</code>.</p>

<p>This might work if you have a native-supported GnuPG smartcard.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@monty ~]$ gpg --card-status
gpg: selecting card failed: Operation not supported by device
gpg: OpenPGP card not available: Operation not supported by device
[staf@monty ~]$ 
</code></pre></div></div>

<p>In my case, it doesn’t work. I prefer the OpenSC interface, this might be useful if you want to use your smartcard for other usages.</p>

<h2 id="opensc">opensc</h2>

<h3 id="enable-pcscd">Enable pcscd</h3>

<p>FreeBSD has a handy tool <a href="https://man.freebsd.org/cgi/man.cgi?query=sysrc&amp;sektion=8&amp;format=html">sysrc</a> to manage <a href="https://man.freebsd.org/cgi/man.cgi?query=rc.conf">rc.conf</a></p>

<p>Enable the <code class="language-plaintext highlighter-rouge">pcscd</code> service.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@monty ~]$ sudo sysrc pcscd_enable=YES
Password:
pcscd_enable: NO -&gt; YES
[staf@monty ~]$ 
</code></pre></div></div>

<p>Start the <code class="language-plaintext highlighter-rouge">pcscd</code> service.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@monty ~]$ sudo /usr/local/etc/rc.d/pcscd start
Password:
Starting pcscd.
[staf@monty ~]$ 
</code></pre></div></div>

<h3 id="verify-smartcard-access">Verify smartcard access</h3>

<h4 id="pcsc_scan">pcsc_scan</h4>

<p>The <code class="language-plaintext highlighter-rouge">opensc-tools</code> package provides a tool - <code class="language-plaintext highlighter-rouge">pcsc_scan</code> to verify the smartcard readers.</p>

<p>Execute <code class="language-plaintext highlighter-rouge">pcsc_scan</code> to verify that your smartcard is detected.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@monty ~]$ pcsc_scan 
PC/SC device scanner
V 1.7.1 (c) 2001-2022, Ludovic Rousseau &lt;ludovic.rousseau@free.fr&gt;
Using reader plug'n play mechanism
Scanning present readers...
0: Gemalto USB Shell Token V2 (284C3E93) 00 00
1: Alcor Micro AU9540 01 00
 
Thu Jul 25 18:42:34 2024
 Reader 0: Gemalto USB Shell Token V2 (&lt;snip&gt;) 00 00
  Event number: 0
  Card state: Card inserted, 
  ATR: &lt;snip&gt;

ATR: &lt;snip&gt;
+ TS = 3B --&gt; Direct Convention
+ T0 = DA, Y(1): 1101, K: 10 (historical bytes)
  TA(1) = 18 --&gt; Fi=372, Di=12, 31 cycles/ETU
    129032 bits/s at 4 MHz, fMax for Fi = 5 MHz =&gt; 161290 bits/s
  TC(1) = FF --&gt; Extra guard time: 255 (special value)
  TD(1) = 81 --&gt; Y(i+1) = 1000, Protocol T = 1 
-----
  TD(2) = B1 --&gt; Y(i+1) = 1011, Protocol T = 1 
-----
  TA(3) = FE --&gt; IFSC: 254
  TB(3) = 75 --&gt; Block Waiting Integer: 7 - Character Waiting Integer: 5
  TD(3) = 1F --&gt; Y(i+1) = 0001, Protocol T = 15 - Global interface bytes following 
-----
  TA(4) = 03 --&gt; Clock stop: not supported - Class accepted by the card: (3G) A 5V B 3V 
+ Historical bytes: 00 31 C5 73 C0 01 40 00 90 00
  Category indicator byte: 00 (compact TLV data object)
    Tag: 3, len: 1 (card service data byte)
      Card service data byte: C5
        - Application selection: by full DF name
        - Application selection: by partial DF name
        - EF.DIR and EF.ATR access services: by GET DATA command
        - Card without MF
    Tag: 7, len: 3 (card capabilities)
      Selection methods: C0
        - DF selection by full DF name
        - DF selection by partial DF name
      Data coding byte: 01
        - Behaviour of write functions: one-time write
        - Value 'FF' for the first byte of BER-TLV tag fields: invalid
        - Data unit in quartets: 2
      Command chaining, length fields and logical channels: 40
        - Extended Lc and Le fields
        - Logical channel number assignment: No logical channel
        - Maximum number of logical channels: 1
    Mandatory status indicator (3 last bytes)
      LCS (life card cycle): 00 (No information given)
      SW: 9000 (Normal processing.)
+ TCK = 0C (correct checksum)

Possibly identified card (using /usr/local/share/pcsc/smartcard_list.txt):
&lt;snip&gt;
        OpenPGP Card V2

 Reader 1: Alcor Micro AU9540 01 00
  Event number: 0
  Card state
</code></pre></div></div>

<h4 id="pkcs15">pkcs15</h4>

<p>pkcs15 is the <code class="language-plaintext highlighter-rouge">application</code> interface for hardware tokens while pkcs11 is the low-level interface.</p>

<p>You can use <code class="language-plaintext highlighter-rouge">pkcs15-tool -D</code> to verify that your smartcard is detected.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>staf@monty ~]$ pkcs15-tool -D
Using reader with a card: Gemalto USB Shell Token V2 (&lt;snip&gt;) 00 00
PKCS#15 Card [OpenPGP card]:
        Version        : 0
        Serial number  : &lt;snip&gt;
        Manufacturer ID: ZeitControl
        Language       : nl
        Flags          : PRN generation, EID compliant


PIN [User PIN]
        Object Flags   : [0x03], private, modifiable
        Auth ID        : 03
        ID             : 02
        Flags          : [0x13], case-sensitive, local, initialized
        Length         : min_len:6, max_len:32, stored_len:32
        Pad char       : 0x00
        Reference      : 2 (0x02)
        Type           : UTF-8
        Path           : 3f00
        Tries left     : 3

PIN [User PIN (sig)]
        Object Flags   : [0x03], private, modifiable
        Auth ID        : 03
        ID             : 01
        Flags          : [0x13], case-sensitive, local, initialized
        Length         : min_len:6, max_len:32, stored_len:32
        Pad char       : 0x00
        Reference      : 1 (0x01)
        Type           : UTF-8
        Path           : 3f00
        Tries left     : 0

PIN [Admin PIN]
        Object Flags   : [0x03], private, modifiable
        ID             : 03
        Flags          : [0x9B], case-sensitive, local, unblock-disabled, initialized, soPin
        Length         : min_len:8, max_len:32, stored_len:32
        Pad char       : 0x00
        Reference      : 3 (0x03)
        Type           : UTF-8
        Path           : 3f00
        Tries left     : 0

Private RSA Key [Signature key]
        Object Flags   : [0x03], private, modifiable
        Usage          : [0x20C], sign, signRecover, nonRepudiation
        Access Flags   : [0x1D], sensitive, alwaysSensitive, neverExtract, local
        Algo_refs      : 0
        ModLength      : 3072
        Key ref        : 0 (0x00)
        Native         : yes
        Auth ID        : 01
        ID             : 01
        MD:guid        : &lt;snip&gt;

Private RSA Key [Encryption key]
        Object Flags   : [0x03], private, modifiable
        Usage          : [0x22], decrypt, unwrap
        Access Flags   : [0x1D], sensitive, alwaysSensitive, neverExtract, local
        Algo_refs      : 0
        ModLength      : 3072
        Key ref        : 1 (0x01)
        Native         : yes
        Auth ID        : 02
        ID             : 02
        MD:guid        : &lt;snip&gt;

Private RSA Key [Authentication key]
        Object Flags   : [0x03], private, modifiable
        Usage          : [0x200], nonRepudiation
        Access Flags   : [0x1D], sensitive, alwaysSensitive, neverExtract, local
        Algo_refs      : 0
        ModLength      : 3072
        Key ref        : 2 (0x02)
        Native         : yes
        Auth ID        : 02
        ID             : 03
        MD:guid        : &lt;snip&gt;

Public RSA Key [Signature key]
        Object Flags   : [0x02], modifiable
        Usage          : [0xC0], verify, verifyRecover
        Access Flags   : [0x02], extract
        ModLength      : 3072
        Key ref        : 0 (0x00)
        Native         : no
        Path           : b601
        ID             : 01

Public RSA Key [Encryption key]
        Object Flags   : [0x02], modifiable
        Usage          : [0x11], encrypt, wrap
        Access Flags   : [0x02], extract
        ModLength      : 3072
        Key ref        : 0 (0x00)
        Native         : no
        Path           : b801
        ID             : 02

Public RSA Key [Authentication key]
        Object Flags   : [0x02], modifiable
        Usage          : [0x40], verify
        Access Flags   : [0x02], extract
        ModLength      : 3072
        Key ref        : 0 (0x00)
        Native         : no
        Path           : a401
        ID             : 03

[staf@monty ~]$ 
</code></pre></div></div>

<h2 id="gnupg-configuration">GnuPG configuration</h2>

<h3 id="first-test">First test</h3>

<p>Stop (kill) the <code class="language-plaintext highlighter-rouge">scdaemon</code>, to ensure that the <code class="language-plaintext highlighter-rouge">scdaemon</code> tries to use the <code class="language-plaintext highlighter-rouge">opensc</code> interface.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@monty ~]$ gpgconf --kill scdaemon
[staf@monty ~]$ 
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@monty ~]$ ps aux | grep -i scdaemon
staf  9236  0.0  0.0   12808   2496  3  S+   20:42   0:00.00 grep -i scdaemon
[staf@monty ~]$ 
</code></pre></div></div>

<p>Try to read the card status again.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@monty ~]$ gpg --card-status
gpg: selecting card failed: Operation not supported by device
gpg: OpenPGP card not available: Operation not supported by device
[staf@monty ~]$ 
</code></pre></div></div>

<h3 id="reconfigure-gnupg">Reconfigure GnuPG</h3>

<p>Go to the <code class="language-plaintext highlighter-rouge">.gnupg</code> directory in your <code class="language-plaintext highlighter-rouge">$HOME</code> directory.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@monty ~]$ cd .gnupg/
[staf@monty ~/.gnupg]$ 
</code></pre></div></div>

<h4 id="scdaemon">scdaemon</h4>

<p>Reconfigure <code class="language-plaintext highlighter-rouge">scdaemon</code> to disable the internal <code class="language-plaintext highlighter-rouge">ccid</code> and enable logging - always useful to verify why something isn’t working…</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@monty ~/.gnupg]$ vi scdaemon.conf
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>disable-ccid

verbose
debug-level expert
debug-all
log-file    /home/staf/logs/scdaemon.log
</code></pre></div></div>

<h4 id="gpg-agent">gpg-agent</h4>

<p>Enable debug logging for the <code class="language-plaintext highlighter-rouge">gpg-agent</code>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@monty ~/.gnupg]$ vi gpg-agent.conf
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>debug-level expert
verbose
verbose
log-file /home/staf/logs/gpg-agent.log
</code></pre></div></div>

<h4 id="verify-1">Verify</h4>

<p>Stop the <code class="language-plaintext highlighter-rouge">scdaemon</code>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@monty ~/.gnupg]$ gpgconf --kill scdaemon
[staf@monty ~/.gnupg]$ 
</code></pre></div></div>

<p>If everything goes well <code class="language-plaintext highlighter-rouge">gpg</code> will detect the smartcard.</p>

<p>If not, you have some logging to do some debugging ;-)</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@monty ~/.gnupg]$ gpg --card-status
Reader ...........: Gemalto USB Shell Token V2 (&lt;snip&gt;) 00 00
Application ID ...: &lt;snip&gt;
Application type .: OpenPGP
Version ..........: 2.1
Manufacturer .....: ZeitControl
Serial number ....: 000046F1
Name of cardholder: &lt;snip&gt;
Language prefs ...: nl
Salutation .......: Mr.
URL of public key : &lt;snip&gt;
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: xxxxxxx xxxxxxx xxxxxxx
Max. PIN lengths .: 32 32 32
PIN retry counter : 3 0 3
Signature counter : 80
Signature key ....: &lt;snip&gt;
      created ....: &lt;snip&gt;
Encryption key....: &lt;snip&gt;
      created ....: &lt;snip&gt;
Authentication key: &lt;snip&gt;
      created ....: &lt;snip&gt;
General key info..: [none]
[staf@monty ~/.gnupg]$ 
</code></pre></div></div>

<h1 id="test">Test</h1>

<h2 id="shadow-private-keys">shadow private keys</h2>

<p>After you executed <code class="language-plaintext highlighter-rouge">gpg --card-status</code>, GnuPG created “shadow private keys”. These keys just contain references on which hardware tokens the private keys are stored.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@monty ~/.gnupg]$ ls -l private-keys-v1.d/
total 14
-rw-------  1 staf staf 976 Mar 24 11:35 &lt;snip&gt;.key
-rw-------  1 staf staf 976 Mar 24 11:35 &lt;snip&gt;.key
-rw-------  1 staf staf 976 Mar 24 11:35 &lt;snip&gt;.key
[staf@monty ~/.gnupg]$ 
</code></pre></div></div>

<p>You can list the (shadow) private keys with the <code class="language-plaintext highlighter-rouge">gpg --list-secret-keys</code> command.</p>

<h2 id="pinentry">Pinentry</h2>

<p>To be able to type in your PIN code, you’ll need a <code class="language-plaintext highlighter-rouge">pinentry</code> application unless your smartcard reader has a pinpad.</p>

<p>You can use <code class="language-plaintext highlighter-rouge">pkg provides</code> to verify which <code class="language-plaintext highlighter-rouge">pinentry</code> applications are available.</p>

<p>For the integration with Thunderbird, you probably want to have a graphical-enabled version. But this is the topic for a next blog post ;-)</p>

<p>We’ll stick with the (n)curses version for now.</p>

<p>Install a <code class="language-plaintext highlighter-rouge">pinentry</code> program.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@monty ~/.gnupg]$ pkg provides pinentry | grep -i curses
Name    : pinentry-curses-1.3.1
Comment : Curses version of the GnuPG password dialog
Filename: usr/local/bin/pinentry-curses
[staf@monty ~/.gnupg]$ 
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@monty ~/.gnupg]$ sudo pkg install pinentry-curses
Password:
Updating FreeBSD repository catalogue...
FreeBSD repository is up to date.
All repositories are up to date.
Checking integrity... done (0 conflicting)
The most recent versions of packages are already installed
[staf@monty ~/.gnupg]$ 
</code></pre></div></div>

<p>A soft link is created for the pinentry binary.
On FreeBSD, the <code class="language-plaintext highlighter-rouge">pinentry</code> soft link is managed by the <a href="https://www.freshports.org/security/pinentry">pinentry package</a>.</p>

<p>You can verify this with the <code class="language-plaintext highlighter-rouge">pkg which</code> command.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@monty ~]$ pkg which /usr/local/bin/pinentry
/usr/local/bin/pinentry was installed by package pinentry-1.3.1
[staf@monty ~]$ 
</code></pre></div></div>

<p>The curses version is the default.</p>

<p>If you want to use another pinentry version in the <code class="language-plaintext highlighter-rouge">gpg-agent</code> configuration ( <code class="language-plaintext highlighter-rouge">$HOME/.gnupg/gpg-agent.conf</code>).</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pinentry-program &lt;PATH&gt;
</code></pre></div></div>

<h2 id="import-your-public-key">Import your public key</h2>

<p>Import your public key.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@monty /tmp]$ gpg --import &lt;snip&gt;.asc
gpg: key &lt;snip&gt;: public key "&lt;snip&gt;" imported
gpg: Total number processed: 1
gpg:               imported: 1
[staf@monty /tmp]$ 
</code></pre></div></div>

<p>List the public keys.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@monty /tmp]$ gpg --list-keys
/home/staf/.gnupg/pubring.kbx
-----------------------------
pub   XXXXXXX XXXX-XX-XX [SC]
      &lt;snip&gt;
uid           [ unknown] &lt;snip&gt;
sub   XXXXXXX XXXX-XX-XX [A]
sub   XXXXXXX XXXX-XX-XX [E]

[staf@monty /tmp]$ 
</code></pre></div></div>

<p>As a test, we try to sign something with the private key on our GnuPG smartcard.</p>

<p>Create a test file.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@monty /tmp]$ echo "foobar" &gt; foobar
[staf@monty /tmp]$ 
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@monty /tmp]$ gpg --sign foobar
</code></pre></div></div>

<p>If your smartcard isn’t inserted GnuPG will ask to insert it.</p>

<p>GnuPG asks for the smartcard with the serial in the shadow private key.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
                ┌────────────────────────────────────────────┐
                │ Please insert the card with serial number: │
                │                                            │
                │ XXXX XXXXXXXX                              │
                │                                            │
                │                                            │
                │      &lt;OK&gt;                      &lt;Cancel&gt;    │
                └────────────────────────────────────────────┘


</code></pre></div></div>

<p>Type in your PIN code.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>

               ┌──────────────────────────────────────────────┐
               │ Please unlock the card                       │
               │                                              │
               │ Number: XXXX XXXXXXXX                        │
               │ Holder: XXXX XXXXXXXXXX                      │
               │ Counter: XX                                  │
               │                                              │
               │ PIN ________________________________________ │
               │                                              │
               │      &lt;OK&gt;                        &lt;Cancel&gt;    │
               └──────────────────────────────────────────────┘


</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@monty /tmp]$ ls -l foobar*
-rw-r-----  1 staf wheel   7 Jul 27 11:11 foobar
-rw-r-----  1 staf wheel 481 Jul 27 11:17 foobar.gpg
[staf@monty /tmp]$ 
</code></pre></div></div>

<p>In a next blog post in this series, we’ll configure Thunderbird to use the smartcard for OpenPG email encryption.</p>

<p><strong><em>Have fun!</em></strong></p>

<h1 id="links">Links</h1>

<ul>
  <li><a href="https://vermaden.wordpress.com/2019/01/17/less-known-pkg8-features/">https://vermaden.wordpress.com/2019/01/17/less-known-pkg8-features/</a></li>
  <li><a href="https://www.floss-shop.de/en/security-privacy/smartcards/13/openpgp-smart-card-v3.4?c=11">https://www.floss-shop.de/en/security-privacy/smartcards/13/openpgp-smart-card-v3.4?c=11</a></li>
  <li><a href="https://www.gnupg.org/howtos/card-howto/en/smartcard-howto-single.html">https://www.gnupg.org/howtos/card-howto/en/smartcard-howto-single.html</a></li>
  <li><a href="https://support.nitrokey.com/t/nk3-mini-gpg-selecting-card-failed-no-such-device-gpg-card-setup/5057/7">https://support.nitrokey.com/t/nk3-mini-gpg-selecting-card-failed-no-such-device-gpg-card-setup/5057/7</a></li>
  <li><a href="https://security.stackexchange.com/questions/233916/gnupg-connecting-to-specific-card-reader-when-multiple-reader-available#233918">https://security.stackexchange.com/questions/233916/gnupg-connecting-to-specific-card-reader-when-multiple-reader-available#233918</a></li>
  <li><a href="https://www.fsij.org/doc-gnuk/stop-scdaemon.html">https://www.fsij.org/doc-gnuk/stop-scdaemon.html</a></li>
  <li><a href="https://wiki.debian.org/Smartcards">https://wiki.debian.org/Smartcards</a></li>
  <li><a href="https://github.com/OpenSC/OpenSC/wiki/Overview/c70c57c1811f54fe3b3989d01708b45b86fafe11">https://github.com/OpenSC/OpenSC/wiki/Overview/c70c57c1811f54fe3b3989d01708b45b86fafe11</a></li>
  <li><a href="https://superuser.com/questions/1693289/gpg-warning-not-using-as-default-key-no-secret-key">https://superuser.com/questions/1693289/gpg-warning-not-using-as-default-key-no-secret-key</a></li>
  <li><a href="https://stackoverflow.com/questions/46689885/how-to-get-public-key-from-an-openpgp-smart-card-without-using-key-servers">https://stackoverflow.com/questions/46689885/how-to-get-public-key-from-an-openpgp-smart-card-without-using-key-servers</a></li>
</ul>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[www.wagemakers.be]]></title>
    <link href="https://stafwag.github.io/blog/blog/2024/05/30/wagemakers.be/"/>
    <updated>2024-05-30T07:45:00+00:00</updated>
    <id>https://stafwag.github.io/blog/blog/2024/05/30/wagemakers.be</id>
    <content type="html"><![CDATA[<p><a href="https://stafwag.github.io/blog/images/wagemakers.be/wagemakers.be_vierkant.png"><img src="https://stafwag.github.io/blog/images/wagemakers.be/wagemakers.be_vierkant.png" class="right" width="400" height="300" alt="www.wagemakers.be vierkant" /> </a></p>

<p><a href="https://www.wagemakers.be">https://www.wagemakers.be</a></p>

<p>I’ve finally found the time to give my homepage a complete makeover. Yes, HTTPS is enabled now ;-)</p>

<p>The content has been migrated from <a href="https://en.wikipedia.org/wiki/WebGUI">WebGUI</a> to <a href="https://gohugo.io/">Hugo</a>.</p>

<p>It still contains the same old content, but I’ll update it in the coming weeks or when some of the projects are updated.</p>

<p><br />
<br />
<br />
<!--more--></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Mask27.dev]]></title>
    <link href="https://stafwag.github.io/blog/blog/2024/05/20/mask27.dev/"/>
    <updated>2024-05-20T06:45:00+00:00</updated>
    <id>https://stafwag.github.io/blog/blog/2024/05/20/mask27.dev</id>
    <content type="html"><![CDATA[<p><a href="https://stafwag.github.io/blog/images/mask27/mask27_vierkant.png"><img src="https://stafwag.github.io/blog/images/mask27/mask27_vierkant.png" class="left" width="400" height="300" alt="Mask27.dev" /> </a>
I started my company last year and recently had the time to create my company’s website.</p>

<p><a href="https://mask27.dev">https://mask27.dev</a></p>

<p>Feel free to check it out.</p>

<p><br />
<br />
<br /></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Use a GPG smartcard with Thunderbird. Part 1: setup GnuPG]]></title>
    <link href="https://stafwag.github.io/blog/blog/2024/04/21/use-a-gpg-smartcard-with-thunderbird-part_1-setup-gpg/"/>
    <updated>2024-04-21T06:45:00+00:00</updated>
    <id>https://stafwag.github.io/blog/blog/2024/04/21/use-a-gpg-smartcard-with-thunderbird-part_1-setup-gpg</id>
    <content type="html"><![CDATA[<p>I use a <a href="https://fsfe.org/">Free Software Foundation Europe</a> fellowship GPG smartcard for my email encryption and package signing. While FSFE doesn’t provide the smartcard anymore it’s still available at <a href="https://www.floss-shop.de/en/security-privacy/smartcards/13/openpgp-smart-card-v3.4?c=11">www.floss-shop.de</a>.</p>

<p><a href="https://stafwag.github.io/blog/images/gpg/gpg_smartcard_with_readers.jpg"><img src="https://stafwag.github.io/blog/images/gpg/gpg_smartcard_with_readers.jpg" class="left" width="500" height="333" alt="gpg smartcard readers" /> </a></p>

<p>I moved to a Thinkpad w541 with <a href="https://www.coreboot.org">coreboot</a> running Debian GNU/Linux and FreeBSD so I needed to set up my email encryption on <a href="https://www.thunderbird.net/en-US/">Thunderbird</a> again.</p>

<p>It took me more time to reconfigure it again - as usual - so I decided to take notes this time and create a blog post about it. As this might be useful for somebody else … or me in the future :-)</p>

<p>The setup is executed on Debian GNU/Linux 12 (bookworm) with the FSFE fellowship GPG smartcard, but the setup for other Linux distributes, FreeBSD or other smartcards is very similar.</p>

<!--more-->

<h1 id="umask">umask</h1>

<p>When you’re working on privacy-related tasks - like email encryption - it’s recommended to set the <code class="language-plaintext highlighter-rouge">umask</code> to a more private setting to only allow the user to read the generated files.</p>

<p>This is also recommended in most security benchmarks for “interactive users”.</p>

<p><code class="language-plaintext highlighter-rouge">umask 27</code> is a good default as it allows only users that are in the same group to read the generated files. Only the user that generated the file can modify it. This should be the default IMHO, but for historical reasons, <code class="language-plaintext highlighter-rouge">umask 022</code> is the default on most Un!x or alike systems.</p>

<p>On most modern Un!x systems the default group for the user is the same as the user name. If you really want to be sure that only the user can read the generated files you can also use <code class="language-plaintext highlighter-rouge">umask 077</code>.</p>

<p>Set the <code class="language-plaintext highlighter-rouge">umask</code> to something more secure as the default. You probably want to configure it in your <code class="language-plaintext highlighter-rouge">~/.profile</code> or <code class="language-plaintext highlighter-rouge">~/.bashrc</code> ( if you’re using <code class="language-plaintext highlighter-rouge">bash</code>) or configure this on the system level for the <code class="language-plaintext highlighter-rouge">UID</code> range that is assigned to “interactive users”.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ umask 27
</code></pre></div></div>

<p>Verify.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ umask
0027
$
</code></pre></div></div>

<h1 id="install-gnupg">Install GnuPG</h1>

<p>Smartcards are supported by GnuPG by <a href="https://www.gnupg.org/(en)/documentation/manuals/gnupg24/scdaemon.1.html">scdaemon</a>, it should be possible to use the <a href="https://www.gnupg.org/howtos/card-howto/en/ch02s03.html">native GnuPG CCID(Chip Card Interface)</a> driver with more recent versions of GnuPG or the <a href="https://github.com/OpenSC/OpenSC/wiki">OpenSC</a> PC/SC interface.</p>

<p><a href="https://stafwag.github.io/blog/images/gpg/logo-gnupg-light-white-bg.png"><img src="https://stafwag.github.io/blog/images/gpg/logo-gnupg-light-white-bg.png" class="right" width="356" height="120" alt="gpg logo" /> </a></p>

<p>For the native GnuPG <a href="https://en.wikipedia.org/wiki/CCID_(protocol)">CCID</a> interface you’ll need a supported smartcard reader. I continue to use the OpenSC PC/SC method, which implements the <a href="https://en.wikipedia.org/wiki/PKCS_11">PKCS11</a> interface - the defacto standard interface for smartcards or <a href="https://en.wikipedia.org/wiki/Hardware_security_module">HSMs - Hardware Security modules</a>  - and supports more smartcard readers.</p>

<p>The PKCS11 interface also allows you to reuse your PGP keypair for other things like SSH authentication through the PKCS11 interface ( SSH support is also possible with the <code class="language-plaintext highlighter-rouge">gpg-agent</code> ) or other applications like web browsers.</p>

<p>On Debian GNU/Linux, <code class="language-plaintext highlighter-rouge">scdaemon</code> is a separate package.</p>

<p>Make sure that the <code class="language-plaintext highlighter-rouge">gpg</code> and <code class="language-plaintext highlighter-rouge">scdaemon</code> are installed.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo apt install gpg scdaemon
</code></pre></div></div>

<h1 id="gpg-components">GPG components</h1>

<p>GnuPG has a few components, to list the components you can execute the <code class="language-plaintext highlighter-rouge">gpgconf --list-components</code> command.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ gpgconf --list-component
gpg:OpenPGP:/usr/bin/gpg
gpgsm:S/MIME:/usr/bin/gpgsm
gpg-agent:Private Keys:/usr/bin/gpg-agent
scdaemon:Smartcards:/usr/lib/gnupg/scdaemon
dirmngr:Network:/usr/bin/dirmngr
pinentry:Passphrase Entry:/usr/bin/pinentry
</code></pre></div></div>

<p>If you want to know in more detail what the function is for a certain component you can check the manpages for each component.</p>

<p>We use in the:</p>

<ul>
  <li><strong>scdaemon</strong>: Smartcard daemon for the GnuPG system</li>
  <li><strong>gpg-agent</strong>: Secret key management for GnuPG</li>
</ul>

<p>components in this blog post as they are involved in OpenPGP encryption.</p>

<p>To reload the configuration of all components you execute the <code class="language-plaintext highlighter-rouge">gpgconf --reload</code> command. To reload you can execute <code class="language-plaintext highlighter-rouge">gpgconf --reload &lt;component&gt;</code>.</p>

<p>e.g.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ gpgconf --reload scdaemon
</code></pre></div></div>

<p>Will reload the configuration of the <code class="language-plaintext highlighter-rouge">scdaemon</code>.</p>

<p>When you want or need to stop a <code class="language-plaintext highlighter-rouge">gpg</code> process you can use the <code class="language-plaintext highlighter-rouge">gpgconf --kill &lt;component&gt;</code> command.</p>

<p>e.g.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ gpgconf --kill scdaemon
</code></pre></div></div>

<p>Will kill the <code class="language-plaintext highlighter-rouge">scdaemon</code> process.</p>

<h1 id="try-to-find-your-smartcard-device">(Try to) Find your smartcard device</h1>

<p>Make sure that the reader is connected to your system.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 003: ID 08e6:3438 Gemalto (was Gemplus) GemPC Key SmartCard Reader
Bus 001 Device 002: ID 0627:0001 Adomax Technology Co., Ltd QEMU Tablet
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
$ 
</code></pre></div></div>

<h2 id="without-config">Without config</h2>

<p>Let’s see if <code class="language-plaintext highlighter-rouge">gpg</code> can detect the smartcard.</p>

<p>Execute <code class="language-plaintext highlighter-rouge">gpg --card-status</code>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ gpg --card-status
gpg: selecting card failed: No such device
gpg: OpenPGP card not available: No such device
$ 
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">gpg</code> doesn’t detect the smartcard…</p>

<p>When you execute the <code class="language-plaintext highlighter-rouge">gpg</code> command the <code class="language-plaintext highlighter-rouge">gpg-agent</code> is started.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ ps aux | grep -i gpg
avahi        540  0.0  0.0   8288  3976 ?        Ss   Apr05   0:00 avahi-daemon: running [debian-gpg.local]
staf         869  0.0  0.0  81256  3648 ?        SLs  Apr05   0:00 /usr/bin/gpg-agent --supervised
staf        5143  0.0  0.0   6332  2076 pts/1    S+   12:48   0:00 grep -i gpg
$ 
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">gpg-agent</code> also starts the <code class="language-plaintext highlighter-rouge">scdaemon</code> process.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ ps aux | grep -i scdaemon
staf        5150  0.0  0.1  90116  5932 ?        SLl  12:49   0:00 scdaemon --multi-server
staf        5158  0.0  0.0   6332  2056 pts/1    S+   12:49   0:00 grep -i scdaemon
$ 
</code></pre></div></div>

<p>When it’s the first time that you started <code class="language-plaintext highlighter-rouge">gpg</code> it’ll create a <code class="language-plaintext highlighter-rouge">~/.gnupg</code> directory.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>staf@debian-gpg:~/.gnupg$ ls
private-keys-v1.d  pubring.kbx
staf@debian-gpg:~/.gnupg$ 
</code></pre></div></div>

<h2 id="add-debug-info">Add debug info</h2>

<h3 id="scdaemon">scdaemon</h3>

<p>To debug why GPG doesn’t detect the smartcard, we’ll enable debug logging in the <code class="language-plaintext highlighter-rouge">scdeamon</code>.</p>

<p>Create a directory for the logging.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ mkdir ~/logs
$ chmod 700 ~/logs
</code></pre></div></div>

<p>Edit <code class="language-plaintext highlighter-rouge">~/gnugpg/scdaemon.conf</code> to reconfigure the <code class="language-plaintext highlighter-rouge">scdaemon</code> to create logging.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>staf@debian-gpg:~/.gnupg$ cat scdaemon.conf
verbose
debug-level expert
debug-all
log-file    /home/staf/logs/scdaemon.log
staf@debian-gpg:~/.gnupg$ 
</code></pre></div></div>

<p>Stop the <code class="language-plaintext highlighter-rouge">sdaemon</code> process.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>staf@debian-gpg:~/logs$ gpgconf --reload scdaemon
staf@debian-gpg:~/logs$ 
</code></pre></div></div>

<p>Verify.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ ps aux | grep -i scdaemon
staf        5169  0.0  0.0   6332  2224 pts/1    S+   12:51   0:00 grep -i scdaemon
$ 
</code></pre></div></div>

<p>The next time you execute a <code class="language-plaintext highlighter-rouge">gpg</code> command, the <code class="language-plaintext highlighter-rouge">scdaemon</code> is restarted.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ gpg --card-status
gpg: selecting card failed: No such device
gpg: OpenPGP card not available: No such device
$ 
</code></pre></div></div>

<p>With the new config, the <code class="language-plaintext highlighter-rouge">scdaemon</code> creates a log file with debug info.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>]$ ls -l ~/logs
total 8
-rw-r--r-- 1 staf staf 1425 Apr 15 19:45 scdaemon.log
$ 
</code></pre></div></div>

<h3 id="gpg-agent">gpg-agent</h3>

<p>We’ll configure the gpg-agent to generate a debug log as this might help to debug
if something goes wrong.</p>

<p>Open the <code class="language-plaintext highlighter-rouge">gpg-agent.conf</code> configuration file with your favourite editor.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>staf@bunny:~/.gnupg$ vi gpg-agent.conf
</code></pre></div></div>

<p>And set the <code class="language-plaintext highlighter-rouge">debug-level</code> and the log output file.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>debug-level expert
verbose
verbose 
log-file /home/staf/logs/gpg-agent.log
</code></pre></div></div>

<p>Reload the <code class="language-plaintext highlighter-rouge">gpg-agent</code> configuration.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>staf@bunny:~/.gnupg$ gpgconf --reload gpg-agent
staf@bunny:~/.gnupg$ 
</code></pre></div></div>

<p>Verify that a <code class="language-plaintext highlighter-rouge">log-file</code> is created.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>staf@bunny:~/.gnupg$ ls ~/logs/
gpg-agent.log  scdaemon.log
staf@bunny:~/.gnupg$ 
</code></pre></div></div>

<p>The main components are configured to generate debug info now.
We’ll continue with the <code class="language-plaintext highlighter-rouge">gpg</code> configuration.</p>

<h1 id="setup-opensc">Setup opensc</h1>

<p>We will use <code class="language-plaintext highlighter-rouge">opensc</code> to configure the smartcard interface.</p>

<p><a href="https://stafwag.github.io/blog/images/opensc/opensc_logo.png"><img src="https://stafwag.github.io/blog/images/opensc/opensc_logo.png" class="left" width="200" height="200" alt="opensc" /> </a></p>

<h2 id="install-apt-file">Install apt-file</h2>

<p>To find the required files/libraries, it can be handy to have <a href="https://wiki.debian.org/apt-file">apt-file</a> on our system.</p>

<p>Install <code class="language-plaintext highlighter-rouge">apt-file</code>.</p>

<p><br /></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo apt install apt-file
</code></pre></div></div>

<p>Update the <code class="language-plaintext highlighter-rouge">apt-file</code> database.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo apt-file update
</code></pre></div></div>

<p>Search for the tools that will be required.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ apt-file search pcsc_scan 
pcsc-tools: /usr/bin/pcsc_scan            
pcsc-tools: /usr/share/man/man1/pcsc_scan.1.gz
$ 
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ apt-file search pkcs15-tool
opensc: /usr/bin/pkcs15-tool              
opensc: /usr/share/bash-completion/completions/pkcs15-tool
opensc: /usr/share/man/man1/pkcs15-tool.1.gz
$ 
</code></pre></div></div>

<h2 id="install-smartcard-packages">Install smartcard packages</h2>

<p>Install the required packages.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo apt install opensc pcsc-tools
</code></pre></div></div>

<h2 id="start-the-pcscdservice">Start the pcscd.service</h2>

<p>On Debian GNU/Linux the services are normally automatically enabled/started when a package is installed.</p>

<p>But the <code class="language-plaintext highlighter-rouge">pcscd</code> service wasn’t enabled on my system.</p>

<p>Let’s enable it.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo systemctl enable pcscd.service 
Synchronizing state of pcscd.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install enable pcscd
$ 
</code></pre></div></div>

<p>Start it.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo systemctl start pcscd.service 
</code></pre></div></div>

<p>And verify that it’s running.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo systemctl status pcscd.service 
● pcscd.service - PC/SC Smart Card Daemon
     Loaded: loaded (/lib/systemd/system/pcscd.service; indirect; preset: enabled)
     Active: active (running) since Tue 2024-04-16 07:47:50 CEST; 16min ago
TriggeredBy: ● pcscd.socket
       Docs: man:pcscd(8)
   Main PID: 8321 (pcscd)
      Tasks: 7 (limit: 19026)
     Memory: 1.5M
        CPU: 125ms
     CGroup: /system.slice/pcscd.service
             └─8321 /usr/sbin/pcscd --foreground --auto-exit

Apr 16 07:47:50 bunny systemd[1]: Started pcscd.service - PC/SC Smart Card Daemon.
</code></pre></div></div>

<h2 id="verify-connection">Verify connection</h2>

<p>Execute the <code class="language-plaintext highlighter-rouge">pcsc_scan</code> command and insert your smartcard.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ pcsc_scan
PC/SC device scanner
V 1.6.2 (c) 2001-2022, Ludovic Rousseau &lt;ludovic.rousseau@free.fr&gt;
Using reader plug'n play mechanism
Scanning present readers...
0: Alcor Micro AU9540 00 00
 
Tue Apr 16 08:05:26 2024
 Reader 0: Alcor Micro AU9540 00 00
  Event number: 0
  Card state: Card removed, 
 Scanning present readers...
0: Alcor Micro AU9540 00 00
1: Gemalto USB Shell Token V2 (284C3E93) 01 00
 
Tue Apr 16 08:05:50 2024
 Reader 0: Alcor Micro AU9540 00 00
  Event number: 0
  Card state: Card removed, 
 Reader 1: Gemalto USB Shell Token V2 (284C3E93) 01 00
  Event number: 0
  Card state: Card inserted, 
  ATR: &lt;snip&gt;

ATR: &lt;snip&gt;
+ TS = 3B --&gt; Direct Convention
+ T0 = DA, Y(1): 1101, K: 10 (historical bytes)
&lt;snip&gt;
+ TCK = 0C (correct checksum)
&lt;snip&gt;

Possibly identified card (using /usr/share/pcsc/smartcard_list.txt):
&lt;snip&gt;
	OpenPGP Card V2
$ 
</code></pre></div></div>

<p>Execute <code class="language-plaintext highlighter-rouge">pkcs15-tool -D</code> to ensure that the pkcs11/pkcs15 interface is working.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ pkcs15-tool -D
Using reader with a card: Gemalto USB Shell Token V2 (284C3E93) 00 00
PKCS#15 Card [OpenPGP card]:
	Version        : 0
	Serial number  : &lt;snip&gt;
	Manufacturer ID: ZeitControl
	Language       : nl
	Flags          : PRN generation, EID compliant


PIN [User PIN]
	Object Flags   : [0x03], private, modifiable
	Auth ID        : 03
	ID             : 02
	Flags          : [0x13], case-sensitive, local, initialized
	Length         : min_len:6, max_len:32, stored_len:32
	Pad char       : 0x00
	Reference      : 2 (0x02)
	Type           : UTF-8
	Path           : 3f00
	Tries left     : 3

PIN [User PIN (sig)]
	Object Flags   : [0x03], private, modifiable
	Auth ID        : 03
	ID             : 01
	Flags          : [0x13], case-sensitive, local, initialized
	Length         : min_len:6, max_len:32, stored_len:32
	Pad char       : 0x00
	Reference      : 1 (0x01)
	Type           : UTF-8
	Path           : 3f00
	Tries left     : 3

PIN [Admin PIN]
	Object Flags   : [0x03], private, modifiable
	ID             : 03
	Flags          : [0x9B], case-sensitive, local, unblock-disabled, initialized, soPin
	Length         : min_len:8, max_len:32, stored_len:32
	Pad char       : 0x00
	Reference      : 3 (0x03)
	Type           : UTF-8
	Path           : 3f00
	Tries left     : 3

Private RSA Key [Signature key]
	Object Flags   : [0x03], private, modifiable
	Usage          : [0x20C], sign, signRecover, nonRepudiation
	Access Flags   : [0x1D], sensitive, alwaysSensitive, neverExtract, local
	Algo_refs      : 0
	ModLength      : 3072
	Key ref        : 0 (0x00)
	Native         : yes
	Auth ID        : 01
	ID             : 01
	MD:guid        : &lt;snip&gt;

Private RSA Key [Encryption key]
	Object Flags   : [0x03], private, modifiable
	Usage          : [0x22], decrypt, unwrap
	Access Flags   : [0x1D], sensitive, alwaysSensitive, neverExtract, local
	Algo_refs      : 0
	ModLength      : 3072
	Key ref        : 1 (0x01)
	Native         : yes
	Auth ID        : 02
	ID             : 02
	MD:guid        : &lt;snip&gt;

Private RSA Key [Authentication key]
	Object Flags   : [0x03], private, modifiable
	Usage          : [0x222], decrypt, unwrap, nonRepudiation
	Access Flags   : [0x1D], sensitive, alwaysSensitive, neverExtract, local
	Algo_refs      : 0
	ModLength      : 3072
	Key ref        : 2 (0x02)
	Native         : yes
	Auth ID        : 02
	ID             : 03
	MD:guid        : &lt;snip&gt;

Public RSA Key [Signature key]
	Object Flags   : [0x02], modifiable
	Usage          : [0xC0], verify, verifyRecover
	Access Flags   : [0x02], extract
	ModLength      : &lt;snip&gt;
	Key ref        : 0 (0x00)
	Native         : no
	Path           : b601
	ID             : 01

Public RSA Key [Encryption key]
	Object Flags   : [0x02], modifiable
	Usage          : [0x11], encrypt, wrap
	Access Flags   : [0x02], extract
	ModLength      : &lt;snip&gt;
	Key ref        : 0 (0x00)
	Native         : no
	Path           : b801
	ID             : 02

Public RSA Key [Authentication key]
	Object Flags   : [0x02], modifiable
	Usage          : [0x51], encrypt, wrap, verify
	Access Flags   : [0x02], extract
	ModLength      : &lt;snip&gt;
	Key ref        : 0 (0x00)
	Native         : no
	Path           : a401
	ID             : 03

$ 
</code></pre></div></div>

<p>You might want to reinsert your smartcard after you execute <code class="language-plaintext highlighter-rouge">pkcs15-tool</code> or <code class="language-plaintext highlighter-rouge">pkcs11-tool</code> commands, as still this might lock
the smartcard that generates a <strong>sharing violation (0x8010000b)</strong> error (see below).</p>

<h1 id="gnupg-configuration">GnuPG configuration</h1>

<h2 id="scdaemon-1">scdaemon</h2>

<p>The first step is to get the smartcard detected by <code class="language-plaintext highlighter-rouge">gpg</code> (<code class="language-plaintext highlighter-rouge">scdaemon</code>).</p>

<h3 id="test">Test</h3>

<p>Execute <code class="language-plaintext highlighter-rouge">gpg --card-status</code> to verify that your smartcard is detected by <code class="language-plaintext highlighter-rouge">gpg</code>.
This might work as <code class="language-plaintext highlighter-rouge">gpg</code> will try to use the internal CCID if this fails it will try
to use the <code class="language-plaintext highlighter-rouge">opensc</code> interface.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ gpg --card-status
gpg: selecting card failed: No such device
gpg: OpenPGP card not available: No such device
$ 
</code></pre></div></div>

<p>When the smartcard doesn’t get detected, have a look at the <code class="language-plaintext highlighter-rouge">~/logs/scdaemon.log</code> log file.</p>

<h3 id="disable-the-internal-ccid">Disable the internal ccid</h3>

<p>When you use a smartcard reader that isn’t supported by GnuPG or you want to force GnuPG to use the <code class="language-plaintext highlighter-rouge">opensc</code> interface it’s a good idea to disable the internal ccid.</p>

<p>Edit <code class="language-plaintext highlighter-rouge">scdaemon.conf</code>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>staf@bunny:~/.gnupg$ vi scdaemon.conf
staf@bunny:~/.gnupg$
</code></pre></div></div>

<p>and add <code class="language-plaintext highlighter-rouge">disable-ccid</code>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>card-timeout 5
disable-ccid

verbose
debug-level expert
debug-all
log-file    /home/staf/logs/scdaemon.log
</code></pre></div></div>

<p>Reload the <code class="language-plaintext highlighter-rouge">scdaemon</code>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>staf@bunny:~/.gnupg$ gpgconf --reload scdaemon
staf@bunny:~/.gnupg$ 
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">gpg</code> will try to use the <code class="language-plaintext highlighter-rouge">opensc</code> as a failback by default, so disabling the internal CCI interface will probably not fix the issue when your smartcard isn’t detected.</p>

<h3 id="multiple-smartcard-readers">multiple smartcard readers</h3>

<p>When you have multiple smartcard readers on your system. e.g. an internal and other one connected over USB. <code class="language-plaintext highlighter-rouge">gpg</code> might only use the first smartcard reader.</p>

<p>Check the <code class="language-plaintext highlighter-rouge">scdaemon.log</code> to get the <code class="language-plaintext highlighter-rouge">reader port</code> for your smartcard reader.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>staf@bunny:~/logs$ tail -f scdaemon.log 
2024-04-14 11:39:35 scdaemon[471388] DBG: chan_7 -&gt; D 2.2.40
2024-04-14 11:39:35 scdaemon[471388] DBG: chan_7 -&gt; OK
2024-04-14 11:39:35 scdaemon[471388] DBG: chan_7 &lt;- SERIALNO
2024-04-14 11:39:35 scdaemon[471388] detected reader 'Alcor Micro AU9540 00 00'
2024-04-14 11:39:35 scdaemon[471388] detected reader 'Gemalto USB Shell Token V2 (284C3E93) 01 00'
2024-04-14 11:39:35 scdaemon[471388] reader slot 0: not connected
2024-04-14 11:39:35 scdaemon[471388] reader slot 0: not connected
2024-04-14 11:39:35 scdaemon[471388] DBG: chan_7 -&gt; ERR 100696144 No such device &lt;SCD&gt;
2024-04-14 11:39:35 scdaemon[471388] DBG: chan_7 &lt;- RESTART
2024-04-14 11:39:35 scdaemon[471388] DBG: chan_7 -&gt; OK
</code></pre></div></div>

<p>To force <code class="language-plaintext highlighter-rouge">gpg</code> to use a smartcard reader you can set the <code class="language-plaintext highlighter-rouge">reader-port</code> directive in the <code class="language-plaintext highlighter-rouge">scdaemon.conf</code>
configuration file.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>staf@bunny:~/.gnupg$ vi scdaemon.conf
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>card-timeout 5
disable-ccid

reader-port 'Gemalto USB Shell Token V2 (284C3E93) 01 00'

verbose
debug-level expert
debug-all
log-file    /home/staf/logs/scdaemon.log
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>staf@bunny:~$ gpgconf --reload scdaemon
staf@bunny:~$
</code></pre></div></div>

<h3 id="sharing-violation-0x8010000b">sharing violation (0x8010000b)</h3>

<p>Applications will try to lock your <code class="language-plaintext highlighter-rouge">opensc</code> smartcard, if your smartcard is already in use by another application you might get a <code class="language-plaintext highlighter-rouge">sharing violation (0x8010000b)</code>.</p>

<p>This is fixed by reinserting your smartcard. If this doesn’t help it might be a good idea to 
restart the <code class="language-plaintext highlighter-rouge">pcscd</code> service as this disconnects all the applications that might lock 
the <code class="language-plaintext highlighter-rouge">opensc</code> interface.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo systemctl restart pcscd
</code></pre></div></div>

<p>When everything goes well your smartcard should be detected now. If not, take a look at the <code class="language-plaintext highlighter-rouge">scdaemon.log</code> .</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>staf@bunny:~$ gpg --card-status
Reader ...........: Gemalto USB Shell Token V2 (284C3E93) 00 00
Application ID ...: &lt;snip&gt;
Application type .: OpenPGP
Version ..........: 2.1
Manufacturer .....: ZeitControl
Serial number ....: 000046F1
Name of cardholder: &lt;snip&gt;
Language prefs ...: &lt;snip&gt;
Salutation .......: &lt;snip&gt;
URL of public key : &lt;snip&gt;
Login data .......: [not set]
Signature PIN ....: &lt;snip&gt;
Key attributes ...: &lt;snip&gt;
Max. PIN lengths .: &lt;snip&gt;
PIN retry counter : &lt;snip&gt;
Signature counter : &lt;snip&gt;
Signature key ....: &lt;snip&gt;
      created ....: &lt;snip&gt;
Encryption key....: &lt;snip&gt;
      created ....: &lt;snip&gt;
Authentication key: &lt;snip&gt;
      created ....: &lt;snip&gt;
General key info..: [none]
staf@bunny:~$ 
</code></pre></div></div>

<p>Note that <code class="language-plaintext highlighter-rouge">gpg</code> will lock the smartcard, if you try to use your smartcard for another application you’ll get
a “Reader in use by another application” error.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>staf@bunny:~$ pkcs15-tool -D
Using reader with a card: Gemalto USB Shell Token V2 (284C3E93) 00 00
Failed to connect to card: Reader in use by another application
staf@bunny:~$ 
</code></pre></div></div>

<h2 id="private-key-references">Private key references</h2>

<p>When you execute <code class="language-plaintext highlighter-rouge">gpg --card-status</code> successfully. <code class="language-plaintext highlighter-rouge">gpg</code> creates references (shadowed-private-keys) to the private key(s) on your smartcard.
These references are text files created in <code class="language-plaintext highlighter-rouge">~/.gnupg/private-keys-v1.d</code>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>staf@bunny:~/.gnupg/private-keys-v1.d$ ls
&lt;snip&gt;.key
&lt;snip&gt;.key
&lt;snip&gt;.key
staf@bunny:~/.gnupg/private-keys-v1.d$ 
</code></pre></div></div>

<p>These references also include the smartcard serial number, this way <code class="language-plaintext highlighter-rouge">gpg</code> knows on which hardware token the private key is located and will 
ask you to insert the correct hardware token (smartcard).</p>

<h2 id="pinentry">Pinentry</h2>

<p><code class="language-plaintext highlighter-rouge">pinentry</code> allows you to type in a passphrase (pin code) to unlock the encryption if you don’t have a smartcard reader with a PIN-pad.</p>

<p>Lets’s look for the packages that provides a <code class="language-plaintext highlighter-rouge">pinentry</code> binary.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo apt-file search "bin/pinentry"
kwalletcli: /usr/bin/pinentry-kwallet     
pinentry-curses: /usr/bin/pinentry-curses
pinentry-fltk: /usr/bin/pinentry-fltk
pinentry-gnome3: /usr/bin/pinentry-gnome3
pinentry-gtk2: /usr/bin/pinentry-gtk-2
pinentry-qt: /usr/bin/pinentry-qt
pinentry-tty: /usr/bin/pinentry-tty
pinentry-x2go: /usr/bin/pinentry-x2go
$ 
</code></pre></div></div>

<p>Install the packages.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo apt install pinentry-curses pinentry-gtk2 pinentry-gnome3 pinentry-qt
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">/bin/pinetry</code> is a soft link to the <code class="language-plaintext highlighter-rouge">pinentry</code> binary.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ which pinentry
/usr/bin/pinentry
staf@debian-gpg:/tmp$ ls -l /usr/bin/pinentry
lrwxrwxrwx 1 root root 26 Oct 18  2022 /usr/bin/pinentry -&gt; /etc/alternatives/pinentry
staf@debian-gpg:/tmp$ ls -l /etc/alternatives/pinentry
lrwxrwxrwx 1 root root 24 Mar 23 11:29 /etc/alternatives/pinentry -&gt; /usr/bin/pinentry-gnome3
$ 
</code></pre></div></div>

<p>If you want to use another <code class="language-plaintext highlighter-rouge">pinentry</code> provider you can update it with <code class="language-plaintext highlighter-rouge">update-alternatives --config pinentry</code>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo update-alternatives --config pinentry
</code></pre></div></div>

<h1 id="import-public-key">Import public key</h1>

<p>The last step is to import our public key.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ gpg --import &lt;snip&gt;.asc
gpg: key &lt;snip&gt;: "Fname Sname &lt;email&gt;" not changed
gpg: Total number processed: 1
gpg:              unchanged: 1
$
</code></pre></div></div>

<h1 id="test-1">Test</h1>

<p>Check if our public and private keys are known by GnuPG.</p>

<p>List public keys.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ gpg --list-keys
/home/staf/.gnupg/pubring.kbx
-----------------------------
pub   rsa&lt;snip&gt; &lt;snip&gt; [SC]
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
uid           [ unknown] fname sname &lt;email&gt;
sub   rsa&lt;snip&gt; &lt;snip&gt; [A]
sub   rsa&lt;snip&gt; &lt;snip&gt; [E]

$ 
</code></pre></div></div>

<p>List our private keys.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ gpg --list-secret-keys 
/home/staf/.gnupg/pubring.kbx
-----------------------------
sec&gt;  rsa&lt;size&gt; &lt;date&gt; [SC]
      XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
      Card serial no. = XXXX YYYYYYYY
uid           [ unknown] Fname Sname &lt;email&gt;
ssb&gt;  rsa&lt;size&gt; &lt;date&gt; [A]
ssb&gt;  rsa&lt;size&gt; &lt;date&gt; [E]

$ 
</code></pre></div></div>

<p>Test if we sign something with our GnuPG smartcard.</p>

<p>Create a test file.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ echo "I'm boe." &gt; /tmp/boe
$ 
</code></pre></div></div>

<p>Sign it.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ gpg --sign /tmp/boe
$ 
</code></pre></div></div>

<p>Type your PIN code.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>                ┌──────────────────────────────────────────────┐
                │ Please unlock the card                       │
                │                                              │
                │ Number: XXXX YYYYYYYY                        │
                │ Holder: first list                           │
                │ Counter: &lt;number&gt;                            │
                │                                              │
                │ PIN ________________________________________ │
                │                                              │
                │      &lt;OK&gt;                        &lt;Cancel&gt;    │
                └──────────────────────────────────────────────┘
</code></pre></div></div>

<p>In a next blog post will set up Thunderbird to use the smartcard for OpenPGP email encryption.</p>

<p><strong><em>Have fun!</em></strong></p>

<h1 id="links">Links</h1>

<ul>
  <li><a href="https://wiki.debian.org/Smartcards/OpenPGP">https://wiki.debian.org/Smartcards/OpenPGP</a></li>
  <li><a href="https://www.floss-shop.de/en/security-privacy/smartcards/13/openpgp-smart-card-v3.4?c=11">https://www.floss-shop.de/en/security-privacy/smartcards/13/openpgp-smart-card-v3.4?c=11</a></li>
  <li><a href="https://www.gnupg.org/howtos/card-howto/en/smartcard-howto-single.html">https://www.gnupg.org/howtos/card-howto/en/smartcard-howto-single.html</a></li>
  <li><a href="https://support.nitrokey.com/t/nk3-mini-gpg-selecting-card-failed-no-such-device-gpg-card-setup/5057/7">https://support.nitrokey.com/t/nk3-mini-gpg-selecting-card-failed-no-such-device-gpg-card-setup/5057/7</a></li>
  <li><a href="https://security.stackexchange.com/questions/233916/gnupg-connecting-to-specific-card-reader-when-multiple-reader-available#233918">https://security.stackexchange.com/questions/233916/gnupg-connecting-to-specific-card-reader-when-multiple-reader-available#233918</a></li>
  <li><a href="https://www.fsij.org/doc-gnuk/stop-scdaemon.html">https://www.fsij.org/doc-gnuk/stop-scdaemon.html</a></li>
  <li><a href="https://wiki.debian.org/Smartcards">https://wiki.debian.org/Smartcards</a></li>
  <li><a href="https://github.com/OpenSC/OpenSC/wiki/Overview/c70c57c1811f54fe3b3989d01708b45b86fafe11">https://github.com/OpenSC/OpenSC/wiki/Overview/c70c57c1811f54fe3b3989d01708b45b86fafe11</a></li>
  <li><a href="https://superuser.com/questions/1693289/gpg-warning-not-using-as-default-key-no-secret-key">https://superuser.com/questions/1693289/gpg-warning-not-using-as-default-key-no-secret-key</a></li>
  <li><a href="https://stackoverflow.com/questions/46689885/how-to-get-public-key-from-an-openpgp-smart-card-without-using-key-servers">https://stackoverflow.com/questions/46689885/how-to-get-public-key-from-an-openpgp-smart-card-without-using-key-servers</a></li>
</ul>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Running OpenBSD as an UEFI virtual machine (on a Raspberry Pi)]]></title>
    <link href="https://stafwag.github.io/blog/blog/2024/02/25/run-opentbsd-as-a-vm-on-pi/"/>
    <updated>2024-02-25T04:05:00+00:00</updated>
    <id>https://stafwag.github.io/blog/blog/2024/02/25/run-opentbsd-as-a-vm-on-pi</id>
    <content type="html"><![CDATA[<p>I started to migrate all the services that I use on my internal network to my <a href="https://www.raspberrypi.com/products/raspberry-pi-4-model-b/">Raspberry Pi 4</a> cluster.
I migrated my <a href="https://www.freebsd.org/">FreeBSD</a> jails to <a href="https://bastillebsd.org/">BastileBSD</a> on a virtual machine running on a Raspberry Pi. See 
my blog post on how to migrate from <a href="https://erdgeist.org/arts/software/ezjail/">ezjail</a> to BastilleBSD. <a href="https://stafwag.github.io/blog/blog/2023/09/10/migrate-from-ezjail-to-bastille-part1-introduction-to-bastillebsd/">https://stafwag.github.io/blog/blog/2023/09/10/migrate-from-ezjail-to-bastille-part1-introduction-to-bastillebsd/</a></p>

<p><a href="https://stafwag.github.io/blog/images/tianocore/logo2.png"><img src="https://stafwag.github.io/blog/images/tianocore/logo2.png" class="right" width="400" height="132" alt="tianocore" /> </a></p>

<p>Running FreeBSD as a virtual machine with UEFI on <a href="https://en.wikipedia.org/wiki/AArch64">ARM64</a> came to the point that it just works. I have to use <a href="https://www.qemu.org/">QEMU</a> with <a href="https://u-boot.org">u-boot</a> to get FreeBSD up and running on the Raspberry Pi as a virtual machine with older FreeBSD versions: <a href="https://stafwag.github.io/blog/blog/2021/03/14/howto_run_freebsd_as_vm_on_pi/">https://stafwag.github.io/blog/blog/2021/03/14/howto_run_freebsd_as_vm_on_pi/</a>.</p>

<p>But with the latest versions of FreeBSD ( not sure when it started to work, but it works on FreeBSD 14) you can run FreeBSD as a virtual machine on ARM64 with UEFI just like on <a href="https://en.wikipedia.org/wiki/X86">x86</a> on <a href="https://www.gnu.org/">GNU</a>/<a href="https://www.kernel.org/">Linux</a> with <a href="https://www.linux-kvm.org/">KVM</a>.</p>

<p>UEFI on KVM is in general provided by the open-source <a href="https://www.tianocore.org">tianocore</a> project.</p>

<p>I didn’t find much information on how to run <a href="https://www.openbsd.org/">OpenBSD</a> with UEFI on x86 or ARM64.</p>

<p><a href="https://stafwag.github.io/blog/images/openbsd/7.4/puffy74.png"><img src="https://stafwag.github.io/blog/images/openbsd/7.4/puffy74.png" class="left" width="400" height="132" alt="OpenBSD 7.4" /> </a></p>

<p>So I decided to write a blog post about it, in the hope that this information might be useful to somebody else. First I tried to download the OpenBSD 7.4 ISO image and boot
it as a virtual machine on KVM (x86). But the iso image failed to boot on a virtual with UEFI enabled. It looks like the ISO image only supports a legacy BIOS.</p>

<p>ARM64 doesn’t support a “legacy BIOS”. The ARM64 <a href="https://www.openbsd.org/faq/faq4.html#Download">download page</a> for OpenBSD 7.4 doesn’t even have an ISO image, but there is an install-&lt;version&gt;.img 
image available. So I tried to boot this image on one of my Raspberry Pi systems and this worked. I had more trouble getting <a href="https://www.netbsd.org/">NetBSD</a> working as a virtual machine on the Raspberry Pi but this might be a topic for another blog post :-)</p>

<p>You’ll find my journey with my installation instructions below.</p>

<!--more-->

<h1 id="download">Download</h1>

<h2 id="download-the-installation-image">Download the installation image</h2>

<p>Download the latest OpenBSD installation ARM64 image from: <a href="https://www.openbsd.org/faq/faq4.html#Download">https://www.openbsd.org/faq/faq4.html#Download</a></p>

<p>The complete list of the mirrors is available at <a href="https://www.openbsd.org/ftp.html">https://www.openbsd.org/ftp.html</a></p>

<p>Download the image.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@staf-pi002 openbsd]$ wget https://cdn.openbsd.org/pub/OpenBSD/7.4/arm64/install74.img
--2024-02-13 19:04:52--  https://cdn.openbsd.org/pub/OpenBSD/7.4/arm64/install74.img
Connecting to xxx.xxx.xxx.xxx:3128... connected.
Proxy request sent, awaiting response... 200 OK
Length: 528482304 (504M) [application/octet-stream]
Saving to: 'install74.img'

install74.img       100%[===================&gt;] 504.00M  3.70MB/s    in 79s     

2024-02-13 19:06:12 (6.34 MB/s) - 'install74.img' saved [528482304/528482304]

[staf@staf-pi002 openbsd]$ 
</code></pre></div></div>

<p>Download the checksum and the signed checksum.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>2024-02-13 19:06:12 (6.34 MB/s) - 'install74.img' saved [528482304/528482304]

[staf@staf-pi002 openbsd]$ wget https://cdn.openbsd.org/pub/OpenBSD/7.4/arm64/SHA256
--2024-02-13 19:07:00--  https://cdn.openbsd.org/pub/OpenBSD/7.4/arm64/SHA256
Connecting to xxx.xxx.xxx.xxx:3128... connected.
Proxy request sent, awaiting response... 200 OK
Length: 1392 (1.4K) [text/plain]
Saving to: 'SHA256'

SHA256                  100%[=============================&gt;]   1.36K  --.-KB/s    in 0s      

2024-02-13 19:07:01 (8.09 MB/s) - 'SHA256' saved [1392/1392]

[staf@staf-pi002 openbsd]$ 
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@staf-pi002 openbsd]$ wget https://cdn.openbsd.org/pub/OpenBSD/7.4/arm64/SHA256.sig
--2024-02-13 19:08:01--  https://cdn.openbsd.org/pub/OpenBSD/7.4/arm64/SHA256.sig
Connecting to xxx.xxx.xxx.xxx:3128... connected.
Proxy request sent, awaiting response... 200 OK
Length: 1544 (1.5K) [text/plain]
Saving to: 'SHA256.sig'

SHA256.sig              100%[=============================&gt;]   1.51K  --.-KB/s    in 0s      

2024-02-13 19:08:02 (3.91 MB/s) - 'SHA256.sig' saved [1544/1544]

[staf@staf-pi002 openbsd]$ 
</code></pre></div></div>

<h2 id="verify">Verify</h2>

<p>OpenBSD uses <a href="https://man.openbsd.org/signify">signify</a> to validate the cryptographic signatures. <code class="language-plaintext highlighter-rouge">signify</code> is also available for GNU/Linux (at least on Debian GNU/Linux and Arch Linux).</p>

<p>More details on how to verify the signature with signify is available at: <a href="https://www.openbsd.org/74.html">https://www.openbsd.org/74.html</a></p>

<p>This blog post was also useful: <a href="https://www.msiism.org/blog/2019/10/20/authentic_pufferfish_for_penguins.html">https://www.msiism.org/blog/2019/10/20/authentic_pufferfish_for_penguins.html</a></p>

<h3 id="install-openbsd-signify">Install OpenBSD signify</h3>

<p>Download the signify public key from: <a href="https://www.openbsd.org/74.html">https://www.openbsd.org/74.html</a></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@staf-pi002 openbsd]$ wget https://ftp.openbsd.org/pub/OpenBSD/7.4/openbsd-74-base.pub
--2024-02-13 19:14:25--  https://ftp.openbsd.org/pub/OpenBSD/7.4/openbsd-74-base.pub
Connecting to xxx.xxx.xxx.xxx:3128... connected.
Proxy request sent, awaiting response... 200 OK
Length: 99 [text/plain]
Saving to: 'openbsd-74-base.pub'

openbsd-74-base.pub     100%[=============================&gt;]      99   397 B/s    in 0.2s    

2024-02-13 19:14:26 (397 B/s) - 'openbsd-74-base.pub' saved [99/99]

[staf@staf-pi002 openbsd]$
</code></pre></div></div>

<p>I run Debian GNU/Linux on my Raspberry Pi’s, let see which <code class="language-plaintext highlighter-rouge">signify</code> packages are available.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@staf-pi002 openbsd]$ sudo apt search signify
sudo: unable to resolve host staf-pi002: Name or service not known
[sudo] password for staf: 
Sorting... Done
Full Text Search... Done
chkrootkit/stable 0.57-2+b1 arm64
  rootkit detector

elpa-diminish/stable 0.45-4 all
  hiding or abbreviation of the mode line displays of minor-modes

fcitx-sayura/stable 0.1.2-2 arm64
  Fcitx wrapper for Sayura IM engine

fcitx5-sayura/stable 5.0.8-1 arm64
  Fcitx5 wrapper for Sayura IM engine

signify/stable 1.14-7 all
  Automatic, semi-random ".signature" rotator/generator

signify-openbsd/stable 31-3 arm64
  Lightweight cryptographic signing and verifying tool

signify-openbsd-keys/stable 2022.2 all
  Public keys for use with signify-openbsd

[staf@staf-pi002 openbsd]$
</code></pre></div></div>

<p>There’re two OpenBSD signify packages available on Debian 12 (bookworm);</p>

<ul>
  <li><strong><code class="language-plaintext highlighter-rouge">signify-openbsd/</code></strong>: The OpenBSD <code class="language-plaintext highlighter-rouge">signify</code> tool.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">signify-openbsd-keys</code></strong>: This package contains the OpenBSD release public keys, installed in <code class="language-plaintext highlighter-rouge">/usr/share/signify-openbsd-keys/</code>. Unfortunately, the OpenBSD 7.4 release isn’t (yet) included in Debian 12 (bookworm).</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@staf-pi002 openbsd]$ sudo apt install signify-openbsd signify-openbsd-keys
sudo: unable to resolve host staf-pi002: Name or service not known
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following NEW packages will be installed:
  signify-openbsd signify-openbsd-keys
0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded.
Need to get 70.4 kB of archives.
After this operation, 307 kB of additional disk space will be used.
Get:1 http://deb.debian.org/debian bookworm/main arm64 signify-openbsd arm64 31-3 [62.3 kB]
Get:2 http://deb.debian.org/debian bookworm/main arm64 signify-openbsd-keys all 2022.2 [8020 B]
Fetched 70.4 kB in 0s (404 kB/s)          
Selecting previously unselected package signify-openbsd.
(Reading database ... 94575 files and directories currently installed.)
Preparing to unpack .../signify-openbsd_31-3_arm64.deb ...
Unpacking signify-openbsd (31-3) ...
Selecting previously unselected package signify-openbsd-keys.
Preparing to unpack .../signify-openbsd-keys_2022.2_all.deb ...
Unpacking signify-openbsd-keys (2022.2) ...
Setting up signify-openbsd-keys (2022.2) ...
Setting up signify-openbsd (31-3) ...
[staf@staf-pi002 openbsd]$ 
</code></pre></div></div>

<h3 id="verify-the-checksum">Verify the checksum</h3>

<p>Verify the checksum.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@staf-pi002 openbsd]$ sha256sum install74.img 
09e4d0fe6d3f49f2c4c99b6493142bb808253fa8a8615ae1ca8e5f0759cfebd8  install74.img
[staf@staf-pi002 openbsd]$ 
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@staf-pi002 openbsd]$ grep 09e4d0fe6d3f49f2c4c99b6493142bb808253fa8a8615ae1ca8e5f0759cfebd8 SHA256
SHA256 (install74.img) = 09e4d0fe6d3f49f2c4c99b6493142bb808253fa8a8615ae1ca8e5f0759cfebd8
[staf@staf-pi002 openbsd]$ 
</code></pre></div></div>

<h3 id="verify-with-signify">Verify with signify</h3>

<p>Execute the <code class="language-plaintext highlighter-rouge">signify</code> command to verify the checksum. See the <a href="https://man.openbsd.org/signify">OpenBSD signify manpage</a> for more information.</p>

<p>You’ll find a brief list of the arguments that are used to verify the authenticity of the image.</p>

<ul>
  <li><strong><code class="language-plaintext highlighter-rouge">-C</code></strong>: Will verify the <strong>C</strong>hecksum.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">-p &lt;path&gt;</code></strong>: The path to the <strong>P</strong>ublic key.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">-x &lt;path&gt;</code></strong>: The path to the signature file.</li>
</ul>

<p>Verify the image with <code class="language-plaintext highlighter-rouge">signify</code>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@staf-pi002 openbsd]$ signify-openbsd -C -p openbsd-74-base.pub -x SHA256.sig install74.img
Signature Verified
install74.img: OK
[staf@staf-pi002 openbsd]$
</code></pre></div></div>
<h1 id="secure-boot">Secure boot</h1>

<p>The Debian UEFI package for libvirt <code class="language-plaintext highlighter-rouge">ovmf</code> is based on <a href="https://github.com/tianocore/tianocore.github.io/wiki/OVMF">https://github.com/tianocore/tianocore.github.io/wiki/OVMF</a>.</p>

<p>Debian Bookworm comes with the following UEFI BIOS settings:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">/usr/share/AAVMF/AAVMF_CODE.ms.fd</code> This is with secure boot enabled.</li>
  <li><code class="language-plaintext highlighter-rouge">/usr/share/AAVMF/AAVMF_CODE.fd</code> This is without secure boot enabled.</li>
</ul>

<p>The full description is available at <code class="language-plaintext highlighter-rouge">/usr/share/doc/ovmf/README.Debian</code> on a Debian system when the <code class="language-plaintext highlighter-rouge">ovmf</code> package is installed.</p>

<p>To install OpenBSD we need to disable secure boot.</p>

<h1 id="test-boot">Test boot</h1>

<p>I first started a test boot.</p>

<p>Logon to the Raspberry Pi.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[staf@vicky ~]$ ssh -X -CCC staf-pi002 
Warning: untrusted X11 forwarding setup failed: xauth key data not generated
Linux staf-pi002 6.1.0-17-arm64 #1 SMP Debian 6.1.69-1 (2023-12-30) aarch64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Wed Feb 14 06:08:45 2024 from xxx.xxx.xxx.xxx
[staf@staf-pi002 ~]$ 
</code></pre></div></div>

<p><br /></p>

<p><a href="https://stafwag.github.io/blog/images/openbsd_vm_on_pi/000_virt_manager.png"><img src="https://stafwag.github.io/blog/images/openbsd_vm_on_pi/000_virt_manager.png" class="right" width="300" height="193" alt="virt-manager" /> </a></p>

<p><br />
<br /></p>

<p>Start <code class="language-plaintext highlighter-rouge">virt-manager</code> and click on the <strong>[ Create on new VM ]</strong> icon.</p>

<p><br />
<br /></p>

<p><a href="https://stafwag.github.io/blog/images/openbsd_vm_on_pi/001_new_vm.png"><img src="https://stafwag.github.io/blog/images/openbsd_vm_on_pi/001_new_vm.png" class="right" width="300" height="314" alt="new vm" /> </a></p>

<p><br />
<br />
<br /></p>

<p>This will bring up the new vm window. Select <strong>( ) Import existing disk image</strong>, you review the architecture option by selecting the
<strong>\/ Architecture options</strong>. The defaults are fine.  Click on <strong>[ Forward ]</strong>.</p>

<p><br />
<br />
<br />
<br />
<br /></p>

<p><a href="https://stafwag.github.io/blog/images/openbsd_vm_on_pi/002_import_vm.png"><img src="https://stafwag.github.io/blog/images/openbsd_vm_on_pi/002_import_vm.png" class="right" width="300" height="314" alt="import vm" /> </a></p>

<p><br />
<br /></p>

<p>This will open the “import vm” window. Click on <strong>[ Browse ]</strong> to select the OpenBSD installation image or just copy/paste the path.</p>

<p>At the bottom of the screen, you’ll see <strong>Choose the operating system you are installing</strong>. Starting type <code class="language-plaintext highlighter-rouge">openbsd</code> and select <strong>[ X ] include end-of-life operating systems</strong> Debian 12 (bookworm) doesn’t include support for OpenBSD 7.4 (yet) so we need to set it to “OpenBSD 7.0”. Click on <strong>[ Forward ]</strong>.</p>

<p><br />
<br />
<br />
<br /></p>

<p><a href="https://stafwag.github.io/blog/images/openbsd_vm_on_pi/003_select_custom.png"><img src="https://stafwag.github.io/blog/images/openbsd_vm_on_pi/003_select_custom.png" class="right" width="300" height="314" alt="select custom" /> </a></p>

<p><br /></p>

<p>In the next windows keep the default <strong>Memory</strong> and <strong>CPU</strong> settings as we’re just verifying that we can boot from the installation image.</p>

<p>Debian uses “secure boot” by default. We need to disable secure boot. Select <strong>[ X ] Customize configuration before install</strong>, this allows us to set the UEFI boot image.</p>

<p><br />
<br />
<br />
<br />
<br /></p>

<p><a href="https://stafwag.github.io/blog/images/openbsd_vm_on_pi/004_begin_install.png"><img src="https://stafwag.github.io/blog/images/openbsd_vm_on_pi/004_begin_install.png" class="right" width="300" height="286" alt="begin install" /> </a></p>

<p><br /></p>

<p>Set the <strong>Firmware</strong> to: <code class="language-plaintext highlighter-rouge">/usr/share/AAVMF/AAVMF_CODE.fd</code> to disable secure boot and click on <strong>[ Begin Installation ]</strong>.</p>

<p><br />
<br />
<br />
<br />
<br />
<br />
<br /></p>

<p><a href="https://stafwag.github.io/blog/images/openbsd_vm_on_pi/005_boot_vm.png"><img src="https://stafwag.github.io/blog/images/openbsd_vm_on_pi/005_boot_vm.png" class="right" width="300" height="286" alt="begin install" /> </a></p>

<p><br />
<br />
<br /></p>

<p>Let’s check if OpenBSD can boot.
Great, it works!</p>

<p><br />
<br />
<br /></p>

<h1 id="installation-with-virt-install">Installation with virt-install</h1>

<p>I prefer to use the command line to install as this allows me to make the installation reproducible and automated.</p>

<h2 id="create-a-zfs-dataset">Create a ZFS dataset</h2>

<p>I used ZFS on my Raspberry Pi’s, this makes it easier to create snapshots etc when you’re testing software etc.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@staf-pi002:/var/lib/libvirt/images# zfs create staf-pi002_pool/root/var/lib/libvirt/images/openbsd-gitlabrunner001
root@staf-pi002:/var/lib/libvirt/images# 
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@staf-pi002:/var/lib/libvirt/images/openbsd-gitlabrunner001# pwd
/var/lib/libvirt/images/openbsd-gitlabrunner001
root@staf-pi002:/var/lib/libvirt/images/openbsd-gitlabrunner001# 
</code></pre></div></div>

<h2 id="get-the-correct-os-variant">Get the correct <code class="language-plaintext highlighter-rouge">os-variant</code></h2>

<p>To get the operating system settings you can execute the command <code class="language-plaintext highlighter-rouge">virt-install --osinfo list</code></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@staf-pi002:/var/lib/libvirt/images/openbsd-gitlabrunner001# virt-install --osinfo list | grep -i openbsd7
openbsd7.0
root@staf-pi002:/var/lib/libvirt/images/openbsd-gitlabrunner001# 
</code></pre></div></div>

<p>We’ll use <code class="language-plaintext highlighter-rouge">openbsd7.0</code> as the operating system variant.</p>

<h3 id="create-qemu-image">Create QEMU image</h3>

<p>Create a destination disk image.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@staf-pi002:/var/lib/libvirt/images/openbsd-gitlabrunner001# qemu-img create -f qcow2 openbsd-gitlabrunner001.qcow2 50G
Formatting 'openbsd-gitlabrunner001.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=53687091200 lazy_refcounts=off refcount_bits=16
root@staf-pi002:/var/lib/libvirt/images/openbsd-gitlabrunner001# 
</code></pre></div></div>

<h3 id="run-virt-install">Run <code class="language-plaintext highlighter-rouge">virt-install</code></h3>

<p>Run <code class="language-plaintext highlighter-rouge">virt-install</code> to import the virtual machine.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#!/bin/bash

virt-install --name openbsd-gitlabrunner001  \
 --noacpi \
 --boot loader=/usr/share/AAVMF/AAVMF_CODE.fd \
 --os-variant openbsd7.0 \
 --ram 2048 \
 --import \
 --disk /home/staf/Downloads/isos/openbsd/install74.img  \
 --disk /var/lib/libvirt/images/openbsd-gitlabrunner001/openbsd-gitlabrunner001.qcow2
</code></pre></div></div>

<p>If everything goes well the virtual machine gets booted.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>BdsDxe: loading Boot0001 "UEFI Misc Device" from PciRoot(0x0)/Pci(0x1,0x3)/Pci(0x0,0x0)
BdsDxe: starting Boot0001 "UEFI Misc Device" from PciRoot(0x0)/Pci(0x1,0x3)/Pci(0x0,0x0)
disks: sd0*
&gt;&gt; OpenBSD/arm64 BOOTAA64 1.18
boot&gt; 
cannot open sd0a:/etc/random.seed: No such file or directory
booting sd0a:/bsd: 2861736+1091248+12711584+634544 [233295+91+666048+260913]=0x13d5cf8
Copyright (c) 1982, 1986, 1989, 1991, 1993
	The Regents of the University of California.  All rights reserved.
Copyright (c) 1995-2023 OpenBSD. All rights reserved.  https://www.OpenBSD.org

OpenBSD 7.4 (RAMDISK) #2131: Sun Oct  8 13:35:40 MDT 2023
    deraadt@arm64.openbsd.org:/usr/src/sys/arch/arm64/compile/RAMDISK
real mem  = 2138013696 (2038MB)
avail mem = 2034593792 (1940MB)
random: good seed from bootblocks
mainbus0 at root: linux,dummy-virt
psci0 at mainbus0: PSCI 1.1, SMCCC 1.1
efi0 at mainbus0: UEFI 2.7
efi0: EDK II rev 0x10000
smbios0 at efi0: SMBIOS 3.0.0
smbios0:
sd1 at scsibus1 targ 0 lun 0: &lt;VirtIO, Block Device, &gt;
sd1: 51200MB, 512 bytes/sector, 104857600 sectors
virtio35: msix per-VQ
ppb5 at pci0 dev 1 function 5 vendor "Red Hat", unknown product 0x000c rev 0x00: irq
pci6 at ppb5 bus 6
ppb6 at pci0 dev 1 function 6 vendor "Red Hat", unknown product 0x000c rev 0x00: irq
pci7 at ppb6 bus 7
ppb7 at pci0 dev 1 function 7 vendor "Red Hat", unknown product 0x000c rev 0x00: irq
pci8 at ppb7 bus 8
ppb8 at pci0 dev 2 function 0 vendor "Red Hat", unknown product 0x000c rev 0x00: irq
pci9 at ppb8 bus 9
ppb9 at pci0 dev 2 function 1 vendor "Red Hat", unknown product 0x000c rev 0x00: irq
pci10 at ppb9 bus 10
ppb10 at pci0 dev 2 function 2 vendor "Red Hat", unknown product 0x000c rev 0x00: irq
pci11 at ppb10 bus 11
ppb11 at pci0 dev 2 function 3 vendor "Red Hat", unknown product 0x000c rev 0x00: irq
pci12 at ppb11 bus 12
ppb12 at pci0 dev 2 function 4 vendor "Red Hat", unknown product 0x000c rev 0x00: irq
pci13 at ppb12 bus 13
ppb13 at pci0 dev 2 function 5 vendor "Red Hat", unknown product 0x000c rev 0x00: irq
pci14 at ppb13 bus 14
pluart0 at mainbus0: rev 1, 16 byte fifo
pluart0: console
"pmu" at mainbus0 not configured
agtimer0 at mainbus0: 54000 kHz
"apb-pclk" at mainbus0 not configured
softraid0 at root
scsibus2 at softraid0: 256 targets
root on rd0a swap on rd0b dump on rd0b
WARNING: CHECK AND RESET THE DATE!
erase ^?, werase ^W, kill ^U, intr ^C, status ^T

Welcome to the OpenBSD/arm64 7.4 installation program.
(I)nstall, (U)pgrade, (A)utoinstall or (S)hell? 
</code></pre></div></div>

<p>Continue with the OpenBSD installation as usual. Make sure that you select the second disk during the installation process.</p>

<p>To fully automate the installation we need a system that executes the post-configuration at the first boot. On GNU/Linux is normally done by <a href="https://cloud-init.io/">cloud-init</a>
while there are solutions to get cloud-init working on the BSDs. I didn’t look into this (yet).</p>

<p><strong><em>Have fun!</em></strong></p>

<h1 id="links">Links</h1>

<ul>
  <li><a href="https://www.openbsd.org/faq/faq4.html#Download">https://www.openbsd.org/faq/faq4.html#Download</a></li>
  <li><a href="https://www.msiism.org/blog/2019/10/20/authentic_pufferfish_for_penguins.html">https://www.msiism.org/blog/2019/10/20/authentic_pufferfish_for_penguins.html</a></li>
  <li><a href="https://wiki.debian.org/QEMU">https://wiki.debian.org/QEMU</a></li>
  <li><a href="https://docs.openstack.org/image-guide/convert-images.html">https://docs.openstack.org/image-guide/convert-images.html</a></li>
  <li><a href="http://wiki.netbsd.org/ports/evbarm/qemu_arm/">http://wiki.netbsd.org/ports/evbarm/qemu_arm/</a></li>
  <li><a href="https://mike42.me/blog/2019-08-how-to-use-the-qemu-bridge-helper-on-debian-10">https://mike42.me/blog/2019-08-how-to-use-the-qemu-bridge-helper-on-debian-10</a></li>
  <li><a href="https://www.spad.uk/posts/really-simple-network-bridging-with-qemu/">https://www.spad.uk/posts/really-simple-network-bridging-with-qemu/</a></li>
  <li><a href="https://pellaeon.github.io/bsd-cloudinit/">https://pellaeon.github.io/bsd-cloudinit/</a></li>
  <li><a href="https://cloudinit.readthedocs.io/en/latest/reference/datasources/nocloud.html">https://cloudinit.readthedocs.io/en/latest/reference/datasources/nocloud.html</a></li>
</ul>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Best wishes 2024!]]></title>
    <link href="https://stafwag.github.io/blog/blog/2024/01/02/best_wishes_2024/"/>
    <updated>2024-01-02T14:31:00+00:00</updated>
    <id>https://stafwag.github.io/blog/blog/2024/01/02/best_wishes_2024</id>
    <content type="html"><![CDATA[<p><a href="https://stafwag.github.io/blog/images/2024/2024.jpg"><img src="https://stafwag.github.io/blog/images/2024/2024.jpg" class="left" width="1000" height="666" alt="2024" /> </a></p>
]]></content>
  </entry>
  
</feed>
