Live data from Hacker News

How to handle secrets on the command line

smallstep.com

61–70 of 77 posts

Re: How to handle secrets on the command line

#61
I’ll add onto this: if at all possible, secrets should be short lived and rotated reasonably often.

Given enough time and enough secrets, it becomes asymptotically likely that a secret will become exposed. Ensuring that those secrets expire quickly is a good way to mitigate this.

Re: How to handle secrets on the command line

#62

I'm currently using Doppler ( https://www.doppler.com/ ) but I'm not sure if it sidesteps the issues outlined in the article.

Doppler solves this problem by storing your secrets in the cloud *hand wave*.

In actuality, the Doppler CLI (a Go binary) fetches your secrets from Doppler's API and injects them as environment variables into your specified process. That looks something like `doppler run -- printenv`. This prevents your secrets from being written to the filesystem in plain text, and prevents the environment variables from being available more broadly. In the case of docker, you would bake the Doppler CLI into your image, thereby sidestepping the documented `docker inspect` pitfall.

Of course, the CLI still needs a way of authenticating to Doppler's API. You authenticate and authorize the CLI by running `doppler login`. This initiates a login flow that you complete in your browser. Once completed, your newly generated auth token is sent back to the CLI. The CLI then saves the auth token to your system keyring for later use. The identifier needed to access that keyring entry is then stored in plain text in the CLI's config file (~/.doppler/.doppler.yaml), which is only readable by the user.

We're exploring other means of injecting your secrets into your application, as some users are wary of using environment variables. This is a challenging problem though as there are few means of injecting secrets that don't require substantially changing your application's logic.

Re: How to handle secrets on the command line

#64
post #63

What does sanitizing ps outputs protect you from? Untrusted non-root users in the same machine?

Yes. If someone manages to gain a foothold on the machine running the process they would not instantly be able to elevate privileges. Of course the happier scenario includes no hackers on your machines, but why dig yourself a deeper hole?

Re: How to handle secrets on the command line

#65
post #40
post #27

Earlier quoted context omitted.

That's not what I experienced. Is it just way worse for different locations (NZ here)? It's not opt-out by default; I had to turn off advertising and analytics cookies manually. The cookie consent pop-up takes up a third of a big mobile screen. As well as "Continue to site", it has buttons for "Policies", "Preferences", "Do not sell my personal information", and "Powered by CLM". Cookie pop-ups need to die. Non-essen…

That's strange. Maybe it defaults to opt-out only in the EU? While it's not entirely unobtrusive, especially on mobile, it's far better than similar forms on most other sites that usually take up the bottom half of the screen, or block the content entirely behind a modal dialog. > As well as "Continue to site", it has buttons for "Policies", ... Those others aren't buttons, but links, and small ones. The most promine…

> If you've seen most other consent forms, rejecting cookies (if possible at all) is usually done via a small link next to a prominent "Accept all" button and other such dark patterns.

That's exactly how this one works for me. The prominent "Continue to site" is "Accept all" in disguise, and to opt out you need to click on the little "Preferences" button/link. It's the same dark pattern as usual, not a UX improvement.

Re: How to handle secrets on the command line

#66
post #9

Sidenote: I really like the cookie consent form on this site. It's unobtrusive, clear, opt-out by default and the highlighted and only button is "Continue to site". And it even has a built-in GDPR request form! Bravo to https://www.clym.io/ Nice article, covers the basics well. Credential files seem like simplest way to go and are secure enough for most local uses. For anything more involved a secrets manager is prob…

It makes me feel weird that I have the option to “fill a form to not sell my personal data” though.

It almost feels like satire.

Re: How to handle secrets on the command line

#67
post #54

I have been asking myself lately: Without considering resources or practicality, if we were to re-design computers and servers from security-first principles, what would features like management of secrets look like? Secure enclaves are wonderful but the secret still has to be propagated or used. A ground up computer design might greatly embellish on the idea of a secure enclave. Linux seems a bit of a dinosaur in th…

