Jekyll2023-03-30T15:44:09+01:00https://mikemylonakis.com/feed.xmlMike MylonakisBlog and personal website of Mike Mylonakis.Mike MylonakisDIY DynDns using GoDaddy’s REST API2020-05-12T00:00:00+01:002021-06-10T10:06:41+01:00https://mikemylonakis.com/networking/poor-man's-dyndns-with-godaddy-domain<p><img src="https://mikemylonakis.com/assets/images/posts/godaddy.webp" alt="no-alignment" /></p>
<h2 id="introduction">Introduction</h2>
<p>For those of us who want to remotely access some device in our home network, there are really two
options - either pay a premium for a static IP address, or use what is called
<a href="https://en.wikipedia.org/wiki/Dynamic_DNS">Dynamic DNS</a>. This
is because our public IP address can ( and will ) change for several reasons, so if we want to
access our home network we need to know what’s the most recent IP that has been allocated to us.
Although there are several Dynamic DNS providers, their free tier usually includes ads and has
restrictions around the domain name format ( i.e. can only be something.mooo.com or
something.xyz.com - can’t be our own domain ), the number of domains per user etc. In this post
I am showing how to utilize our own domain, <a href="https://developer.godaddy.com/">GoDaddy’s REST API</a>
and a raspberry pi, in order to have
our domain or a <a href="https://en.wikipedia.org/wiki/Subdomain">subdomain</a>, point to our dynamic IP address.</p>
<p>The idea is simple - we ‘ll first figure out what’s our current public IP address and then use our domain
provider’s REST API to update our domain to point to that IP. Then we ‘ll make sure that we
do these steps on a regular basis ( e.g. every 5 mins ) so that , when our dynamic IP changes, in
the worst case scenario we will say a stale IP address for 5 minutes at most.</p>
<h2 id="using-the-rest-api-to-create-and-update-the-sub-domain">Using the REST API to create and update the Sub Domain</h2>
<h3 id="register-for-an-api-key">Register for an API key</h3>
<p>Before using the REST API, we must create an API key.
<a href="https://developer.godaddy.com/">developer.godaddy.com</a> should have all the updated info on how to
get up and running with it. In the end we should have a key and its associated secret,
and we ll use them in the script that will be updating our domain.</p>
<h3 id="use-the-go-script-to-update-the-domain">Use the go script to update the Domain</h3>
<p>The go script that we ‘re going to use in order to update our public ip address can be found in
<a href="https://github.com/mikemyl/godyndns/">mikemyl/godydns</a>. We can grab the latest binaries for our OS-architecture from
the <a href="https://github.com/mikemyl/godyndns/releases">releases</a> and then we can run it like this:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>./godaddy-dyndns <span class="nt">--api-key</span><span class="o">=</span><godaddy_api_key> <span class="nt">--secret-key</span><span class="o">=</span><godaddy_secret_key> <span class="nt">--domain</span><span class="o">=</span><godaddy_subdomain>
</code></pre></div></div>
<p>Upon successful completion, the script should print something like this:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>./godaddy-dydns <span class="nt">--api-key</span><span class="o">=</span><GODADDY_API_KEY> <span class="nt">--secret-key</span><span class="o">=</span><GODADDY_SECRET_KEY> <span class="nt">--domain</span><span class="o">=</span><GODADDY_SUBDOMAIN>
2020/07/19 13:47:51 Getting my public IP address from http://ipinfo.io/ip ...
2020/07/19 13:47:52 My public IP is:<redacted>
2020/07/19 13:47:52 <redacted> is pointing to <redacted>. Will update it to point to <redacted>
</code></pre></div></div>
<p>Assuming everything worked correctly, if we try to run that script again we should get a message
that the subdomain is already pointing to the right IP address. Something like that:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>./godaddy-dydns <span class="nt">--api-key</span><span class="o">=</span><GODADDY_API_KEY> <span class="nt">--secret-key</span><span class="o">=</span><GODADDY_SECRET_KEY> <span class="nt">--domain</span><span class="o">=</span><GODADDY_SUBDOMAIN>
2020/07/19 15:47:56 Getting my public IP address from http://ipinfo.io/ip ...
2020/07/19 15:47:57 My public IP is:<redacted>
2020/07/19 15:47:58 <redacted> is already pointing to <redacted>. Won<span class="s1">'t update..
</span></code></pre></div></div>
<h3 id="create-a-systemd-timer">Create a systemd timer</h3>
<p>Now let’s make sure this script runs periodically so that our public IP stays up to date. In order
to do that:</p>
<ol>
<li>
<p>Copy the script into <code class="language-plaintext highlighter-rouge">/usr/local/bin</code> :</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">sudo cp </span>godaddy-dyndns /usr/local/bin/
</code></pre></div> </div>
</li>
<li>
<p>Create the timer file <code class="language-plaintext highlighter-rouge">/etc/systemd/system/five-minute-timer.timer</code> with the following contents:</p>
<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nn">[Unit]</span>
<span class="py">Description</span><span class="p">=</span><span class="s">Five Minute Timer</span>
<span class="nn">[Timer]</span>
<span class="py">OnBootSec</span><span class="p">=</span><span class="s">5min</span>
<span class="py">OnCalendar</span><span class="p">=</span><span class="s">*:0/5</span>
<span class="py">Unit</span><span class="p">=</span><span class="s">five-minute-timer.service</span>
<span class="nn">[Install]</span>
<span class="py">WantedBy</span><span class="p">=</span><span class="s">timers.target</span>
</code></pre></div> </div>
</li>
<li>
<p>Create the service unit file <code class="language-plaintext highlighter-rouge">/etc/systemd/system/five-minute-timer.service</code> with the
following contents:</p>
<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nn">[Unit]</span>
<span class="py">Description</span><span class="p">=</span><span class="s">Five Minute Timer Service</span>
<span class="nn">[Service]</span>
<span class="py">Type</span><span class="p">=</span><span class="s">oneshot</span>
<span class="py">Environment</span><span class="p">=</span><span class="s">GODADDY_API_KEY=<godaddy-api-key> </span>
<span class="py">Environment</span><span class="p">=</span><span class="s">GODADDY_SECRET_KEY=<godaddy-secret-key> </span>
<span class="py">Environment</span><span class="p">=</span><span class="s">GODADDY_DOMAIN=<godaddy-subdomain> </span>
<span class="py">ExecStart</span><span class="p">=</span><span class="s">/usr/local/bin/godaddy-dyndns</span>
<span class="nn">[Install]</span>
<span class="py">WantedBy</span><span class="p">=</span><span class="s">multi-user.target</span>
</code></pre></div> </div>
</li>
<li>
<p>Start and enable the timer:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>systemctl <span class="nb">enable </span>five-minute-timer.timer <span class="o">&&</span> systemctl start five-minute-timer.timer
</code></pre></div> </div>
</li>
<li>
<p>Verify that the timer runs every 5 minutes and check the logs:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>systemctl list-timers
<span class="nv">$ </span>journalctl <span class="nt">-u</span> five-minute-timer.service
</code></pre></div> </div>
</li>
</ol>
<h2 id="conclusion">Conclusion</h2>
<p>In this post we saw a free, DIY alternative to the paid Dynamic DNS services such as <a href="https://freedns.afraid.org/">FreeDNS</a> ,
<a href="https://account.dyn.com/">Dyn</a> and others. Using a raspberry pi, a utility script
from <a href="https://github.com/mikemyl/godyndns/">mikemyl/godyndns</a> and a systemd timer we were able to
stay up to date with our latest public IP address and update a domain, which we will be using
to access our home network.</p>Mike MylonakisHow to set up your own dynamic DNS using a GoDaddy domain and its REST APISetting up the Unix Password Manager on Android with YubiKey 5 NFC2018-12-26T00:00:00+00:002018-12-26T00:00:00+00:00https://mikemylonakis.com/cryptography/android-youbikey-5-nfc<p><img src="https://mikemylonakis.com/assets/images/posts/yubikey.webp" alt="no-alignment" /></p>
<h2 id="introduction">Introduction</h2>
<p>Having used the <a href="/cryptography/unix-pass/">unix password manager</a> for a while I managed to have a simple,
secure and powerful password manager that makes my passwords available on every computer that I use.
However, there is still something that’s missing: making my passwords available on my Android phone.</p>
<p>In this post I will address this issue by describing how to utilize the new <a href="https://www.yubico.com/product/yubikey-5-nfc/">YubiKey 5 NFC</a>,
an Android phone with NFC reader and the apps
<a href="https://www.openkeychain.org/">Openkeychain</a> and <a href="https://play.google.com/store/apps/details?id=com.zeapo.pwdstore&hl=en_US">Password Store</a>
in order to bring the power of the Unix Password Manager into Android. Let’s start!</p>
<h2 id="setting-up-the-yubikey">Setting up the YubiKey</h2>
<p>First of all, let me explain why a YubiKey is needed. So if we want to use the Unix password manager on an Android phone,
we need to be able to decrypt the files that contain our passwords. Now we can do that by copying the private encryption
key into the Android phone but IMHO, putting the private key in an phone is not a very good idea. That’s were YubiKey comes into
the picture. Using the new <a href="https://www.yubico.com/product/yubikey-5-nfc/">YubiKey 5 NFC</a> or the older
<a href="https://support.yubico.com/support/solutions/articles/15000006494-yubikey-neo">YubiKey Neo</a> we can have them store our
private key(s), making them available to the phone only when needed, via NFC.</p>
<p>Setting up the YubiKey with OpenPGP is quite easy, following the instructions on <a href="https://support.yubico.com/support/solutions/articles/15000006420-using-your-yubikey-with-openpgp">Yubico’s</a>
website. Assuming that we have an encryption subkey with id <code class="language-plaintext highlighter-rouge">1F077BAE</code> ( have a look on my <a href="/cryptography/unix-pass/#create-a-pgp-key">previous post</a> ):</p>
<ol>
<li>
<p>Create a backup of the encryption key and keep it in a safe location, in case the YubiKey is lost or stolen:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>gpg <span class="nt">--output</span> 1F077BAE-bak.asc <span class="nt">--export-secret-subkeys</span> <span class="nt">--armor</span> 1F077BAE!
</code></pre></div> </div>
<p class="notice--info">
<strong>Note</strong>: This will export only the encryption key, as if it is decoupled from its main key. Don't forget the "!" in the end.
</p>
</li>
<li>
<p>With the YubiKey plugged in:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>gpg <span class="nt">--edit-key</span> 1F077BAE
<span class="nv">$ </span>key 1 <span class="c"># Depending on the number of subkeys, the number 1 may be different</span>
<span class="nv">$ </span>keytocard <span class="c"># Key password and YubiKey admin pin are needed for this step</span>
</code></pre></div> </div>
</li>
</ol>
<p>Here’s a asciinema of what’s described above:</p>
<script id="asciicast-QEi40F3mFUzpAFPAoIFkdD05p" src="https://asciinema.org/a/QEi40F3mFUzpAFPAoIFkdD05p.js" data-rows="25" data-theme="asciinema" async=""></script>
<p class="notice--info">
<strong>Note</strong>: I obviously didn't replace my existing key in the YubiKey thus the bad password in the end :smile:
</p>
<h2 id="setting-up-the-phone">Setting up the phone</h2>
<p>We are going to need two apps:</p>
<ul>
<li><a href="https://f-droid.org/en/packages/org.sufficientlysecure.keychain/">Openkeychain</a>, which is a gpg toolchain for Android. This is need so that the encryption key can be loaded from YubiKey.</li>
<li><a href="https://f-droid.org/en/packages/com.zeapo.pwdstore/">Password Store</a>, which is the Unix Password Manager implemented on Android.</li>
</ul>
<h3 id="setting-up-openkeychain">Setting up OpenKeyChain</h3>
<p>The setup is really easy here. Having the app installed, we just open it and move the YubiKey near the NFC reader,
we ‘re then asked for the YubiKey pin, and the key is imported successfully.</p>
<h3 id="setting-up-password-store">Setting up Password store</h3>
<p>For this step, we ‘re going to need our password-store in a git repository (see <a href="/cryptography/unix-pass/#adding-a-remote">here</a> how to add one).</p>
<p>We open the Password Store app, go to Settings->Crypto->Select OpenPGP Provider and select OpenKeychain. Then we add the
git remote url for the password-store, and as soon as it’s cloned we ‘re good to go!</p>
<h2 id="conclusion">Conclusion</h2>
<p>Utilizing the Unix Password Store in an Android phone is easy and secure using an NFC-enabled YubiKey. The android app
for the Password Store is intuitive and easy to use, supports full text searching and adding / updating passwords. And
as an extra bonus we can use our YubiKey to add an extra layer of security to our 2-factor-authentication using the
<a href="https://www.yubico.com/products/services-software/download/yubico-authenticator/">Yubico Authenticator App</a> as an
alternative to Google Authenticator.</p>
<p>Happy decrypting !</p>Mike MylonakisHow to set up the Unix Password manager on android using a YubiKey 5 NFCUsing docker behind an http proxy with authentication2018-12-01T00:00:00+00:002018-12-01T00:00:00+00:00https://mikemylonakis.com/unix/docker-proxy<p><img src="https://mikemylonakis.com/assets/images/posts/docker.jpg" alt="no-alignment" /></p>
<h3 id="introduction">Introduction</h3>
<p>Web proxies are mostly used in corporate environments but can be useful on small offices / home offices as well. <a href="http://www.squid-cache.org/">Squid</a>
is an example of a easy to install and configure proxy, that can help us achieve centralized control of the web traffic
in our home. Using an http_proxy from the client perspective is pretty simple, and comes down to specifying the proxy
address in the browser settings, but from an engineer perspective things are more interesting!</p>
<p>I have been playing a lot with docker lately and I had a really hard time in configuring it to use an authenticated
http(s) proxy, so I thought I ‘d share my experience here.</p>
<h3 id="environment-variables">Environment variables</h3>
<p>On Unix environments most applications respect the <code class="language-plaintext highlighter-rouge">http_proxy</code>, <code class="language-plaintext highlighter-rouge">https_proxy</code> environment variables. If we want to
tell wget to use a proxy for instance, we would do something like that:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">export </span><span class="nv">https_proxy</span><span class="o">=</span>http://<my_usename>:<my_password>@my_proxy.com
<span class="nv">$ </span>wget someurl.com
</code></pre></div></div>
<p>Docker, however, is a daemon and is managed by <a href="https://wiki.archlinux.org/index.php/systemd">systemd</a> on the most
popular Linux distributions, so we need to configure these environment variables in a different way.</p>
<h3 id="systemd-directives">Systemd directives</h3>
<p>According to the <a href="https://docs.docker.com/config/daemon/systemd/">official documentation</a>, we should create a file
<code class="language-plaintext highlighter-rouge">/etc/systemd/system/docker.service.d/http-proxy.conf</code> with the following contents:</p>
<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">[Service]</span>
<span class="py">Environment</span><span class="p">=</span><span class="s">"HTTP_PROXY=http://proxy.example.com:80/"</span>
</code></pre></div></div>
<p class="notice--info">
<strong>Note:</strong> HTTP_PROXY doesn't have to be in uppercase. As per
<a href="https://golang.org/src/net/http/transport.go?s=13180:13237#L329">golang's documentation</a>
the lowercase variants work as well.
</p>
<p>This works fine, if the web proxy does not use authentication or, if it does use it, our credentials do not
contain special characters. If my password looks like this <code class="language-plaintext highlighter-rouge">MyAw3s0m3p^$$.!</code>, and I create the systemd configuration
file as instructed:</p>
<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">[Service]</span>
<span class="py">Environment</span><span class="p">=</span><span class="s">"http_proxy=http://myusername:MyAw3s0m3p^$$.!@proxy.example.com:80/"</span>
</code></pre></div></div>
<p>docker won’t be able to use the http_proxy. <code class="language-plaintext highlighter-rouge">docker pull</code> will fail miserably with an error like this:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>docker pull hello-world
Error response from daemon: Get https://registry-1.docker.io/v2/: proxyconnect tcp: dial tcp: lookup http: no such host
</code></pre></div></div>
<p>There are two issues here. First of all, golang (which powers docker) doesn’t like these special characters in the url. We
need to <a href="https://www.url-encode-decode.com/">urlencode</a> this password. <code class="language-plaintext highlighter-rouge">http://myusername:MyAw3s0m3p^$$.!@proxy.example.com:80/</code>
becomes <code class="language-plaintext highlighter-rouge">http%3A%2F%2Fmyusername%3AMyAw3s0m3p%5E%24%24.%21%40proxy.example.com%3A80%2F</code>. But even the urlencoded url won’t work,
cause systemd doesn’t like the <code class="language-plaintext highlighter-rouge">%</code> and some other special characters in there. There is <a href="https://www.freedesktop.org/software/systemd/man/systemd-escape.html">systemd-escape</a>
which escapes strings for usage in systemd unit names, but this didn’t work for me. My solution to that was to use the <code class="language-plaintext highlighter-rouge">EnironmentFile</code>
directive instead of the <code class="language-plaintext highlighter-rouge">Environment</code>. Instead of specifying the environment variables in the systemd configuration file,
we will create another file that systemd is going to read in order to load the environment variables.</p>
<p>The <code class="language-plaintext highlighter-rouge">/etc/systemd/system/docker.service.d/http-proxy.conf</code> file becomes:</p>
<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">[Service]</span>
<span class="py">EnvironmentFile</span><span class="p">=</span><span class="s">/etc/system/default/docker</span>
</code></pre></div></div>
<p>And the <code class="language-plaintext highlighter-rouge">/etc/system/default/docker</code> file looks like this:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>http_proxy='http%3A%2F%2Fmyusername%3AMyAw3s0m3p%5E%24%24.%21%40proxy.example.com%3A80%2F'
</code></pre></div></div>
<p>This is a good practice btw, as we can restrict the permissions to that file so that it’s not readable by the world. If
we want to include passwords in our environment variables we wouldn’t want some unauthorized user to be able to view our
passwords by looking at the systemd configuration file or by using <code class="language-plaintext highlighter-rouge">systemctld show docker</code> for instance. Let’s do that
and restrict access to this file:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">chgrp </span>docker /etc/default/docker <span class="c"># change group owner to docker</span>
<span class="nv">$ </span><span class="nb">chmod </span>o-r /etc/default/docker <span class="c"># remove read access from ppl not in the docker group</span>
</code></pre></div></div>
<p>Having made the changes above, we reload - restart the docker service and everything works as expected.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>systemctl daemon-reload
<span class="nv">$ </span>systemctl restart docker
</code></pre></div></div>
<h3 id="conclusion">Conclusion</h3>
<p>We saw that golang needs the urls in an encoded form when special characters are included. We also noticed that systemd
cannot read these encoded urls when specified in its configuration files using the <code class="language-plaintext highlighter-rouge">Environment</code> directive, and we used
the <code class="language-plaintext highlighter-rouge">EnvironmentFile</code> instead with a new file that contains our environment variables under <code class="language-plaintext highlighter-rouge">/etc/default/docker</code>. Finally,
we restricted access to that file so that only members of the docker group can read it.</p>Mike MylonakisHow to use docker behind an authenticated http proxyThe Unix Password Manager2018-01-30T00:00:00+00:002018-01-30T00:00:00+00:00https://mikemylonakis.com/cryptography/unix-pass<p><img src="https://mikemylonakis.com/assets/images/posts/unix-pass.jpg" alt="no-alignment" /></p>
<h2 id="introduction">Introduction</h2>
<p>As the number of username-passwords we need to remember increases, password managers are becoming
more and more relevant. By using a password manager we no longer have to revert our password because
we can’t remember the variation we used for that particular website, or use the same one everywhere.
But chances are you already know that since you came across
this post, so let’s cut to the chase and talk about <a href="https://www.passwordstore.org/">pass</a>, the standard
unix password manager.</p>
<p>Pass is a simple password manager that stores our credentials in gpg encrypted files, where the filenames correspond to the
respective titles of the service / website.</p>
<p>We can also utilize the build-in git integration to keep those credentials synced between our devices - including Android, iOS
devices windows computers etc.</p>
<h2 id="prerequisites">Prerequisites</h2>
<h3 id="create-a-pgp-key">Create a PGP key</h3>
<p>In order to start using pass, we need a <a href="https://en.wikipedia.org/wiki/Pretty_Good_Privacy">PGP key</a> with encryption
capabilities.</p>
<p>In most Linux distributions GnuPG toolchain should already be installed and is avaliable through their package managers.
If not, get the latest verion from <a href="https://www.gnupg.org/download/">GnuPG website</a>. Make sure you use a GnuPG version > 2
(in Ubuntu for example, that would be the <code class="language-plaintext highlighter-rouge">gpg2</code> command):</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>gpg <span class="nt">--version</span>
gpg <span class="o">(</span>GnuPG<span class="o">)</span> 2.2.5
libgcrypt 1.8.2
Copyright <span class="o">(</span>C<span class="o">)</span> 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Home: /home/mike/foo
Supported algorithms:
Pubkey: RSA, ELG, DSA, ECDH, ECDSA, EDDSA
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
CAMELLIA128, CAMELLIA192, CAMELLIA256
Hash: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB, BZIP2
</code></pre></div></div>
<p>So let’s generate our gpg key using the following command:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>gpg <span class="nt">--full-generate-key</span>
</code></pre></div></div>
<p>I went with the default options for the key type (RSA and RSA), and the key size (2048). I could have selected a
4096-bits long key, but I intend to use with my <a href="https://www.yubico.com/products/yubikey-hardware/yubikey-neo/">YubiKey Neo</a> and it doesn’t
support 4096-bit keys yet. I then specified the valid until date, my name - email, a password. Make sure you don’t forget
that key’s password cause every password managed by pass is encrypted with that private key. But we used to
remember our credentials for all those services that we use so a single key’s password won’t be much of an issue!</p>
<p>We can verify that the key was successfully generated, using the command below:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>gpg <span class="nt">-K</span>
gpg: checking the trustdb
gpg: marginals needed: 3 completes needed: 1 trust model: pgp
gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
gpg: next trustdb check due at 2019-06-10
/home/mike/foo/pubring.kbx
<span class="nt">--------------------------</span>
sec rsa2048 2018-06-10 <span class="o">[</span>SC] <span class="o">[</span>expires: 2019-06-10]
15E886BF97A7828A2F5795DBC22FADC6585FDF18
uid <span class="o">[</span>ultimate] Michail Mylonakis <span class="o">(</span>My gpg key<span class="o">)</span> <mike@mikemylonakis.com>
ssb rsa2048 2018-06-10 <span class="o">[</span>E] <span class="o">[</span>expires: 2019-06-10]
</code></pre></div></div>
<h3 id="install-pass">Install pass</h3>
<p>Pass is available on all major linux distributions, so it should be easy to install using the package manager. In Arch
linux that would be pacman, and we can easily install pass.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>pacman <span class="nt">-S</span> pass
</code></pre></div></div>
<h3 id="initialise-pass">Initialise pass</h3>
<p>In order to set up pass, we need to run the following:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>pass init mike@mikemylonakis.com
</code></pre></div></div>
<p>Note that we used the same email address of our secret gpg key.
Let’s also enable the git integration:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>pass git init
</code></pre></div></div>
<p>Now our password store (the <em>~/.password-store</em> directory) is a git repository, so we can utilize git to keep our password
synced between our multiple devices (we ll see how in a next section).</p>
<h3 id="export-the-private-key">Export the private key</h3>
<p>Now let’s export our private key so that we can import it into our other devices. It also makes sense to save it somewhere
“safe” as a backup.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>gpg <span class="nt">--export-secret-keys</span> <span class="o">></span> secret.asc
</code></pre></div></div>
<h2 id="using-pass">Using pass</h2>
<h3 id="generate-a-new-pass">Generate a new pass</h3>
<p>Now we are ready to start using pass. Let’s generate our first simple password, for the website <em>test.com</em>:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>pass generate test.com 10
<span class="o">[</span>master e065551] Add generated password <span class="k">for </span>test.com.
1 file changed, 0 insertions<span class="o">(</span>+<span class="o">)</span>, 0 deletions<span class="o">(</span>-<span class="o">)</span>
create mode 100644 test.com.gpg
The generated password <span class="k">for </span>test.com is:
+U%90>_<span class="k">*</span><span class="o">=</span>Y
</code></pre></div></div>
<p>In the last line above, we see the (randomly) generated password. The number 10 that we passed as the last argument of
the pass generate command specifies the password length. We can use the <code class="language-plaintext highlighter-rouge">-n or --no-symbols</code> option to blacklist specific
chars. Our password is stored at the file <code class="language-plaintext highlighter-rouge">~/.password-store/test.com.gpg</code> in an encrypted format.</p>
<h3 id="insert-an-existing-password">Insert an existing password</h3>
<p>Now let’s insert an already existing password.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>pass insert social/twitter
<span class="nb">mkdir</span>: created directory <span class="s1">'/home/mike/.password-store/social'</span>
Enter password <span class="k">for </span>social/twitter:
Retype password <span class="k">for </span>social/twitter:
<span class="o">[</span>master d2f3237] Add given password <span class="k">for </span>social/twitter to store.
1 file changed, 0 insertions<span class="o">(</span>+<span class="o">)</span>, 0 deletions<span class="o">(</span>-<span class="o">)</span>
create mode 100644 social/twitter.gpg
</code></pre></div></div>
<p>We can organize the password store directory structure into categories, as seen bellow.</p>
<h3 id="update-an-existing-password">Update an existing password</h3>
<p>We can update an existing password like this:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>pass edit social/twitter
</code></pre></div></div>
<p>or have pass generate a new password for us.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>pass generate <span class="nt">-i</span> social/twitter
</code></pre></div></div>
<h3 id="retrieve-a-password">Retrieve a password</h3>
<p>We can see what passwords exist in the password store usgin the <code class="language-plaintext highlighter-rouge">pass ls</code> command:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>pass <span class="nb">ls
</span>Password Store
├── social
│ └── twitter
└── test.com
</code></pre></div></div>
<p>We can reveal a password like this:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>pass test.com
</code></pre></div></div>
<p>If we pass the <code class="language-plaintext highlighter-rouge">-c</code> flag on the above command the password is copied to our clipboard and stays there for 45 seconds by
default.</p>
<h3 id="store-more-details">Store more details</h3>
<p>Another interesting feature of pass is that we can store more details alongside with the password - just make sure
that the first line contains the password as that’s what pass copies into our clipboard. We can edit an existing
password using the <code class="language-plaintext highlighter-rouge">pass edit</code> command, in which case the text editor specified by the <em>$EDITOR</em> env variable will
open up and let us modify the file. We can also use the <code class="language-plaintext highlighter-rouge">-m</code> flag in the <em>pass insert</em> command to add the details
in one go:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>pass insert <span class="nt">-m</span> github
Enter contents of github and press Ctrl+D when finished:
mypassword
url: github.com
username: myusername
<span class="o">[</span>master 791253d] Add given password <span class="k">for </span>github to store.
1 file changed, 0 insertions<span class="o">(</span>+<span class="o">)</span>, 0 deletions<span class="o">(</span>-<span class="o">)</span>
create mode 100644 github.gpg
</code></pre></div></div>
<h3 id="remove-a-password">Remove a password</h3>
<p>We can easily remove an existing password:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>pass <span class="nb">rm </span>github
Are you sure you would like to delete github? <span class="o">[</span>y/N] y
removed <span class="s1">'/home/mike/.password-store/github.gpg'</span>
<span class="o">[</span>master 99c7fda] Remove github from store.
1 file changed, 0 insertions<span class="o">(</span>+<span class="o">)</span>, 0 deletions<span class="o">(</span>-<span class="o">)</span>
delete mode 100644 github.gpg
</code></pre></div></div>
<h2 id="git-integration">Git integration</h2>
<h3 id="interacting-with-the-git-repo">Interacting with the git repo</h3>
<p>As we have enabled git integration in the beginning of this guide our passwords are stored encrypted in a
full-fledged git repository. We can examine the repo using the normal git commands prepended by pass:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>pass git log
commit 791253d6ad8bd4149f1106a3a32f1d65c55c34df <span class="o">(</span>HEAD -> master<span class="o">)</span>
Author: Mike <mike@mikemylonakis.com>
Date: Sat Jun 16 17:58:00 2018 +0100
Add given password <span class="k">for </span>github to store.
commit 99c7fdaf5a902f2dd6e31f211933fdb950b8548b
Author: Mike <mike@mikemylonakis.com>
Date: Sat Jun 16 17:53:41 2018 +0100
Remove github from store.
commit 53f887ce03aadbe865daead5923fb6dbb2e44b26
Author: Mike <mike@mikemylonakis.com>
Date: Sat Jun 16 17:51:23 2018 +0100
Edit password <span class="k">for </span>test.com using vi.
...
</code></pre></div></div>
<h3 id="adding-a-remote">Adding a remote</h3>
<p>We can easily add a remote so that we can clone the repo from other devices.
Note however that, although our passwords are encrypted (so without our private key they cannot
be decrypted) the filenames are not encrypted so one could see the websites / services that we maintain an account.</p>
<p>We could use a private or a self-hosted git repository as a workaround:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>pass git remote add origin git@bitbucket.org:username/private-git-repo.git
</code></pre></div></div>
<p>And then push our password-store to the remote:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>pass git push origin master
</code></pre></div></div>
<p>Now all we have to do is import our private key (using the .asc file that we have exported) into our other device and
clone the repo to start using pass and have our passwords synced!</p>
<h2 id="conclusion">Conclusion</h2>
<p>Pass is a very simple but powerful password manager that is open source (thus free) easy to use and can keep our
passwords synced across many devices. There are also some very cool pass <a href="https://www.passwordstore.org/#other">clients</a> and
<a href="https://www.passwordstore.org/#extensions">extensions</a> that make working with pass even easier.</p>Mike MylonakisSetup the unix password manager with pgp and git