getsops / sops

Simple and flexible tool for managing secrets
https://getsops.io/
Mozilla Public License 2.0
16.29k stars 857 forks source link

Support a one-way encryption scheme #428

Open skang0601 opened 5 years ago

skang0601 commented 5 years ago

I would like a way to support a one-way encryption scheme more seamless than currently possible. Here is the scenario I'm proposing:

I have a KMS service

I have a developer and a target(CICD, K8 cluster, server, etc.).

I'd like to give the developer only access to encrypt a DEK rather than being able to decrypt the DEK and therefore gain access to the encrypted payload and I'd like to give the target access to decrypt.

When a developer needs to add/modify a new secret to the existing file, SOPS would generate a new DEK and encrypt that section of the payload and the DEK and checks it in and does not modify the unmodified secrets. When the target receives this mixed payload, it should be able rencrypt all of the payload with this new DEK.

This is somewhat negates some of the nice usability features of SOPS but can be desirable in certain scenarios. Let me know if this makes sense in context of this project.

jvehent commented 5 years ago

I believe you could already do that by granting kms.Encrypt to developers and kms.Decrypt to instances, though I admit having never tried, because I fail to see the point of preventing developers to decrypt when the secret originates from them anyway.

thepont commented 5 years ago

I was hoping this would be able to do this as well, I already tried what you said, although the application seems unable to encrypt values unless it decrypts the entire file.

The following is the error from sops when you attempt to set a var without the decrypt permission.

~/Downloads/sops-3.2.0.linux --set '["app2"] "test"' test.json
Failed to get the data key required to decrypt the SOPS file.

Group 0: FAILED
  arn:aws:kms:ap-southeast-2:<AccountID>:key/5bc8698a-8b29-4a7f-920f-a09ebd93a738: FAILED
    - | Error decrypting key: AccessDeniedException: The ciphertext
      | refers to a customer master key that does not exist, does
      | not exist in this region, or you are not allowed to access.
      |     status code: 400, request id:
      | 88d13251-8b52-497f-8ddb-b33abb0c83f9

Recovery failed because no master key was able to decrypt the file. In
order for SOPS to recover the file, at least one key has to be successful,

As for your point as to why hide secrets to those who add secrets,

I would personally like to add secrets to the file, but also would not be interested as to what is the contents of the file are, I don't need the credentials of the server ( only the server does ).

Since my team and I don't need access to this information it makes no sense to expose a secret to everyone.

I realise I am capable of writing down the secret to remember it and therefore somewhat defeating the purpose, but having said that the rest of the team is not.

Since only the server needs to know it's secrets, the closer we can get to this ideal the better.

skang0601 commented 5 years ago

@thepont Yeah I believe SOPS needs to decrypt the whole file to generate the MAC.

thepont commented 5 years ago

@skang0601 I think you're right, The only way I can see this might be possible using SOPS currently therefor would be to encrypt an entire file each time you wanted a new encrypted set of values and never modify pre-existing ones.

mykter commented 4 years ago

If my reading of the MAC implementation is right, the current mechanism is encrypt-and-MAC, which isn't as robust as an encrypt-then-MAC approach.

So solving this would have two security benefits (at the cost of introducing a new file format version).

mykter commented 4 years ago

I fail to see the point of preventing developers to decrypt when the secret originates from them anyway.

A situation this is helpful in is if a developer's credentials or machine have been compromised. An attacker with access to those credentials or machine can not get access to the current secret.

herzogf commented 3 years ago

