hraban / secrets-trampoline

Bake a secret into a binary with execute-only permissions

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Bake Secrets into Executables

Use Nix to bake a secret into an executable without allowing read access to the raw secret for non-root users, just execute.

This example creates a binary in /var/run/secrets-trampolines/backup-to-s3 which is executable but not readable by user “john”:

{
  inputs.secrets-trampoline.url = "github:hraban/secrets-trampoline";
  # ...

  outputs = {
    nix-darwin
    , secrets-trampoline
    , ...
  }: {
    darwinConfigurations = {
      MyHost = nix-darwin.lib.darwinSystem {
        # ...

        modules = [
          secrets-trampoline.darwinModules.default

          (
            { pkgs, config, inputs, ... }:
            {
              #...

              secrets-trampoline = {
                programs = {
                  backup-to-s3 = {
                    drv = pkgs.writeShellScriptBin "backup-to-s3" ''
                      ${pkgs.restic}/bin/restic backup -r s3:https://s3.amazonaws.com/my-bucket ~
                    '';
                    users = [ "john" ];
                    secrets.RESTIC_PASSWORD = "backup-encryption";
                    secrets.AWS_ACCESS_KEY_ID = "aws-key-id";
                    secrets.AWS_SECRET_ACCESS_KEY = "aws-secret-key";
                  };
                };
                secrets = {
                  aws-key-id = {
                    type = "1Password";
                    vault = "Family";
                    item = "hbb3ohvwtudves6jxpe7zfjhdm";
                    entry = "key id";
                  };
                  aws-secret-key = {
                    type = "1Password";
                    vault = "Family";
                    item = "hbb3ohvwtudves6jxpe7zfjhdm";
                    entry = "secret key";
                  };
                  backup-encryption = {
                    type = "1Password";
                    vault = "Personal";
                    item = "s6jxpe7zfjhdmhbb3ohvwtudve";
                    entry = "backup encryption key";
                  };
                };
                # Included here as a demonstration, though this specific reader
                # is provided by default
                secretReader."1Password" = { vault, item, entry }: ''
                  ${pkgs._1password}/bin/op read "op://${vault}/${item}/${entry}"
                '';
              }
            }
          )

        ];
      };
    };
  };
}

(assuming you use flakes)

The secret is read once from 1Password, when you run nix-darwin switch.

It’s useful for background tasks that you trust with a secret, but where you don’t want just any process with file-read access on your OS to have access to that secret.

The usual solution to secret provisioning on servers is to just have the secret available as a file on your disk, but on regular desktop computers that can be too open. Another solution is to use a vault like Keychain or 1Password, but that breaks down for background services.

Safety

There is at least one vulnerability: while “baking”, the secret is temoprarily on a subprocess’ argv. This is generally considered bad practice because argv of running processes is easy for other processes to view.

The actual safety of your secret of course depends on the nested application not leaking it. If e.g. you baked something as general purpose as vim, you might as well just put the secret directly in a plain text file.

About

Bake a secret into a binary with execute-only permissions

License:GNU Affero General Public License v3.0


Languages

Language:Nix 100.0%