Vault documentation and code encourage passing unseal keys on the command line
Describe the bug
A variety of places in the Vault documentation and code encourage operators to pass unseal keys on the command line, or don't appropriately discourage them.
Passing unseal keys on the command line is vulnerable not only to being stored in shell history, it's also visible to anybody on the same machine. i can pretty consistently see an unseal key passed on the command line with a command like:
$ vault operator unseal aeouaeouaoeu & ps -ocmd | grep [v]ault
[1] 1846022
vault operator unseal aeouaeouaoeuObviously winning this race is harder if vault and ps aren't being spawned from the same shell, but I expect that malware could easily continuously monitor commands on the machine to extract the key.
Locations that encourage passing unseal keys on the command line:
- Most prominently,
vault operator unsealrejects passing unseal keys on stdin. According toecho | vault operator unseal, "You should run the unseal command from a terminal for maximum security. If this is not an option, the unseal key can be provided as the first argument to the unseal command. The raw error was: file descriptor 0 is not a terminal". I am not aware of a realistic Linux security model in which passing a secret on stdin is less secure than passing it on the command line, so I'm unclear whyvault operator unsealblocks the former and allows the latter. - The sealing best practices suggest storing unseal keys in encrypted form, but there's no real guidance on how to decrypt unseal keys and feed them into Vault, and doing it safely is surprisingly tough -- the most natural approach,
gpg --decrypt unseal.gpg | vault operator unsealwon't work, and the (probably) next most obvious approach (vault operator unseal $(gpg --decrypt unseal.gpg)) can leak keys. - The operator unseal docs calls out that a command like
vault operator unseal aoeuoaeuwill leave the key in the shell history, butvault operator unseal $(gpg --decrypt unseal.gpg)wouldn't be vulnerable to that so people reading the docs might think that's safe. The docs should also call out that the argument is visible to anybody else on the machine in appropriately-timedpsoutput, even if the key isn't literally typed on the command line. - There's a tutorial to Use PGP encrypted key shares (that concept seems great -- that seems like the right way for people who aren't doing auto-sealing to manage keys), but the tutorial simply says to unseal using
vault operator unseal $(gpg --decrypt /root/.gnupg/alice_unseal_key.dat)-- there's no caveat about the confidentiality issues with that. There's also a version for "API call using cURL", which similarly appears to leak the key.
To Reproduce
i can pretty consistently see an unseal key passed on the command line with a command like:
$ vault operator unseal aeouaeouaoeu & ps -ocmd | grep [v]ault
[1] 1846022
vault operator unseal aeouaeouaoeuExpected behavior
These four pieces of documentation (and potentially others) should provide or link to secure ways to unseal Vault. Given the current vault operator unseal, this probably looks like a curl command that assembles the right JSON.
However, in my opinion, gpg --decrypt unseal.gpg | vault operator unseal should work. As previously described, I can't think of a reason that's less secure than vault operator unseal foo, which is supported. While I have some sympathy to an attitude of "If the vault CLI exposes every possible way to interact with the underlying API it'll be a bad case of second system syndrome.", extending a command that already accepts interactive entry of a key to also accept the key on stdin hardly seems excessive. Part of the argument against changing vault operator unseal was that there are other approaches available, but one approach in the thread accidentally leaks keys as well and the other I saw is convoluted to actually implement. For one of the most sensitive secrets in a secret-management tool, I think there should be a straightforward, intuitive way to enter it automatically that doesn't risk minor tweaks leaking the key, and I don't think we have that right now.
(Honestly, the fact that the recommended unseal approach is to type a key in interactively is wild to me. Echo is disabled on entry, but most people presumably don't memorize their unseal keys. That suggests that people are e.g. GPG-encrypting the unseal keys, and then presumably decrypting it to the screen and copy/pasting the keys back in, so I would guess most unseal keys show up on screen anyway. It's possible people are using a copy button in a password manager or something like gpg --decrypt unseal.gpg | xclip, but I'd guess that's less common -- and all of these mean the keys are on the clipboard, for any apps that monitor that. Something like gpg --decrypt unseal.gpg | vault operator unseal would mean the unseal keys are decrypted for a matter of milliseconds, never appearing on screen, disk, or clipboard.)
Source: hashicorp/vault