I second that, my use case is letting developers change/add secret configs for their applications which then get deployed via Argo CD to a kubernetes cluster. The dev should only be able to change/add things but not be able to decrypt the whole file (we're still heavily separated in dev and ops atm..), i.e. the kubernetes cluster has public/private keys, the dev only the public part.

Right now I'd either have to have 1 file per config value (-> https://github.com/mozilla/sops/issues/428#issuecomment-497562011) or have some "encryption service" running in my kubernetes cluster which gets the config values file and the plantext key-value pair to set/add. Or completely switch away from Mozilla Sops and use something like https://github.com/FiloSottile/age and do the yaml-just-value encryption by myself (i.e. encrypt each value individually so that it can be changed separately).

Would it be possible to have multiple data keys in one sops-encrypted file to solve this? I guess not bc the MAC mechanism wouldn't work with that.

bd-g commented 2 years ago

I fail to see the point of preventing developers to decrypt when the secret originates from them anyway.

A situation this is helpful in is if a developer's credentials or machine have been compromised. An attacker with access to those credentials or machine can not get access to the current secret.

We also would like this for security - having to consider other options besides SOPS because of this main flaw.

dblackdblack commented 2 years ago

This is pretty much a total blocker for us. It's basically unworkable for us that in order for a developer of a one service to be able to set a single secret value for just their service, they must have IAM permission to decrypt all other secrets (of potentially other unrelated services that live within the same sops file).

We could work around this by having separate sops files per service and carefully tailoring our IAM permissions so that we have a 1:1 mapping of developers to services (and keep that updated), but I want to be able to have all developers able to encrypt secrets but nothing except for a Lambda function that has permission to decrypt for final storage within Vault. No human would have decrypt permission in this model.

jvehent-sops-ci commented 2 years ago

Sops' unit of work is the file. Once granted access to a file, both encryption and decryption is possible, and changing this would fundamentally change the way Sops operate and was designed for.

For this particular use case, I'd suggest looking at alternative solutions.

On Tue, May 24, 2022, at 8:23 PM, dblackdblack wrote:

This is basically a blocker for us. It's basically unworkable for us that in order to be able for a developer of a service to be able to set a secret for just their service, they must have permission to view all other secrets. Sure, we could work around this by having separate sops files per service and carefully tailoring our IAM permissions so that we have a 1:1 mapping of developers to services (and keep that updated), but I want to be able to have all developers able to encrypt secrets but nothing except for a Lambda function that has permission to decrypt (and then shove the plaintext values into vault). No human should have decrypt capabilities.

— Reply to this email directly, view it on GitHub https://github.com/mozilla/sops/issues/428#issuecomment-1136557087, or unsubscribe https://github.com/notifications/unsubscribe-auth/AEJTC2NBPHPEWC5CYK3DDXLVLVXIDANCNFSM4GYMRRTA. You are receiving this because you are subscribed to this thread.Message ID: @.***>

thepwagner commented 1 year ago

Apologies for potential necromancy, like everyone else this always comes up as a blocker for SOPS adoption in my organization.

The solution I came up with is layering SOPS files:

It allows developers to add/overwrite values by adding additional layers (kms.Encrypt), but removes the requirement that they modify the plaintext directly (no kms.Decrypt). The neat property of this system is that every layer is a valid SOPS file. Each file has exactly one DEK and MAC calculation is unchanged. No schema changes, entirely additive and opt-in.

To decrypt, the SOPS library walks backwards through layer files. This scales KMS operations with the number of layers, which I prefer to proposed alternatives like storing each secret in a unique file (which scales on the number of secrets). To manage sprawl, operators/bots with kms.Decrypt permissions can flatten the layers at any point. SOPS might allow users to limit the number of layers so they can manage debt.

Is this interesting to upstream? It could be a library but I implemented a PoC as a fork because the walk() functions are handy - https://github.com/getsops/sops/compare/main...thepwagner:sops:sops-layers

thepont commented 2 months ago

Relates to: https://github.com/getsops/sops/issues/684

felixfontein commented 2 months ago

It's not really related to #684. This issue is about being able to encypt without being to decrypt, while that other isse is about being able to encrypt without having access to the AWS KMS secrets, similar to other keystores like age and pgp.

Hmm after reading some more I'm confused, maybe this isn't correct...