<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Gpg on inetshell</title><link>https://inet.sh/en/tags/gpg/</link><description>Recent content in Gpg on inetshell</description><generator>Hugo</generator><language>en</language><lastBuildDate>Mon, 24 Aug 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://inet.sh/en/tags/gpg/index.xml" rel="self" type="application/rss+xml"/><item><title>Encrypt secrets with SOPS and GPG (PGP)</title><link>https://inet.sh/en/posts/sops/gpg/</link><pubDate>Mon, 24 Aug 2026 00:00:00 +0000</pubDate><guid>https://inet.sh/en/posts/sops/gpg/</guid><description>Encrypt secrets in git with SOPS and a GPG/PGP key: generate the key, wire the fingerprint into .sops.yaml, and encrypt/decrypt only the values.</description><content:encoded><![CDATA[<h2 id="tldr">TL;DR</h2>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">gpg --list-secret-keys --keyid-format<span class="o">=</span>long   <span class="c1"># get the fingerprint</span>
</span></span><span class="line"><span class="cl"><span class="c1"># .sops.yaml → creation_rules: pgp: &lt;FINGERPRINT&gt;</span>
</span></span><span class="line"><span class="cl">sops -e -i secrets.yaml                        <span class="c1"># encrypt in place</span>
</span></span><span class="line"><span class="cl">sops secrets.yaml                              <span class="c1"># edit decrypted, re-encrypt on save</span>
</span></span><span class="line"><span class="cl">sops -d secrets.yaml                           <span class="c1"># decrypt to stdout</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>SOPS encrypts the <strong>values</strong> of a structured file (YAML/JSON/env/ini) and leaves the <strong>keys</strong> readable, so a <code>secrets.enc.yaml</code> is a clean, reviewable git diff. Decryption needs the GPG <strong>private</strong> key on the machine.</p>
<h2 id="prerequisites">Prerequisites</h2>
<p><code>gpg</code> and <code>sops</code> installed. Check: <code>gpg --version</code> and <code>sops --version</code>.</p>
<h2 id="1-get-a-gpg-key">1. Get a GPG key</h2>
<p>Use an existing key or create one:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">gpg --full-generate-key
</span></span><span class="line"><span class="cl">gpg --list-secret-keys --keyid-format<span class="o">=</span>long
</span></span></code></pre></td></tr></table>
</div>
</div><p>Copy the 40-char <strong>fingerprint</strong> (the long hex line under <code>sec</code>). That fingerprint is what SOPS references — not the short key id.</p>
<h2 id="2-tell-sops-which-key-to-use">2. Tell SOPS which key to use</h2>
<p>Put a <code>.sops.yaml</code> at the repo root so you never pass keys by hand:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">creation_rules</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="nt">path_regex</span><span class="p">:</span><span class="w"> </span><span class="l">\.enc\.ya?ml$</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">pgp</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;FBC7B9E2A4F9289AC0C1D4843C1FCF3D&#34;</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li><code>path_regex</code> scopes the rule to files you name <code>*.enc.yaml</code>.</li>
<li><code>pgp</code> takes one or more comma-separated fingerprints (multiple recipients = anyone with one of those private keys can decrypt).</li>
</ul>
<h2 id="3-encrypt-edit-decrypt">3. Encrypt, edit, decrypt</h2>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">sops -e -i secrets.enc.yaml     <span class="c1"># encrypt in place (-i), values only</span>
</span></span><span class="line"><span class="cl">sops secrets.enc.yaml           <span class="c1"># open $EDITOR decrypted; re-encrypts on save</span>
</span></span><span class="line"><span class="cl">sops -d secrets.enc.yaml        <span class="c1"># decrypt to stdout</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Commit the encrypted file. The plaintext never touches git.</p>
<h2 id="what-sops-touches">What SOPS touches</h2>
<table>
  <thead>
      <tr>
          <th>Part</th>
          <th>Encrypted?</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Values (<code>password: hunter2</code>)</td>
          <td>yes</td>
      </tr>
      <tr>
          <td>Keys / structure (<code>password:</code>)</td>
          <td>no (readable diffs)</td>
      </tr>
      <tr>
          <td>Extra <code>sops:</code> metadata block</td>
          <td>added (recipients, MAC)</td>
      </tr>
  </tbody>
</table>
<h2 id="traps">Traps</h2>
<ul>
<li><strong>Subkeys:</strong> to force a specific GnuPG subkey, append <code>!</code> to the fingerprint in <code>creation_rules</code> (e.g. <code>A3D6...E8F!</code>). Only honored since SOPS 3.9.3.</li>
<li><strong>Different gpg binary:</strong> set <code>SOPS_GPG_EXEC</code> to point SOPS at a wrapper instead of the default <code>gpg</code>.</li>
<li><strong>Back up the private key.</strong> Lose it and the encrypted files are gone — SOPS is only as recoverable as the GPG key. Add a second recipient (a backup/escrow key) in <code>creation_rules</code> from day one.</li>
<li><strong>Rotating recipients:</strong> after editing <code>creation_rules</code>, run <code>sops updatekeys secrets.enc.yaml</code> to re-encrypt the file key for the new set.</li>
<li>Only structured files get value-level encryption; for a blob use <code>sops -e --input-type binary</code>.</li>
</ul>
<h2 id="git-and-automation">Git and automation</h2>
<ul>
<li>The encrypted file is what lives in git; reviewers see key names, never values.</li>
<li>On any host/CI that must decrypt, import the <strong>private</strong> key into its GPG keyring first (<code>gpg --import</code>), then <code>sops -d</code>.</li>
<li>Ansible can consume SOPS directly via the <code>community.sops</code> collection (e.g. the <code>community.sops.sops</code> lookup / <code>load_vars</code>) so playbooks read secrets without a manual decrypt step. Verify the collection is installed on the control node.</li>
</ul>
<h2 id="see-also">See also</h2>
<ul>
<li>SOPS PGP / GnuPG docs: <a href="https://getsops.io/docs/usage/identities/pgp/">https://getsops.io/docs/usage/identities/pgp/</a></li>
</ul>
]]></content:encoded></item></channel></rss>