Hacker News new | past | comments | ask | show | jobs | submit login
Git-secret – store private data in a Git repo (coderwall.com)
211 points by bitsweet on May 9, 2016 | hide | past | favorite | 70 comments

This project scares me because it helps foster a bad practice -- keeping secrets in a repo. You really shouldn't be keeping secrets in the repo.

You should be using a secrets service that is designed for such a purpose, like Hashicorp's Vault[0], so that you never have to keep a secret in the code.

[0] https://github.com/hashicorp/vault

Storing secrets in a repository is not bad.

Storing secrets in a repository with non-secrets is bad, because access is pre-repo, and it would hurt your ability to limit secret access to the smallest possible audience.

You are technically correct, the best kind of correct.

However, storing secrets in a git repo is still not as good as a purpose built store, because the access control on git is not fine grained enough.

Yes, that could be appropriate.

Access is per-repo, so if you have enough secrets and disparate interested parties, the number of required repos could make a dedicated alternative far more manageable.

Agree, also check out credstash[0], a very good and secure solution if you are running on AWS. Credstash is an small utility that encrypt with KMS and store the ciphertext of the datakey and secret on Dynamodb.

I configure my application roles to be able to decrypt with the master key and I restrict what ciphertext they can read from Dynamodb.

[0] https://github.com/fugue/credstash

Perhaps it's an alternative practice/behavior rather than a "bad" practice?

It's a bad practice, because git makes keys practically irrevocable. It's not enough to rotate encryption keys, because the old ciphertexts are in the git history; you have to rotate the underlying secrets as well (people don't do this and shouldn't have to).

Don't store encrypted secrets in git if you can avoid it.

No, this forces you to rotate your secrets because you don't get to pretend that losing access to the repo means losing access to the secrets. While dynamic secrets are best, static secrets (like API keys) should be stored in version control.

When someone has unintended access to secrets (for example, the developer you just fired), you need to rotate both the key and secrets to have any semblance of security. Ideally you use deterministic encryption to create the secrets too.

We agree that if you store secrets in a repo, any time you change the encryption key, you have to go and purge the underlying secrets. We disagree that this is intuitive or that shops do this reliably.

We should be able to agree that not storing secrets in your repo dodges all these problems nicely.

Well, I disagree. It doesn't matter where you store them, repo or not: even if they're not in a "repo", they're stored somewhere, and when you revoke access from someone to that somewhere, you still have the same problem: the party that you're revoking access from had access at one point. For all you know, they copied the secret while they had access. You can't "revoke" information from someone's mind: you MUST rotate the secret to accomplish that.

If anything, I like the git repo idea b/c — presuming that the repository stores a history of who had access to what, when — it removes the question of whether you need to rotate a secret. You can look at the history, and if the secret didn't get rotated when access was removed or at some time afterwards, you know you're not secure.

Compare that to say, a random file somewhere, say on a deployment node in deployment code, or alongside that code so as to keep it out of a repo, that just keeps the latest copy of the secrets, where one doesn't know when access was revoked. Do the keys need rotation?

If you use a purpose built storage though then you can deny access to the actual keys to just about everyone, so if a developer leaves then they won't have the keys, and if they do you'll know because it will have a built in audit trail. And in many cases you never have to release the key from the purpose built store because it takes in crypto text and gives out plain text without ever revealing the key to the user.

They'll have their own key, which will be revoked from the store, and they might have a single key that machines use to access the store. You should be rotating that machine key all the time anyway, so rotating once more when a dev leaves isn't a big deal. It's also much easier than rotating all of your actual keys, which in many cases is generated by a third party that may make such a thing very hard.

What you are describing is how to remove _access_ to the secret. The issue here is, that the former employee still has _knowledge_ of the secret. Hence you have to rotate the secret.

Plenty of companies choose to accept the risk that an employee might have memorized a secret, but not accept the risk that the employee's secret-encrypting-key might leak at any point for the lifetime of the repository.

Obviously, nothing you do w/r/t secret storage is going to resolve the problem of what's in your employees' heads.

If a developer leaves they'll still have the plaintext of the keys from when they were working for you. You have to change your secrets at that point.

In this case state of access control is stored along with code/secrets. The problem is that ACLs, secrets themselves and code change independently of each other. This only works if you assume no downgrading and homogeneous versioning across all instances.

You're forgetting that if I have been storing all of the encrypted traffic all along and then get access to the keys I can unlock all of the history too. Once a secret is out of use it should be purged completely. This is why secrets should be stored on ephemeral storage if at all possible. This is however pretty advance for many people.

This is solved with perfect forward secrecy: https://en.m.wikipedia.org/wiki/Forward_secrecy

Great! It's "solved". No need to worry anymore!


The page says "When someone is out - just delete his public key, reencrypt the files, and he won’t be able to decrypt secrets anymore." but doesn't talk about rotating the secrets.

This practice seems unnecessary to me.

