
Show HN: Cryptic – A sensible secret management toolkit and Go library - domodwyer
https://github.com/domodwyer/cryptic
======
eropple
So this is a neat idea, because Credstash and Sneaker are certainly not
perfect gizmos, but it leads to the turtles problem: how do I securely handle
the initial key that's being plopped on systems? If I can do that, I don't
need Cryptic.

I've become a big fan of Credstash over the last few months largely because it
solves (well, more like _makes irrelevant_ , I wouldn't really strongly say
it's "solved") this problem through using AWS as a trusted third party.
Further, Credstash actually handles key ACLs in a much, much smarter way in
that it uses KMS encryption contexts, which can be dropped into an IAM
policy's Condition block, to further restrict access to secrets. Cryptic
doesn't seem to offer this, and its use of Redis as a backing store (itself
intended to be used in trusted environments) makes me worried, too.

If continuing along with this project--and please don't take this as
discouraging, it seems largely reasonable as a thing!--I would look in more
depth at how Credstash uses KMS and bloodily rip it off to improve Cryptic's
KMS functionality; it's very, very good at what it's doing.

~~~
ak217
Credstash looks great, but having written something very similar for internal
use (a secrets management system using KMS and S3 for use by EC2 instances) I
was expecting it to have built in functionality to manage IAM policies the way
you describe. Otherwise I'm not sure how this restricts different roles from
accessing each other's secrets, which is the essential part of defense in
depth for secret management.

For example, with S3, I have been defining IAM policies that restrict each
role's access to just the secrets granted to that role, with a prefix-
conditional IAM statement. You can further define similar parameterized
policies for IAM users and groups without even enumerating their names.

~~~
eropple
As mentioned, KMS uses encryption contexts (a set of key-value pairs) to
namespace your secrets. KMS won't decrypt the data key if you aren't in the
key policy or your IAM policies don't allow access to that particular
encryption context.

You're doing it at the S3 object level (presumably with a single KMS key?).
Credstash does it at the KMS access level. Both are roughly equivalent, but
Dynamo accesses are a lot cheaper in my neck of the woods than S3 accesses.

~~~
ak217
It seems to me that cost is negligible for any of the use cases. The KMS CMK
cost will dominate access cost in my estimation. I see that Credstash cites
latency as a factor in favor of S3, which is not a major factor if you
retrieve a secret only once in a while and put it into memory, but could
enable cool use cases where you really retrieve it on demand. S3 does have
other advantages - ease of use and granularity of IAM access control, I think.

The Credstash documentation and code lead me to believe you are responsible
for managing your own IAM policies - it won't set the policies in credential
writer mode. Is that not correct? I expect this functionality to be part of
the secret manager.

~~~
eropple
_> I see that Credstash cites latency as a factor in favor of S3, which is not
a major factor if you retrieve a secret only once in a while and put it into
memory_

Sorry, I wasn't clear. I meant "cheaper" in terms of time. I have a _lot_ of
machines in flight at any time, and I do actively roll credentials--chef-zero
runs every five minutes and pulls credentials out of Credstash. S3 accesses
add latency, which slows my converges (sometimes by a lot; I currently have
around ~25 secret lookups in one particular Chef run).

 _> I expect this functionality to be part of the secret manager._

I'm not saying you're _wrong_ to want that, but I'm very skeptical of it--
extremely skeptical. I can't envision a situation where I'd rather have policy
management as part of the secret manager as opposed to part of my provisioning
infrastructure. My KMS accesses are in IAM roles; there is no situation in
which I would _ever_ want Credstash to manage those, because I have other
stuff in them! I build my policies in CloudFormation, just like I do
everything else.

If anything, my biggest criticism of Credstash is that it has a hardcoded
table name that I'd rather was an environment variable so that I could
establish that via CloudFormation and dump it into an env var via Chef.

~~~
ak217
In many cases, I think the secret manager should be part of your provisioning
infrastructure. There are certainly other reasonable ways to structure this
though - as long as you're clear on your threat model.

Would you agree that the secret manager should at least print out a
_suggested_ IAM policy for you to use? IAM policies are complex, tricky, and
easy to mess up. I think it should absolutely be the job of the secret manager
to at least sanity check your policies, if not write them directly.

> S3 accesses add latency [vs dynamodb], which slows my converges

That's useful to know, thanks.

~~~
eropple
I don't find IAM policies to be tricky, to be honest. It may just be
familiarity; I have been doing this for a little bit of time now. I'm also not
really sure what sort of interface for generating those policies without
introducing to the secret manager its own notion of "policies"\--at which
point you're duplicating effort and work.