Can you really lay blame on the kernel though? All of this stuff with secrets is happening in userspace and mostly at the shell. If anything, systemd would probably be the place you'd want to build a secret storage system--perhaps build something API driven similar to Hashicorp's vault.

edit: Apparently systemd now has an option to pass secrets/credentials to a service through a more secure by default (i.e. only stored in memory) file option: https://www.freedesktop.org/software/systemd/man/systemd.exe...

Re: How to handle secrets on the command line

#68
post #34

In the programming language I’m working on, MethodScript, I’ve created a subclass of string, secure_string. The normal print value is “secure string”. Unlike somewhat equivalent classes in other languages, this is a subclass of string, which means it can be passed around opaquely to things that only accept strings, but then the functions that actually need to be aware of secrets can check for the subclass and call th…

> the functions that actually need to be aware of secrets can check for the subclass I feel like this is an antipattern in OOP. Shouldn’t the functions just be defined to take in parameters of type SecureString instead? I think this violates the liskov substitution principle ( https://en.m.wikipedia.org/wiki/Liskov_substitution_principl... ). For example, how is the “length” function or “startsWith” defined on Secure…

Yeah, that's a decent point. To answer your question, it's as if it's the string "*secure string*" for the purposes of other string methods.

I think this is a good point, and perhaps worth considering, but in most of my thought exercises, it's worth it, owing to the fact that when I use SecureString in other languages, I find myself having to decrypt the string more often than I would like. I guess one could argue that this is a deficiency of the libraries and such that are used, rather than a deficiency of the fact that SecureString doesn't extend String. I'm having trouble recalling a specific example right now, but I know I've run into it before, because that's what prompted me to implement this many years ago.

Re: How to handle secrets on the command line

#69
post #28

Earlier quoted context omitted.

Sounds similar to Powershell's SecureString, if you want to compare vs a non-"toy" equivalent.

In isolation, yes, but my version is a subclass of string, which adds another layer of functionality on top of the base feature set.

I fear that this design violates the so-called "substitution principle", which states you should be able to use instances of a subclass anywhere instances of the parent class are used. In this case, you have defined a default behavior, but I would argue it's degenerate, because the value of your subclass are all the same.

In general, it's better to design subclasses to be constrained versions of the parent. If you want to add functionality to a class you're better off using another technique like composition, or even just a simple utility method.

Another way to state the issue here is that a user of an encrypted string will always need to know that it is an encrypted string because the only thing cyphertext is useful for is feeding the decryption algorithm.

Re: How to handle secrets on the command line

#70
post #34

Earlier quoted context omitted.

> the functions that actually need to be aware of secrets can check for the subclass I feel like this is an antipattern in OOP. Shouldn’t the functions just be defined to take in parameters of type SecureString instead? I think this violates the liskov substitution principle ( https://en.m.wikipedia.org/wiki/Liskov_substitution_principl... ). For example, how is the “length” function or “startsWith” defined on Secure…

Yeah, that's a decent point. To answer your question, it's as if it's the string "*secure string*" for the purposes of other string methods. I think this is a good point, and perhaps worth considering, but in most of my thought exercises, it's worth it, owing to the fact that when I use SecureString in other languages, I find myself having to decrypt the string more often than I would like. I guess one could argue th…

> Yeah, that's a decent point. To answer your question, it's as if it's the string "secure string" for the purposes of other string methods.

That’s a problem because you are enforcing all your functions accepting normal strings to either have to check if it’s NOT a SecretString or to return some nonsense. For exemple a function that returns the 2 firsts characters without caring about secret string could be passed one as argument and return « *s ».

The Liskov Substitution Principle states that a function accepting an Animal (a String) should never care about wether it’s a Cat (a Secret) and don’t fear Animal (String) methods to return meaningful values.

Post reply on HN