Second that, if there are many people having access to the repository and you maintain repo's history, rotating encryption keys and secrets won't save you, unless you also delete the whole history and do some major updates to the files. Someone can answer to that that he can put the ciphertests in a separate repository and limit repo's access to only deployment server/user, but that completely invalidates the goal.

The problem is you need some repository to store this information and it's incredibly helpful to store the configuration along with the code.

If someone has access to a shared secret and then shouldn't you should assume the secret is now compromised and rotate it. Rotating the keys doesn't solve this problem.

No. If that were the case, there would be no purpose to rotating keys. The problem is that despite rotating keys, your old crypto keys have permanent access to secrets, because the old ciphertexts are by default retained in the git history.

It's a bad idea to store secrets in any form in your source code repository.

I think what grandparent and others are saying is that you also revoke the secrets contained in the ciphertext, e.g. if it's an AWS key you would revoke that AWS key on AWS's side as well as encrypting new secrets with a different encryption key.

Obviously this is a huge hassle and isn't easily done with all kinds of secrets (which is what I think you're getting at?). But it's also often necessary.

> The problem is you need some repository to store this information

This doesn't have to be a Git repository, nor does it have to be the same repository as the code which uses the secrets.

> it's incredibly helpful to store the configuration along with the code

It's helpful, but ultimately means that the ciphertext is potentially available to the world and existing keys may decipher it in perpetuity. Thus this is not a recommended tradeoff to make.

It is helpful to store configuration with code, but you don't have to include secret values in your code. It's much better to use a purpose built service like credstash[0] to store secret values while you keep the name of the secret and (possibly) version in a repo with your code.

[0] https://github.com/fugue/credstash

>you have to rotate the underlying secrets as well (people don't do this and shouldn't have to).

How is that different from the case of an employee having written down the secrets and leaving the company later on? In both cases the employee has had access to the secrets and in both cases the only way to be secure is to change them.

why shouldn't people have to rotate the underlying secrets?

a rogue employee who created a secret, or any engineer who had to access that secret to get their job done, is always going to be able to use that secret value, regardless of where the encrypted blob is stored.

seems like we should be making it easier to rotate secret values often and automatically.

Doesn't the OP say that secrets aren't allowed to be stored unless they're in the gitignore file? Does this mean they're somehow not storing the secret's history? Say by rewriting the history of those particular files in the .gitsecrets file every time they're committed so they've only got the lastedt version?

Hmmm, I'm thinking you'd have the same problem storing secrets in a blockchain.

In addition to what others are saying, for many types of secrets (API credentials, salts, keys, etc.) it's good practice to make them different in production vs development. This has the advantage of keeping your production secrets in the domain of ops, and your developers never even need to have them.

This is built on the assumption that you only ever have one set of secrets, or that you don't mind distributing your prod secrets to your engineers, both of which I would consider to be bad practice.

Another option worth considering may be Knox[0] by Pinterest.

> Knox is a service for storing and rotation of secrets, keys, and passwords used by other services.

[0] https://github.com/pinterest/knox

On a sidenote: anyone know how Vault Project built this: it's very cool


Nice work!

I've been using https://github.com/AGWA/git-crypt until now, always good to have more alternatives.

Can you tell us what is different about your approach with this project?

I've started using git-crypt for deploying configuration. It keeps things simple and ensures that keys are not in plain text on bit-bucket which is basically good enough right now.

I've been using ansible-vault to solve this problem in our infrastructure repository. A symmetric vault key is encrypted using gpg, and Ansible's vault_password_file is set to to an executable shell script containing `gpg --batch --use-agent --descrypt vault_key.gpg`.

Very specific to Ansible, but works fine. It's a shame only files containing variables (we're using group_vars) can be encrypted, and not arbitrary files or templates.

To be a bit pedantic, all .yml files can be encrypted with ansible-vault, so also playbooks and roles.

There are two things currently that bother me about ansible-vault. The first is that the 'edit' command write a completely new file even if I didn't change anything. And the second is that the diffs in git become useless. I'd love to have a special diff driver for ansible-vault encrypted files that decrypts before diffing when the secret is available.

If you use show instead of edit it doesn't re-encrypt the file.

Agreed on the useless diffs however, it makes reviewing pull requests or changes much harder.

I'm curious, why do you feel the need to encrypt every single file instead of just secrets (to keep reviewing possible)? :)

I usually only encrypt var files that contain things like db passwords or something. In our case it made it harder to spot typos in the username for example.

I wouldn't encrypt a whole playbook for example.

We don't encrypt all of the credentials, just the actual passwords.

Uhm, for me edit brings up vi, I then :q and the file's modification date didn't change?

More things about Ansible vault that are a shame:

- no file encryption, only YML

- no separate values, only entire file

- OMG it's s...l...o...w...

- password based instead of certs

- only one password

- password cannot even stored in an env var

More: http://jpmens.net/2014/02/22/my-thoughts-on-ansible-s-vault/

A good trick I found was to have a file with your values assigned as vault_something and then in the clear version have the variable assigned as: something: "{{ vault_something }}"

But yeah, the "only one password" is the biggest pain for me...

