<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title>there was a fish in the calculator</title><id>https://fishinthecalculator.me/feeds/tags/automation.xml</id><subtitle>Tag: automation</subtitle><updated>2026-05-05T22:13:01Z</updated><link href="https://fishinthecalculator.me/feeds/tags/automation.xml" rel="self" /><link href="https://fishinthecalculator.me" /><entry><title>Secrets management with SOPS Guix</title><id>https://fishinthecalculator.me/blog/secrets-management-with-sops-guix.html</id><author><name>Giacomo Leidi</name><email>therewasa@fishinthecalculator.me</email></author><updated>2024-01-02T16:20:00Z</updated><link href="https://fishinthecalculator.me/blog/secrets-management-with-sops-guix.html" rel="alternate" /><content type="html">&lt;p&gt;Dealing with secrets in functional operating systems can range from pretty usable to complete hell. Nix has &lt;a href=&quot;https://nixos.wiki/wiki/Comparison_of_secret_managing_schemes&quot;&gt;several answers to this problem&lt;/a&gt;, the more integrated of which appears to be &lt;a href=&quot;https://github.com/Mic92/sops-nix&quot;&gt;&lt;code&gt;sops-nix&lt;/code&gt;&lt;/a&gt;. After spending some months envying our neighbors grass, I figured it was time for Guix to have its own (attempt at an) answer to the secrets problem.&lt;/p&gt;&lt;p&gt;This is how the &lt;a href=&quot;https://github.com/fishinthecalculator/sops-guix&quot;&gt;SOPS Guix&lt;/a&gt; channel was born, the first take I'm aware of at implementing secure deploying of secrets with Guix and &lt;a href=&quot;https://getsops.io&quot;&gt;SOPS&lt;/a&gt; and as the name shows is quite inspired from Nix's &lt;code&gt;sops-nix&lt;/code&gt;.&lt;/p&gt;&lt;h2 id=&quot;secure_secret_provisioning_with_guix&quot;&gt;Secure secret provisioning with Guix&lt;/h2&gt;&lt;p&gt;This channels exposes the &lt;code&gt;sops-secrets-service-type&lt;/code&gt; Guix service and the &lt;code&gt;sops-secret&lt;/code&gt; record to safely handle secrets with Guix. It works by putting encrypted secrets in the store and by adding a one-shot Shepherd service that decrypts them at startup in a ramfs/tmpfs filesystem. This means that clear text secrets never hit the disk and that you can (and actually are encouraged to) check in your SOPS secrets in the same version control system you use to track you Guix configurations.&lt;/p&gt;&lt;p&gt;Assuming that the right private keys are also provided, &lt;code&gt;sops-secret&lt;/code&gt;s can be included in Guix images, deployed with &lt;code&gt;guix deploy&lt;/code&gt; and included in Guix System/Home containers. Before starting, &lt;a href=&quot;https://github.com/fishinthecalculator/sops-guix/#configure&quot;&gt;make sure you add it to your &lt;code&gt;.config/guix/channels.scm&lt;/code&gt;&lt;/a&gt;, run &lt;code&gt;guix pull&lt;/code&gt; and make sure &lt;code&gt;sops-guix&lt;/code&gt; appears in your &lt;code&gt;guix describe&lt;/code&gt; output.&lt;/p&gt;&lt;h3 id=&quot;creating_secrets_with_sops&quot;&gt;Creating secrets with SOPS&lt;/h3&gt;&lt;p&gt;First of all you need to create encrypted secrets with SOPS. To do so I'm assuming you already have a GPG key for yourself and the machines you want to deploy secrets to. You should be able to list the private keys you have in your keyring with&lt;/p&gt;&lt;pre&gt;&lt;code&gt;user1@home:~ $ gpg --list-secret-keys
/home/user1/.gnupg/pubring.kbx
------------------------
sec   ed25519 2023-12-01 [SC] [expires: 2907-11-30]
      8D1060B96BB8B7249AED41CC193B701E2SODIJNS
uid           [ultimate] user1@example.org
ssb   cv25519 2023-12-01 [E]

pub   rsa3072 1970-01-01 [SCE]
      8C3E4F6EB38828939029AE7BE9B6AF0CD39DD935
uid           [ unknown] root (Imported from SSH) &amp;lt;root@localhost&amp;gt;

pub   rsa3072 1970-01-01 [SCE]
      ZZ3E4VREB38800039029AE7BE9B6AF0CD39AALH9
uid           [ unknown] root (Imported from SSH) &amp;lt;root@localhost&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you don't have a suitable set of GPG keys it's pretty simple to find online how generate them. Once you have a suitable set of keys for yourself and your machines you are ready to create the only configuration you need for SOPS: a &lt;code&gt;.sops.yaml&lt;/code&gt; file that you will place in your project's root directory, or anyway in the same directory where you keep your system configuration. In this file you define which keys will be able to access your secrets files, it may very well be something like:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;keys:
    - &amp;amp;user_user1 8D1060B96BB8B7249AED41CC193B701E2SODIJNS
    - &amp;amp;host_host1 8C3E4F6EB38828939029AE7BE9B6AF0CD39DD935
    - &amp;amp;host_host2 ZZ3E4VREB38800039029AE7BE9B6AF0CD39AALH9

creation_rules:
    - path_regex: .*common\.yaml$
      key_groups:
          - pgp:
                - *user_user1
                - *host_host1
                - *host_host2
    - path_regex: .*host1\.yaml$
      key_groups:
          - pgp:
                - *user_user1
                - *host_host1&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In this file we define three keys called &lt;code&gt;user_user1&lt;/code&gt;, &lt;code&gt;host_host1&lt;/code&gt; and &lt;code&gt;host_host2&lt;/code&gt; . The prefixes &lt;code&gt;host_&lt;/code&gt; and &lt;code&gt;user_&lt;/code&gt; are just a convention to indicate that some GPG keys belong to users and some belong to machines.&lt;/p&gt;&lt;p&gt;We now have defined two secrets file names patterns and we declared permissions for each key, it should be possible now to run the following in your projects root directory:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;sops common.yaml&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will open your default editor with an example content to define your secrets value. You can edit it or delete it and your own content for example:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;wireguard:
    private: MYPRIVATEKEY&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;after saving and closing the file you can see by &lt;code&gt;cat&lt;/code&gt;ting the secret file that &lt;code&gt;sops&lt;/code&gt; encrypted it before saving it, so you are free to check it in your VCS.&lt;/p&gt;&lt;h3 id=&quot;making_sure_the_right_host_keys_are_in_the_configured_gnupg_keyring&quot;&gt;Making sure the right host keys are in the configured GnuPG keyring&lt;/h3&gt;&lt;p&gt;For hosts to be able to decrypt secrets you need to provide in the &lt;code&gt;root&lt;/code&gt; user keyring (or anyway the keyring located at the configured &lt;code&gt;gnupg-homedir&lt;/code&gt;) the keys you defined in your &lt;code&gt;.sops.yaml&lt;/code&gt;. So based on the above example you'd need to provide &lt;code&gt;8C3E4F6EB38828939029AE7BE9B6AF0CD39DD935&lt;/code&gt;'s private key on &lt;code&gt;host1&lt;/code&gt; and &lt;code&gt;ZZ3E4VREB38800039029AE7BE9B6AF0CD39AALH9&lt;/code&gt;'s private key on &lt;code&gt;host2&lt;/code&gt; .&lt;/p&gt;&lt;p&gt;To check that your key is correctly imported into the keyring run:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;user1@host1:~ $ sudo gpg --list-secret-keys
/root/.gnupg/pubring.kbx
------------------------
pub   rsa3072 1970-01-01 [SCE]
      8C3E4F6EB38828939029AE7BE9B6AF0CD39DD935
uid           [ unknown] root (Imported from SSH) &amp;lt;root@localhost&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;By setting &lt;code&gt;generate-key?&lt;/code&gt; to &lt;code&gt;#t&lt;/code&gt; in &lt;code&gt;sops-service-configuration&lt;/code&gt; a GPG key will be automatically derived for you from your system's &lt;code&gt;/etc/ssh/ssh_host_rsa_key&lt;/code&gt; and added to the configured keyring. It is &lt;em&gt;discouraged&lt;/em&gt; to do so and you are more than encouraged to autonomally provide a key in your configured keyring.&lt;/p&gt;&lt;h3&gt;Adding secrets to your &lt;code&gt;operating-system&lt;/code&gt; record&lt;/h3&gt;&lt;p&gt;Now, supposing you have your &lt;code&gt;operating-system&lt;/code&gt; file in the same directory where you have your &lt;code&gt;.sops.yaml&lt;/code&gt; and &lt;code&gt;common.yaml&lt;/code&gt; files, you can simply add the following to your configuration:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;use-modules&lt;/span&gt; &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;sops&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;secrets&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;sops&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;services&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;sops&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;guix&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;utils&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-special&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;project-root&lt;/span&gt;
  &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;current-source-directory&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-special&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;sops.yaml&lt;/span&gt;
  &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;local-file&lt;/span&gt; &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;string-append&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;project-root&lt;/span&gt; &lt;span class=&quot;syntax-string&quot;&gt;&amp;quot;/.sops.yaml&amp;quot;&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;syntax-comment&quot;&gt;;; This is because paths on the store
&lt;/span&gt;              &lt;span class=&quot;syntax-comment&quot;&gt;;; can not start with dots.
&lt;/span&gt;              &lt;span class=&quot;syntax-string&quot;&gt;&amp;quot;sops.yaml&amp;quot;&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-special&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;common.yaml&lt;/span&gt;
  &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;local-file&lt;/span&gt; &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;string-append&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;project-root&lt;/span&gt; &lt;span class=&quot;syntax-string&quot;&gt;&amp;quot;/common.yaml&amp;quot;&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;operating-system&lt;/span&gt;
  &lt;span class=&quot;syntax-open&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;services&lt;/span&gt;
    &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;list&lt;/span&gt;
       &lt;span class=&quot;syntax-open&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;]&lt;/span&gt;
       &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;service&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;sops-secrets-service-type&lt;/span&gt;
                &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;sops-service-configuration&lt;/span&gt;
                  &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;gnupg-homedir&lt;/span&gt; &lt;span class=&quot;syntax-string&quot;&gt;&amp;quot;/mnt/.gnupg&amp;quot;&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;
                  &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;generate-key?&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;#t&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;
                  &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;sops.yaml&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;
                  &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;secrets&lt;/span&gt;
                    &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;list&lt;/span&gt;
                      &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;sops-secret&lt;/span&gt;
                        &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-string&quot;&gt;&amp;quot;wireguard&amp;quot;&lt;/span&gt; &lt;span class=&quot;syntax-string&quot;&gt;&amp;quot;private&amp;quot;&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;
                        &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;common.yaml&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;
                        &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;syntax-string&quot;&gt;&amp;quot;user1&amp;quot;&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;
                        &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;group&lt;/span&gt; &lt;span class=&quot;syntax-string&quot;&gt;&amp;quot;users&amp;quot;&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;
                        &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;permissions&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;#o400&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Upon reconfiguration, this will yield the following content at &lt;code&gt;/run/secrets&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;user1@host1:~ $ sudo ls -la /run/secrets/
total 12
drwxr-xr-x 1 root root    50 Jan  2 12:44 .
drwxr-xr-x 1 root root   254 Jan  2 12:44 ..
lrwxrwxrwx 1 root root    53 Jan  2 12:44 .sops.yaml -&amp;gt; /gnu/store/lyhyh91jw2n2asa1w0fc0zmv93yxkxip-sops.yaml
-r-------- 1 user1 users  44 Jan  2 12:44 wireguard
user1@host1:~ $ cat /run/secrets/wireguard/private
MYPRIVATEKEY&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Adding secrets to your &lt;code&gt;home-environment&lt;/code&gt; record&lt;/h3&gt;&lt;p&gt;&lt;code&gt;sops-guix&lt;/code&gt; also provides a Guix Home service that is able to provide most feature of the system service. Most significant limitations are:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;AFAIK &lt;code&gt;home-environment&lt;/code&gt;s can't configure ramfs mount points hence the &lt;code&gt;secrets-directory&lt;/code&gt; option is not available. Secrets are stored in &lt;code&gt;/run/user/$UID/secrets&lt;/code&gt; which usually is mounted on tmpfs.&lt;/li&gt;&lt;li&gt;&lt;code&gt;sops-secret-user&lt;/code&gt; and &lt;code&gt;sops-secrets-group&lt;/code&gt; are ignored. All secrets belong to the user running the Guix comman line but you can still set permissions.&lt;/li&gt;&lt;li&gt;There's no option to automatically generate GPG keys since probably users can easily generate one.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Now, supposing you have your &lt;code&gt;home-environment&lt;/code&gt; file in the same directory where you have your &lt;code&gt;.sops.yaml&lt;/code&gt; and your secrets files, you can simply add the following to your configuration:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;use-modules&lt;/span&gt; &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;sops&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;secrets&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;sops&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;home&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;services&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;sops&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;guix&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;utils&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-special&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;project-root&lt;/span&gt;
  &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;current-source-directory&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-special&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;sops.yaml&lt;/span&gt;
  &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;local-file&lt;/span&gt; &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;string-append&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;project-root&lt;/span&gt; &lt;span class=&quot;syntax-string&quot;&gt;&amp;quot;/.sops.yaml&amp;quot;&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;syntax-comment&quot;&gt;;; This is because paths on the store
&lt;/span&gt;              &lt;span class=&quot;syntax-comment&quot;&gt;;; can not start with dots.
&lt;/span&gt;              &lt;span class=&quot;syntax-string&quot;&gt;&amp;quot;sops.yaml&amp;quot;&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-special&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;user1.yaml&lt;/span&gt;
  &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;local-file&lt;/span&gt; &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;string-append&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;project-root&lt;/span&gt; &lt;span class=&quot;syntax-string&quot;&gt;&amp;quot;/user1.yaml&amp;quot;&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;home-environment&lt;/span&gt;
  &lt;span class=&quot;syntax-open&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;services&lt;/span&gt;
    &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;list&lt;/span&gt;
       &lt;span class=&quot;syntax-open&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;]&lt;/span&gt;
       &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;service&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;home-sops-secrets-service-type&lt;/span&gt;
                &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;home-sops-service-configuration&lt;/span&gt;
                  &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;gnupg-homedir&lt;/span&gt; &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;string-append&lt;/span&gt; &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;getenv&lt;/span&gt; &lt;span class=&quot;syntax-string&quot;&gt;&amp;quot;HOME&amp;quot;&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;syntax-string&quot;&gt;&amp;quot;/.gnupg&amp;quot;&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;
                  &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;sops.yaml&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;
                  &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;secrets&lt;/span&gt;
                    &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;list&lt;/span&gt;
                      &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;sops-secret&lt;/span&gt;
                        &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-string&quot;&gt;&amp;quot;wireguard&amp;quot;&lt;/span&gt; &lt;span class=&quot;syntax-string&quot;&gt;&amp;quot;private&amp;quot;&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;
                        &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;user1.yaml&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;
                        &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;permissions&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;#o400&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Upon reconfiguration, this will yield the following content at &lt;code&gt;/run/secrets/$YOUR_UID/secrets&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;user1@host1:~ $ ls -la /run/user/$(id -u)/secrets
total 12
drwxr-xr-x 1 user1 users    50 Jan  2 12:44 .
drwxr-xr-x 1 user1 users   254 Jan  2 12:44 ..
lrwxrwxrwx 1 user1 users    53 Jan  2 12:44 .sops.yaml -&amp;gt; /gnu/store/lyhyh91jw2n2asa1w0fc0zmv93yxkxip-sops.yaml
-r-------- 1 user1 users    44 Jan  2 12:44 wireguard
user1@host1:~ $ cat /run/user/$(id -u)/secrets/wireguard/private
MYPRIVATEKEY&lt;/code&gt;&lt;/pre&gt;</content></entry><entry><title>Tame Docker selfhosting with Guix</title><id>https://fishinthecalculator.me/blog/tame-docker-selfhosting-with-guix.html</id><author><name>Giacomo Leidi</name><email>therewasa@fishinthecalculator.me</email></author><updated>2023-12-10T16:20:00Z</updated><link href="https://fishinthecalculator.me/blog/tame-docker-selfhosting-with-guix.html" rel="alternate" /><content type="html">&lt;p&gt;Many applications are packaged in &lt;a href=&quot;https://opencontainers.org&quot;&gt;OCI&lt;/a&gt;/Docker images but not in Guix. A good subset of them is written either in NodeJS, Go, Rust or languages that, as a general approach, encourage applications to have huge dependency graphs.&lt;/p&gt;&lt;p&gt;Let's take Grafana as an example. &lt;a href=&quot;https://github.com/grafana/grafana/blob/main/package.json&quot;&gt;According to its &lt;code&gt;package.json&lt;/code&gt;&lt;/a&gt; Grafana's web frontend has more than 180 direct dependencies and more than 170 build time dependencies, for a grand total of ~350 direct dependencies. This is excluding all transitive dependencies. In the same way, Grafana's &lt;a href=&quot;https://github.com/grafana/grafana/blob/main/go.mod&quot;&gt;Go backend&lt;/a&gt; has ~440 direct dependencies. Some of them may be optional, but go figure.&lt;/p&gt;&lt;p&gt;This phenomenon is not uncommon in modern software development, it's not that Grafana is doing worse than everyone else. Yet it's quite problematic, it clearly shows that nobody put the effort of auditing or even reviewing the dependency graph of one of the most used dashboarding application in the industry.&lt;/p&gt;&lt;p&gt;Dissecting the interests which prevent the investment in building software products with a sustainable maintenance process is a topic for another post, the point is that the Guix project accepts package contributions that comply to very strict standards in term of licensing and other criteria, such as whether the package and its dependencies can be completely built from source. It's the reason why practically no NodeJS application (or even web applications with complex frontends, such as Grafana) can be upstreamed to Guix. It is not clear &lt;a href=&quot;https://dustycloud.org/blog/javascript-packaging-dystopia/&quot;&gt;whether they will ever be&lt;/a&gt;, since especially in the Javascript world packages suffer from cyclical dependency which complicate the packaging process even more.&lt;/p&gt;&lt;p&gt;It is very painful to have to package whole dependency graphs just to use some service on the Guix System. This is especially true when you have a goal that you want to achieve and you could use Guix to achieve it, but it does not necessarily involve sending a bunch of patches upstream. It could be that you want to start some Matrix community around Guix or other people-sized technologies, you may want to self host a personal cloud with Nextcloud or maybe you want to setup an accessible monitoring dashboard for your services with Grafana and Prometheus. These are all softwares that do not follow the best sustainability practices, but they are pretty useful to use while we build the alternative technology (also called alt-tech) that we need to survive sustainably in our digital lives.&lt;/p&gt;&lt;h2 id=&quot;container_taming_on_guix&quot;&gt;Container taming on Guix&lt;/h2&gt;&lt;p&gt;If you use &lt;code&gt;docker compose&lt;/code&gt; on the Guix System, you end up having two different interfaces to manage your system services: Shepherd and Docker. The &lt;code&gt;oci-container-service-type&lt;/code&gt; aims at &lt;a href=&quot;https://guix.gnu.org/en/manual/devel/en/guix.html#index-oci_002dcontainer_002dservice_002dtype&quot;&gt;implementing Shepherd Services&lt;/a&gt; that look and feel native (so you can configure and manage them with the usual consistent interface that Guix exposes) but under the hood are implemented as &lt;code&gt;docker run&lt;/code&gt; (or &lt;code&gt;docker rm&lt;/code&gt;) invokations, so that you don't have to package those huge dependency graphs just to start self hosting on Guix.&lt;/p&gt;&lt;p&gt;Next you can find an example of how run Prometheus on the Guix System through the &lt;code&gt;oci-container-service-type&lt;/code&gt;. You just need to add&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;use-modules&lt;/span&gt; &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;gnu&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;services&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;docker&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;gnu&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;services&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;monitoring&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;guix&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;gexp&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-special&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;prometheus.yml&lt;/span&gt;
  &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;plain-file&lt;/span&gt; &lt;span class=&quot;syntax-string&quot;&gt;&amp;quot;prometheus.yml&amp;quot;&lt;/span&gt;
              &lt;span class=&quot;syntax-string&quot;&gt;&amp;quot;global:
  scrape_interval: 30s
  scrape_timeout: 12s