(I also wouldn't be able to use any policy spat out by the tool in the first
place--I use a Cfer, Ruby DSL, to generate CloudFormation and all I'd be doing
is transliterating it over.)

~~~
ak217
> I don't find IAM policies to be tricky, to be honest. It may just be
> familiarity; I have been doing this for a little bit of time now.

Then you are an elite AWS operator, but you also have to think about how to
teach and review work from other, less skilled operators working with you. In
my experience it's not easy at all to do that with something as critical as
IAM, so when I'm orchestrating resources, I heavily rely on IAM policy
automation and built-in sanity checks.

~~~
eropple
My policies are automated. I wrote the automation. :) And thank you for the
compliment, but I wouldn't call myself "elite", merely "pretty good".
Seriously, this is _literally all it is_ :

    
    
       def kms_read_policy(contexts)
         contexts.map do |context|
           {
             PolicyName: "kms-read",
             PolicyDocument: {
               Version: '2012-10-17',
               Statement: [
                 {
                   Effect: 'Allow',
                   Action: 'kms:Decrypt' ,
                   Resource: [
                     Cfer.cfize('arn:aws:kms:C{AWS.region}:' \
                               'C{AWS.account_id}:key/C{Fn.ref(:CredstashKey)}')
                   ],
                   Condition: {
                     StringEquals: 
                       context.map do |k, v|
                         [ "kms:EncryptionContext:#{k}", v ]
                       end.to_h
                   }
                 }
               ]
             }
           }
         end.to_a
       end
    

And a single DynamoDB policy in a managed policy that allows for querying the
`credential-store` table. This just is not rocket science. It's helped by
cfer[0] and cfer-provisioning[1] being pretty great, but it's very achievable.