Actually, you can make the vault password file an executable shell script containing


re: your last bullet point, I put my password as the only thing in a text file, then point the environment variable to that. Same effect, although it is one (small) extra step.

Another tool worth looking into is git-gpg, which allows you to store encrypted git repositories on third-party / potentially insecure servers, but unlike this tool it stores all changes to source files as compressible textual deltas (a key reason for using git in the first place). The repository is encrypted remotely but the local version has no encrypted blobs inside.


Other benefits include architectural simplicity and low footprint: it consists of a single Python script that you add to your executable path.

Similar project, that I personally use quite often: https://github.com/StackExchange/blackbox

I'm glad that blackbox is gaining in popularity. Future directions for the project are listed here: https://github.com/StackExchange/blackbox/blob/master/Versio...

This should really work with ssh public/private keys¹. Public keys are probably already on the box the git server runs on, and users already have them generated to access git - no need to generate separate gpg keys.

If you have a github account the script could also get the pubkey directly from the github api...


SSH keys aren't really used for encryption. Typical ssh uses some kind of DH construct, with the ssh keypairs just used for authentication.

However, stackexchange is the right place to go if you want to use asymmetric secret storage in git.


I used to put .gpg files in my repos that stored sensitive information like database passwords and such.

I don't do that anymore. The main problem as I saw it was that you basically liberate your security to an environment you can't monitor or send rejections to (if someone downloads your gpg file). Compare this to an ssh server which affords both those abilities.

> When someone is out - just delete his public key, reencrypt the files, and he won’t be able to decrypt secrets anymore.

But they still can encrypt old versions stored in git, no? Do you change all secrets when somebody leaves the team/company? I guess that'd be best practice, but I have no idea how often that's done out there.

Yes, they can still decrypt old versions.

Storing secret keys, API keys, etc. in your git repo is a terrible idea and an antipattern any way you slice it. Keep your secrets out of version control.

The quoted advice is extremely bad. If someone who has access to a secret of any importance leaves your team, the only acceptable response is to rotate the secret.

Yes, he can still decrypt the secrets he had access to before his key was revoked, just as he could have written down those secrets before he was fired. There is no difference really, and the way to solve that is the same for both cases - you change your secrets after such an event.

A word of warning to those considering using this. While I completely understand why people might want to encrypt/decrypt files within their public Git repositories, doing so doesn't come for free.

As Junio C Hamano explains more eloquently and in greater depth here[1], one thing to bear in mind with this (and similar) tools is that they store the managed files as binary blobs, regardless of their original format, meaning that a change to the source file of even a single bit will result in an entirely different uncompressed blob being stored, rather than a compressible textual delta.

[1] http://article.gmane.org/gmane.comp.version-control.git/1132...

While technically true, the type of data this extension is meant for (small configuration snippets containing sensitive credentials) are both small and rarely-changing. A couple extra bytes in the index won't be a very big deal.

Why would someone change a single bit in their key anyway? If keys are replaced, the new key should be generated independent from the old ones.

I can imagine a great number of use cases involve encrypting an access key or password making this not a big issue, right?

At Zemanta, we developed py-secretcrypt[0] and go-secretcrypt[1] for keeping secrets encrypted with Amazon KMS (Key Management Service) in our repos. They are then decrypted on the fly by the application.

Access control is managed through AWS KMS key policies, with EC2 instances running the applications having permissions to decrypt the secrets.

Blog post about this will follow soon.

[0] https://github.com/Zemanta/py-secretcrypt

[1] https://github.com/Zemanta/go-secretcrypt

See also: https://github.com/StackExchange/blackbox "blackbox by StackExchange"

Hmm... adding access controls to Git? I'm not sure how I feel about this. I like how Git is low level and stays away from all of that stuff leaving it up to wrappers like GitLab, GitHub, Gerrit, etc.

When you remove someone from the list of users does it have to go and re-write history? Isn't that a big no-no in Git?

I have nothing to do with this project, but I think the answer to your question is no - you don't have to re-write history. If the removed party had access to previous revisions signed with his key, they're already "compromised" as far as security is concerned. Whether or not you rewrite history, he already has it.

The re-encryption they're referring to is presumably just to protect future revisions (since you would ideally rotate all keys they had access to, git-secret or not, and publish new ones right away).

If you need to do this, I would recommend looking at Transcrypt: https://github.com/elasticdog/transcrypt

If all you have is a hammer, everything looks like a nail.

I am using keybase.io to store soft secrets like the coveralls.io token. Let me share my simple use case: http://g14n.info/2014/07/my-keybase-experience/

Some cross platform tool that we've developed for our company which has some nice features


I've been using https://github.com/ahoward/sekrets in private repos for years. Great tool.

I definitely agree this should be used with heavy caution and only in private repos.

This should not even be used in private repos unless the only person who will ever access the repo is you.

Recently, I've wrote simple tool for storing secrets like passwords in public Git repos using AES cypher: https://github.com/seletskiy/carcosa/

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact