0

I'm getting into Kubernetes security and I'm looking at various ways to encrypt and use Secrets values in pods but I think I'm not grasping some key concepts. As I understood it, from the cluster security standpoint encrypting secrets should avoid that in case of cluster attack the attacker wouldn't be able to get api keys, access tokens, usernames and passwords, just by simply base64 decode the secrets values.

I'm comparing the use of secrets managers like Vault and Sealed Secrets against enabling Encryption at rest.

I see that with implementing either Vault + Vault Secrets Operator,or Vault + External Secrets, or Sealed Secrets, a normal Secret is generated from encrypted secrets and laying around in the cluster.

From Vault Secrets Operator GitHub

The Operator writes the source Vault secret data directly to the destination Kubernetes Secret, ensuring that any changes made to the source are replicated to the destination over its lifetime.In this way, an application only needs to have access to the destination secret in order to make use of the secret data contained within.

From Seal Secret GitHub I see that their Sealed Secret custom resource will get converted to a normal Kubernetes Secret..

This normal kubernetes secret will appear in the cluster after a few seconds you can use it as you would use any secret that you would have created directly (e.g. reference it from a Pod).

Encryption at rest on the other hand, will actually encrypt the secrets upon creation, dough you need to also configure RBAC rules, or use envelope encryption with a third-party KMS provider like Azure Key Vaults for example.

The three methods are almost equally complicated to implement as for example Vault needs a lot of manual configuration for unsealing and create encrypted secrets for example, but only encryption at rest will actually secure sensitive data against cluster attacks as Secrets are actually encrypted and decrypted when used from pods.

Given that above considerations, what are Vault and Sealed Secret good for, and what's even the point of going through all that trouble for setting them up if then Secrets end up laying around unencrypted?

Update - I love this security thing, I really do -

As suggested by David, passing sensitive data to the containerised Node.js app environment through Pod's container environment variables just makes the easy to get, so they're better off in a secure store like Azure Key Vault and retrieved directly in app via the SDK. Fair enough..just update the app to us that. But just there it all starts again.

You now have to secure the KEYVAULT_URI, AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET.

This is the exact situation I thought of when I first started programming and started using .env file not to hard code api keys and other sensitive data and avoid pushing it to the repo. But then you have to pass those values to the containerised app. No worries, there you have a Secret to inject them.. but no..that way with a simple exec command on the pod an attacker could get them all, So you gotta stored them in a secure remote encryted and re-encrypted NASA level service on Mars, but hey.. You need access to them so there you have a bounce of keys, secrets and ids to pass to an SDK in your app to do that.. This way it takes just an extra step to get all securely stored sensitive data. Instead of cracking your app and get them, they need to crack your app and get the keys to go and get them.. oh I almost forgot. Thanks for your Azure credentials too..very kind of yours.

This whole security thing is just a sort of a treasure hunt where a clue takes you to the next one and away to the treasure.. Is there an end to all this security, encryption, key rotation thing? I mean one way or another sensitive data seem to get exposed somewhere.. I might just leave the keys in the car..

Seriously.. how you manage all this? Sorry for the rant.. hope I made you at least smile

Vincenzo
  • 5,304
  • 5
  • 38
  • 96

1 Answers1

1

Getting the Secret into the cluster at all can be a challenge. You can use Kubernetes RBAC to limit the Secret's visibility, which may help some of the security concerns.

I'd suggest there are three basic levels here:

  1. The secret values don't exist in Kubernetes at all, but the application directly integrates with Vault or a similar service. (Hardest to set up and run, especially in non-production.)

  2. Kubernetes Secrets exist but they're populated by an operator or integration.

  3. Kubernetes Secrets are created at deploy time via kubectl apply or Helm.

If the Secret exists at all, as you note, it's fairly straightforward to get its value. kubectl get secret will have it in all but plain text, kubectl exec can find it in the running Pod, if you can kubectl run a new Pod or create any of the workload-type resources then you can mount the Secret into a new Pod and print out its value. That's an argument for having the application tie directly into the secret store, but that's a more complex setup.

Let's say you're not hard-wired into Vault and need to provide a database password as an environment variable. Where does it actually live; when you deploy the application, how does it get set? One option is to put the password in your CI system's credentials store, but this is a very "leaky" option – the CI script and every step along the chain can see the secret, and you need an administrator of the CI system to create or modify the value.

This is where the various secret-manager tools come in. Sealed Secrets lets you commit an encrypted secret file to source control, so you don't need to coördinate with the CI system to create or update a credential. External Secrets creates a Secret from a system like Vault or AWS Secrets Manager. Vault has a fairly rich access-control system, so this makes it possible for a user to create a secret, and list existing secrets, but not directly retrieve the secret value (at least, not outside of Kubernetes).

So, if you install the secret through the CI system:

credential (only CI admins can update)
    v
CI system --> helm install --> Secret object --> container --> application
    ^              ^                 ^               ^              ^
    credential is visible everywhere

If you let an operator like Sealed Secrets or External Secrets create the Secret object:

                secret store --> operator
                                     v
CI system --> helm install --> Secret object --> container --> application
                                     ^               ^              ^
                                  Kubernetes operations can get credential

And if you change the application code to directly wire into the secret store (Vault, AWS Secrets Manager, ...):

                                                              secret store
                                                                    ^
CI system --> helm install --> Secret object --> container --> application
                                                                    ^
                           credential only visible inside application code
                                  requires wiring specific to secret store
David Maze
  • 130,717
  • 29
  • 175
  • 215
  • "Hardest to set up and run, especially in non-production." I heavily disagree with this. It is straightforward from the application side by utilizing the API SDK bindings in e.g. Go, C++17, Rust, NodeJS, Ruby, Python, etc. On the server side it requires a specific role and policy within the authentication engine that would already be required for any of these solutions. Indeed that solution (1) would be best practices wrt security. – Matthew Schuchard Aug 17 '23 at 13:50
  • @David Maze I see your point in CI, hence using Sealed Secrets would let you avoid publishing the unencrypted secrets, but let create them in the cluster directly from the published encrypted ones. This approach dough leaves the unencrypted Secrets laying around in the cluster so even with this a simple `kubectl get secret` sensitive data (which is passed to Pod container envs) is exposed. – Vincenzo Aug 17 '23 at 16:16
  • Even if we go an extra step and, apart from using Sealed Secret or External Secrets operators, we also enable encryption at rest and store the DEK in Azure Key Vaults and retrieve it for secret decryption could ENV variable can be obtained via the Pod as you pointed? Could you elaborate a bit more on this or point me to some docs or articles on this? If so it really looks that implementing a secret store directly in the app would be the only way to secure sensitive data..what good are then Kubernetes secrets for? Many many thanks. – Vincenzo Aug 17 '23 at 16:16
  • Indeed, it looks pretty easy with an SDK, like for Node.js in my case. Still, even with this approach, there are Azure credential details, Service principal and Key Vault secrets to pass to the App. Is there and end to this? Lol.. – Vincenzo Aug 17 '23 at 17:14
  • If I'm injecting values via environment variables, in _any_ environment (even in a debugger in an IDE in my laptop) I can just set the environment variable and be done with it; and if I want to switch between Sealed Secrets and External Secrets backed by Vault, I don't need to change my code at all. I do fully agree that, from a security point of view, there are...compromises in using Secrets at all, that might be unacceptable. – David Maze Aug 17 '23 at 23:04
  • Also consider, in any of these environments, that if I can create a Pod with an arbitrary ServiceAccount, then I can probably impersonate the "real" Pod well enough to get the credential, no matter where it's stored. – David Maze Aug 17 '23 at 23:06
  • @DavidMaze Let me recap, I'm very confused about it all. 1. Env variables are used not to hard code sensitive data into applications and are the easy setup. 2. Not to expose them publicly we don't commit the .env file, but we have to pass them to the pod some how. 3. Passing them to Pod via Secrets either directly, via Sealed Secret or External Secret, is not secure, Secrets are completely useless from a security point of view as they can be decoded. 4. Passing them to Pod's container is also not secure as a simple kubectl exec -it pod name -- env will reveal all the env variables. – Vincenzo Aug 18 '23 at 09:08
  • 5. Using a secret store in app to get them directly leave us with the problem of setting env variables for accessing the secret store, which is the reason we are using the secret store in the first place. Now to my unexperienced eyes, this looks completely useless as we're going in circles. – Vincenzo Aug 18 '23 at 09:08
  • Of course there are many other levels of security on which we can intervene to secure the cluster as for example `vulnerabilities in the containerised app itself and or running as root user, non secure access to the cluster itself, Pods running as root user and/or allowed to escalate privileges, unlimited and unencrypted internal cluster communications, unencrypted etcd data and unlimited access to it, absence of security policies` , but as for the sensitive data management part I kinda feel that the only thing that we can really do is not hard code them into the app source code. – Vincenzo Aug 18 '23 at 09:09
  • I do compare the cluster security to safely lock your bicycle. If you use one lock is not enough even if it's the top level, they can cut it within 5 minutes or just steal parts from your bike. So you can use two or three of them locking both wheels and your seat , lock it in a very public place, well in view of a security cam, only to find out that they cut the locking post, got your bike and the cam footage is not available without a police warrant which take longer that the 24h they keep the footage archived. Any level of security you add only makes it more difficult to break. – Vincenzo Aug 18 '23 at 09:09
  • So to me it feels that avoid to break into the cluster would be the top concern and priority, "keeping my bike at home with secure doors and windows" so to speak, and use every other measure possible. Now, some of these measure feel to me as a trade off between security, usability and implementation difficulty ( cycling with 5 kg of locks and using them is quite a different cycling experience) especially the sensitive data/secret part. For which possibly using Sealed Secret is the optimal compromise between not publish them/ make the available in repos and actually use them. – Vincenzo Aug 18 '23 at 10:33