[0] -
[https://github.com/seanedwards/cfer](https://github.com/seanedwards/cfer)

[1] - [https://github.com/seanedwards/cfer-
provisioning](https://github.com/seanedwards/cfer-provisioning) (I'm a
maintainer)

------
RussianCow
I don't know much about secret management. How does this compare to something
like Vault?

Edit: [https://www.vaultproject.io/](https://www.vaultproject.io/)

~~~
pibefision
Can this be used to replace apps like 1Password for a skilled user?

~~~
tptacek
That would be a bad idea, since (a) 1Password (at least in standalone mode)
has been vetted crypographically, and (b) most of the security problems of
password management aren't cryptographic.

~~~
pibefision
thank you

------
FiloSottile
This is exactly the use case of
[https://github.com/gtank/cryptopasta](https://github.com/gtank/cryptopasta)

Although, the only thing I can see it doing wrong is the use of passwords as
keys
[https://github.com/domodwyer/cryptic/blob/6bd92fab6778dac26c...](https://github.com/domodwyer/cryptic/blob/6bd92fab6778dac26cf48fcbc7658ee579421dc9/examples_test.go#L17-L18)
which is still an open issue in cryptopasta
[https://github.com/gtank/cryptopasta/issues/7](https://github.com/gtank/cryptopasta/issues/7)

~~~
domodwyer
They're only there as an easy-to-read example, the library fully supports
binary keys if that's what you're getting at?

~~~
tptacek
A secure storage system shouldn't _allow_ passwords as keys. If passwords are
a thing that is going to happen, the API should be structured so that those
passwords get run through a KDF. That's what he's getting at.

~~~
domodwyer
You're absolutely right.

PBKDF2 incoming.

~~~
tptacek
You can do that, but a better API design is one that simply ensures keys are
always random. KDF'd passwords are still weaker than real cryptographic keys.

A common design pattern is to use KDF keys as key-encrypting keys wrapping
fully random keys. The system in steady-state relies only on the fully random
key; the KDF key, depending on the design, can sometimes be kept offline. This
is how SSH and GPG handle keys: note how the actual keys the system uses are
fully random and totally out of the user's hands.

But you might not need any of this mechanism at all; it might be totally
possible to design this system such that keys are simply blobs, generated via
urandom by reading crypt.Rand.

------
gregwebs
I went with biscuit because it writes to a simple file and I am not worried
about updating 2 secrets at once, particularly since I have a different file
per app per environment.
[https://github.com/dcoker/biscuit/blob/master/README.md](https://github.com/dcoker/biscuit/blob/master/README.md)

------
ique
Its interesting to see a lot of alternative implementations of credstash pop
up, there was one written in Haskell recently called "credentials".
[https://github.com/brendanhay/credentials](https://github.com/brendanhay/credentials)

------
Natales
It's always good to see options out there. But honestly, having being working
with Hashicorp's Vault for a while
([https://www.vaultproject.io/](https://www.vaultproject.io/)) I really don't
see the need for it. Vault is extremely simple to setup and has many more
advanced features without sacrificing functionality. There is also Keywhiz
([https://square.github.io/keywhiz/single_page.html](https://square.github.io/keywhiz/single_page.html))
which also provides a nifty FUSE abstraction.

------
hamandcheese
The readme doesn't say what databases are supported, and similarly the config
example config file doesn't have a field to configure this either.

The only clue is the example SQL for creating the table appears to be MySQL.
Is Postgres supported?

~~~
domodwyer
The binaries don't support Postgres (though it's a 2 minute job to add)
because the drivers aren't included in the build, though the library can
support it.

The underlying SQL uses "?" as a parameter binding placeholder, Postgres uses
$1, $2 right?

Seems like an obvious oversight, I can put up a build if you're willing to
test it?

------
ketralnis
Cool! I've love to hear more about the security and crypto design. I started
writing up some questions but after asking so many it feels like I should just
check out the code and answer some of them for myself. Still, I left the
discussion here in case you're interested :)

I've been working on a similar tool in Rust:
[https://github.com/ketralnis/secrets](https://github.com/ketralnis/secrets).
My focus has been less APIs and more person-to-person (e.g. sharing the team's
twitter password between humans that need to use it) but I'd love to hear how
you've solved some of the conceptual problems that I've struggled with in
trying to make it secure.

Some issues that I've struggled with:

1\. withstanding attacks on the file format, some of which are described in
this paper:
[https://www.cs.ox.ac.uk/files/6487/pwvault.pdf](https://www.cs.ox.ac.uk/files/6487/pwvault.pdf).
My answer has been the logging system that I talk about in Auditing below but
I'd love to hear how you withstand some of these attacks in your system where
it looks like you don't even control the file format (is that mysql?)

2\. bootstrapping trust. how do I know I haven't been MitM'd, and how can I
avoid having to trust the server? My system has a public/private key for every
user, so when I share a password with you I'm encrypting it to your public
key. The worst possible case then is that I inject my public key claiming to
be you because then I get the passwords instead of you. Preventing this while
also allowing for public keys to be rotated after a compromise of a client
machine is currently stumping me. My current solution is to keep a record of
every public key I've seen before, when I see a new one prompt the user to
double check it out-of-band (like SSH does), and to just refuse to ever use a
new public key for a user that I've seen before. But I bet that users don't
actually check this, just like with SSH. And ideally I wouldn't rely on less
secure out-of-band communication channels.

3\. And speaking of verification, here's how I'm asking users if everything
looks right:

    
    
        === secrets.vm ===
        common name: secrets.vm
        fingerprint: b957e10c998faa9909cff3ba4ec35485d04708c3ecc7481fe14d7f07bc0229cd
        public key:  c15e697e4807793ef8a9461a7b2c6cf2266d1ec1480a594e83b54e7b75e07702
        public sign: f1db594eb55fe97657c57f2aa01afd1210a46d42d80d5552ac4d548162d4968e
        mnemonic:    AM ROBE KIT OMEN BATE ICY TROY RON WHAT HIP OMIT SUP LID CLAY AVER LEAR CAVE REEL CAN PAM FAN LUND RIFT ACME
        does that look right? [y/n]
    

AFAICT these word-based (it's rfc1751) or sentence based (as recommended by
[https://www.usenix.org/conference/usenixsecurity16/technical...](https://www.usenix.org/conference/usenixsecurity16/technical-
sessions/presentation/dechand)) are the best we have but do users actually
verify these? How do you help your users prove that your server is really your
server before they store secrets in it, in a way that they'll actually verify?

4\. Auditing. How can I, as an end user or as an admin of the server, prove
that the server hasn't been tampered with to inject rogue keys? Right now I
have a sketch for a merkle tree type log system where the server (1) logs
every action (2) links every "fact" (a key, a secret, a user) to an entry in
the log and (3) signs every log entry along with the log entry before it. Then
a user can reconstruct the current state of the database to make sure that it
matches. The upside is that it's pretty hard to forge, but the downside is
that it's prohibitively expensive to verify: you really have to check the
whole thing so you don't want that happening every time you retrieve a secret.
And there are some tricky bits like making sure that the log doesn't have
orphan entries that are easy to get wrong. Do you have a good solution to the
auditing problem?

5\. Keeping the crypto itself simple and auditable. I use libnacl for the
actual crypto and openssl for TLS. I've found that simply writing down every
way the crypto is used
([https://github.com/ketralnis/secrets/blob/master/DESIGN.md](https://github.com/ketralnis/secrets/blob/master/DESIGN.md))
that I've found a lot of cases where it was too complicated and likely to be
messed up. Finding that out made a big difference to me in how I write it: now
I describe it first and then write the code and that has made a huge
difference in keeping it simple. I don't see really any documentation on your
crypto, how do you know you're doing it right?

~~~
e12e
For 2,3 the better approach is probably certificates of some form. Ssh
supports certificates as well as plain keys (a key with optional meta-data
about validity, principals (users,servers etc).

And/or you could use some form of Web of trust model (one could say that a CA
system is just a very small, highly trusted wot - typically one key with
ultimate trust, that signs all valid certs - as opposed to wot that typically
scores a key based on signatures by other (semi-)trusted/known keys).

Unfortunately Ca/wot/certs doesn't _solve_ the problem - but it reduces
"verify all the keys" and "rotate all the keys" to verify/rotate _the_ key
(eg: the key that signs your user cert - if you have a cert, you have a xhain
of trust). It does however bring with it "maintain a CA" \- which really is
_less_ work than "synchronise all the various public keys" but frequently ends
up being hard to decentralise.

The latter is probably solved by realising better is _better_ and having a few
people/principals with signing powers (many priest, not just one bishop) and
an audit trail, roll-call/revoke - can be a _lot_ safer than ad-hoc trust-on-
first-use.

~~~
voltagex_
>Ssh supports certificates as well as plain keys (a key with optional meta-
data about validity, principals (users,servers etc).

Wouldn't validity and principals be best left to something like LDAP?

I still haven't found anything that fits in the gap between "I only have one
machine" and "I'm comfortable setting up Active Directory et-al". I like
reading about all these systems but I've only got 5 or so machines under my
direct control (although something that integrates with AWS would be nice for
when I'm doing development work there)

~~~
e12e
> Wouldn't validity and principals be best left to something like LDAP?

Yes and no. Even with easier access to caching etc, ldap can still be rather
fragile (no (readable) ldap; no login)[1]

In general _certificates_ need to _be_ (proof of) _principals_ (the entity
that can prove ownership of the secret key X' corresponding to public key X"
_is_ X - where X is a uid (eg: e12e) Or a machine or service
(login.example.com).

But if your use case is simple, and some meta-data can be readily attached to
the certificate, it's easy to add limits on where key X is valid from (source
ip/host), have access to (services) and when (time of day) -- and adding an
expiry. If policy is max lifetime of a week except for CA keys, then that
greatly simplifies revocation lists.

Generally "trust only this _one_ CA" is simple, and allows moving capability
(largely) to certificates. Centralised, on-line catalogs like LDAP make some
things simpler.

And there might be a balance: perhaps some basic group info is in the cert -
and each service can base policy on that (email login ok 24/7 - certain other
services only 8-16 -- although I can't think of a compelling need for the
latter right now).

[1] Of course one _should_ check for revocations, but with an automated system
to mint certificates, one can trade off with hour/day/week lifetimes. There
was a recentish show hn: sharkey:

[https://news.ycombinator.com/item?id=12097992](https://news.ycombinator.com/item?id=12097992)

------
gernest
I looked through the project and it is cryptic indeed.

I will try to digest a little bit for people who aren't familiar with Go and
by any chance read the project's README

\- The examples you see there with commands like `./put ...` `./get ...` are
actual Go command line apps found in the `cmd` directory.

What I mean is there are two command line applications which you actually
might need to build separately one named `put` the other `get` . What they do,
oh! well , never mind it should be crypting stuffs.

After being tasked to do devops for like 6 months. I understand the pain of
having more secrets than those of the secret agencies we see on the movies.

Something that turn out to be true most of the times is, secrets should always
be secrets. Managing secrets is supposed to be a secret.

I find the Configuration on the README to be full of secrets I mean passwords
, API keys e.t.c. And wondering if cryptic is aware of that and how it is
going to address this.

With my little understanding about security. I have a feeling that In some
cases encryption is mistaken with secure.

~~~
daenney
> After being tasked to do devops for like 6 months. I understand the pain of
> having more secrets than those of the secret agencies we see on the movies.

I would highly recommend you read up on this thing called DevOps and what it
is about. Start
here:[https://en.wikipedia.org/wiki/DevOps](https://en.wikipedia.org/wiki/DevOps).
You don't just "do devops".

