Howdy Lemmy,

I’m announcing Rook v0.0.9, software that provides a secret service a-la secret-tool, keyring, or pass/gopass, except backed by a Keepass 4.x kdbx file.

The problem Rook solves is mainly in script automation, where you have aerc, offlineimap, isync, vdirsyncer, msmtp, restic, or any other cron jobs that need passwords and which are often configured to fetch these passwords from a secret service with a CLI tool. Unlike existing solutions, Rook is headless and does not have a bespoke secrets database, full of passwords that must be manually synchronized with Keepass; instead, it uses a Keepass db directly.

While the readme goes into more detail, I will say the motivation for Rook evolved from a desire to use a Keepass db in a GUI-less environment and finding no existing solutions. KeepassXC provides a secret service, but is not headless; it also provides a CLI tool, but this requires the db credentials on every call. kpmenu exists, but is designed specifically to require human interaction and is unsuitable for cron environment scripting. Every other solution maintains its own DB back end, incompatible with Keepass.

Rook also benefits from minimal external dependencies, and at 1kloc is auditable by developers - I believe even by ones who do not know Go (the language of implementation). Being able to verify for yourself that there’s no malicious code is a critical trait for a tool with which you’re trusting secrets.

Rook is fit for purpose, and signed binaries are provided as well as build-from-source instructions (for auditors).

The project contains work in progress: credentials are limited to simple password-locked kdbx, and so doesn’t yet support key files. Bash scripts that provide autotyping and attribute/secret selection via rofi, fzf, and xdotool are provided, for GUI environments; these have known bugs. Rook has not been tested on BSD, Darwin, or any other system than Linux, but may well work; the main sticking point is the use of a local file socket for client/server communication, so POSIX systems should be fine, but still, YMMV.

As a final caveat: up until v0.0.9 I’ve been compressing with brotli, which is very nice yet somewhat obscure. With the next release, everything will be gzipped. Also included in the next release will be packages for various distributions.

  • d3Xt3r@lemmy.nz
    link
    fedilink
    arrow-up
    1
    ·
    edit-2
    8 months ago

    This looks interesting! I haven’t had a chance to try it yet, but I’ve got a couple of questions:

    • Is the password in ROOK_PASSWORD stored in plain text?
    • When the database is unlocked by rook, can KeepassXC still be used to save entries to the same file?
    • 𝕽𝖚𝖆𝖎𝖉𝖍𝖗𝖎𝖌𝖍OP
      link
      fedilink
      arrow-up
      1
      ·
      8 months ago

      Thanks!

      1. Yes. And no. The one external dependency Rook uses is tobischo’s gokeepasslib to manage all things related to Keepass, and that doesn’t store the password in plain text. Neither does Rook, intentionally, but there was a flag that was holding onto it; now that you’ve pointed it out, I’ve changed that. It’s in v0.1.0, which I’ll push in a sec. This isn’t an issue in v0.0.9 if you use the open client command, because the password is used in a local variable and not in the flags lib, and exits scope immediately after the DB is opened.
      2. Yes. Every time Rook accesses the DB, it checks the timestamp and if the file has changed, it reloads the the db.

      However: if you’re concerned about memory dumps by bad actors, do not use Rook. Do not use any secret service tool; do not use KeepassXC. All of these are susceptible to attacks by any account that can do memory dumps; but memory dumps are probably the least of your concerns if root is compromised.

      I discuss this in the Security section of the readme.

      • d3Xt3r@lemmy.nz
        link
        fedilink
        arrow-up
        1
        ·
        edit-2
        8 months ago

        Sorry, so to clarify the first point - are you’re saying that the ROOK_PASSWORD is in plain text? Or is the password encrypted by gokeepasslib and that encrypted text is what is stored in the variable? The security section doesn’t really detail this.

        • 𝕽𝖚𝖆𝖎𝖉𝖍𝖗𝖎𝖌𝖍OP
          link
          fedilink
          arrow-up
          1
          ·
          8 months ago

          Clarifying this point in the readme is a good suggestion.

          The password supplied to Rook is plain text, whether environment variable, prompt, or even the (discouraged) command line argument.

          gokeepasslib keeps a hashed version of the credentials, but the credentialing is with plaintext passwords.

          • d3Xt3r@lemmy.nz
            link
            fedilink
            arrow-up
            1
            ·
            8 months ago

            Hmm in that case, would it be possible to have a separate utility/command to generate a secure string so I can store it in ROOK_PASSWORD persistently, without any manual promoting later on? Basically I don’t want to store a plain-text password in an environment variable.

            I’m not worried about root access btw, my use case is in a production multi-user environment. I want automated scripts to be able to pull secrets from our Keepass db without needing to prompt for a password, so I need that environment variable to persist across reboots - which means populating it via a .bashrc or pam_env etc - but that means you’re now storing your plain text master password on disk.

            Either way, there’s a risk that the environment variable could be read by any other programs running under the same user context, so it would be great if it can be encrypted.

            • 𝕽𝖚𝖆𝖎𝖉𝖍𝖗𝖎𝖌𝖍OP
              link
              fedilink
              arrow-up
              1
              ·
              8 months ago

              Interesting use case. For your use case, is there a reason you’re not using pass (or the more self-contained but compatible gopass)?

              What you’re suggesting wouldn’t be difficult; it’d be a sort of ratchet where the password is encrypted and passed through, and then decrypted by Rook. You’d still need to supply Rook with the decryption key, which gets you back to just prompting again.

              But I see the plight: you might be using Vault and needing to start Rook with credentials. You can’t use -P, because it’s interactive; you don’t want to use 12-Factor, because it exposes passwords.

              Would an acceptable solution be if Rook accepted the password on stdin? I intend to implement the key file authentication mechanism, which might also be a solution for your use case.