scrape_configs:
  - job_name: prometheus
    metrics_path: /metrics
    static_configs:
      - targets: ['localhost:9090','localhost:9100']\n&amp;quot;&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;operating-system&lt;/span&gt;
  &lt;span class=&quot;syntax-open&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;services&lt;/span&gt;
    &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;list&lt;/span&gt;
      &lt;span class=&quot;syntax-open&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;syntax-comment&quot;&gt;;; Prometheus node exporter
&lt;/span&gt;      &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;service&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;prometheus-node-exporter-service-type&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;syntax-comment&quot;&gt;;; Prometheus OCI backed Shepherd service
&lt;/span&gt;      &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;simple-service&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;oci-container-service-type&lt;/span&gt;
                      &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;list&lt;/span&gt;
                        &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;oci-container-configuration&lt;/span&gt;
                          &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;command&lt;/span&gt;
                            &lt;span class=&quot;syntax-symbol&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-string&quot;&gt;&amp;quot;--web.enable-lifecycle&amp;quot;&lt;/span&gt;
                              &lt;span class=&quot;syntax-string&quot;&gt;&amp;quot;--config.file=/etc/prometheus/prometheus.yml&amp;quot;&lt;/span&gt;
                              &lt;span class=&quot;syntax-string&quot;&gt;&amp;quot;--web.enable-admin-api&amp;quot;&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;
                          &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;image&lt;/span&gt; &lt;span class=&quot;syntax-string&quot;&gt;&amp;quot;prom/prometheus:v2.45.0&amp;quot;&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;
                          &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;ports&lt;/span&gt;
                            &lt;span class=&quot;syntax-symbol&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-string&quot;&gt;&amp;quot;9000&amp;quot;&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;syntax-string&quot;&gt;&amp;quot;9000&amp;quot;&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;
                              &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-string&quot;&gt;&amp;quot;9090&amp;quot;&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;syntax-string&quot;&gt;&amp;quot;9090&amp;quot;&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;
                          &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;volumes&lt;/span&gt;
                            &lt;span class=&quot;syntax-symbol&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-string&quot;&gt;&amp;quot;/var/lib/prometheus&amp;quot;&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;syntax-string&quot;&gt;&amp;quot;/prometheus&amp;quot;&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;
                              &lt;span class=&quot;syntax-open&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-symbol&quot;&gt;,prometheus.yml&lt;/span&gt; &lt;span class=&quot;syntax-symbol&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;syntax-string&quot;&gt;&amp;quot;/etc/prometheus/prometheus.yml:ro&amp;quot;&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-close&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;to the &lt;code&gt;services&lt;/code&gt; field of your &lt;code&gt;operating-system&lt;/code&gt; record. In this example it's also shown how to install the Prometheus node exporter to collect metrics from the host.&lt;/p&gt;&lt;p&gt;This approach obviously is lacking in reproducibility and bootstrappability, but in my experience often users need some software that is not yet guixable (i.e. possible to include in Guix upstream) so they choose to use Nix or something else entirely.&lt;/p&gt;&lt;h2 id=&quot;what's_next?&quot;&gt;What's next?&lt;/h2&gt;&lt;p&gt;The &lt;code&gt;oci-container-service-type&lt;/code&gt; implements Shepherd services through Docker containers, but a Shepherd service is only a small block in the implementation of a nicely integrated Guix System service. To provide a secure, consistent and integrated experience a Guix System service may declare user accounts, to allow for less then root authority execution, or it may initialize some state upon activation: all things for which an additional service extension is required.&lt;/p&gt;&lt;p&gt;This is why I'm implementing a &lt;a href=&quot;https://github.com/fishinthecalculator/gocix&quot;&gt;library of (hopefully) community maintained Guix System services&lt;/a&gt; for many common self hostable applications such as Matrix Conduit, Forgejo, Grafana and more. These services try to be as similar as possible to an upstream provided service, in the hope of being upstreamed as soon as the underlying dependency graph is packaged.&lt;/p&gt;</content></entry></feed>