Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sops.template docs with systemd DynamicUser #412

Open
johnjameswhitman opened this issue Sep 30, 2023 · 2 comments
Open

sops.template docs with systemd DynamicUser #412

johnjameswhitman opened this issue Sep 30, 2023 · 2 comments

Comments

@johnjameswhitman
Copy link

Thanks for adding sops.template -- it really simplified getting a key into my inadyn service.

Along the way I learned that you can pass credentials into a systemd unit that runs w/ DynamicUser = true. The key bit in the example below is LoadCredential = "inadyn.conf:${config.sops.templates."inadyn.conf".path}";, which exposes the template to the unit at ${CREDENTIALS_DIRECTORY}/inadyn.conf.

Wonder if it'd be worth updating the docs with these bits since I think it's pretty common to set the DynamicUser for better security? If not, figure at least having an example in this issue could be helpful to others in the future.

  sops = {
    defaultSopsFile = ./secrets.yaml;
    age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
    secrets."inadyn/some_tld" = { };
    templates."inadyn.conf" = {
      content = ''
        custom namecheap { 
          username    = some.tld
          password    = ${config.sops.placeholder."inadyn/some_tld}
          ddns-server = dynamicdns.park-your-domain.com 
          ddns-path   = "/update?domain=%u&password=%p&host=%h" 
          hostname    = "some.tld"
        }
      '';
    };
  };

  systemd.timers.inadyn = {
    description = "Sync inadyn every hour";
    wantedBy = [ "default.target" ];
    timerConfig = {
      OnBootSec = "60m";
      OnUnitActiveSec = "60m";
    };
  };

  systemd.services.inadyn = {
    description = "Syncs home IP to dynamic DNS.";
    requires = [ "network-online.target" ];
    serviceConfig = {
      DynamicUser = true;
      Type = "oneshot";
      ProtectSystem = "strict";
      ProtectHome = true;
      PrivateUsers = true;
      PrivateTmp = true;
      LoadCredential = "inadyn.conf:${config.sops.templates."inadyn.conf".path}";
      CacheDirectory= "inadyn";
      ExecStart = ''
        ${pkgs.inadyn}/bin/inadyn \
          --foreground \
          --syslog \
          --once \
          --cache-dir ''${CACHE_DIRECTORY} \
          --config ''${CREDENTIALS_DIRECTORY}/inadyn.conf
      '';
    };
  };
@Mic92
Copy link
Owner

Mic92 commented Oct 3, 2023

Does systemd replace ${CREDENTIALS_DIRECTORY}/inadyn.conf in ExecStart? Didn't knew that.

@johnjameswhitman
Copy link
Author

Yep -- Here are a few key snippets from the systemd docs:

The data is accessible from the unit's processes via the file system, at a read-only location that (if possible and permitted) is backed by non-swappable memory. The data is only accessible to the user associated with the unit, via the User=/DynamicUser= settings (as well as the superuser).

The LoadCredential= setting takes a textual ID to use as name for a credential plus a file system path, separated by a colon.

In order to reference the path a credential may be read from within a ExecStart= command line use "${CREDENTIALS_DIRECTORY}/mycred", e.g. "ExecStart=cat ${CREDENTIALS_DIRECTORY}/mycred".

Apparently this came out with v247 which released in 2020, so it's relatively recent.

Note: Systemd ran into an issue loading the credential when the name of my sops.template lead with a / (e.g. /etc/inadyn.conf instead of just inadyn.conf), I think because the resulting file path included a double-slash //.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants