-
Notifications
You must be signed in to change notification settings - Fork 40.4k
Secret distribution in docker/k8s #2030
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
On a related note some things were discussed in #1553. |
As we partially discussed @jbeda |
Very cool! Thanks for writing this up. I love the idea of an encrypted volume -- lots of decisions there though. Might be worthwhile to raise this with the docker folks too. |
well thought out. Here are my ramblings: From a data security perspective I need to rotate my keys pretty frequently. It would be nice if the k8s implementation had consideration for re-encrypting secrets with new keys via an api call that let me post new keys. I don't want my private keys stored in k8s, but rather I'd like to embed them in my docker containers at deploy time (which is what I do now from my CI server) , or make them available via a storage container I deploy with the pod. If k8s controls both public and private keys for the secrets, people will have a hard time getting through audits. We built crypt specifically for use in Kubernetes so that we could support a model where each environment (QA/Production) had its own set of keys, and keys could be rotated easily -- by making a new deployment of our pods. Then I took it a step further by building crypt support into spf13/viper (PR pending) so that configs can come from env, config files, command line flags, or etcd/consul (both encrypted and plain text). Having that level of flexibility built into k8s would be great. For now, I would settle for any mechanism that allows me to rotate keys. Start small. |
@bketelsen key rotation could be done with Option 3b encrypted Data Volume Containers too. Additionally keys wouldn't be stored in k8s, but are stored in the build environment, which could be separate from the non secret build environment. So key rotation could easily be used. With the LDAP option (Option 2) key rotation would be made easier as it's a central place to change and no rebuild necessary, merely a redeploy (could be circumvented via watching for updates). How do you inject the key at deploy time? I sense that keys are never commited to the actual images as one would hope. A few unclear things with viper and especially crypt: For all above methods key distribution or better seed secret distribution be it a gpg key or else needs to be done either via k8s or via separate tooling. Either way the decryption key will be exposed to k8s. With crypt and Option 3b the encrypted data is also accessible from k8s (etcd/consul or container registry). With LDAP we would at least have a minimal separation there. But when we consider k8s compromised, then we need to worry about other attack vectors anyway. Sidenote: I'm going to write up a similar issue on dynamic config generation and the available possibilities etc.. |
Another way to go about it is to separate keys and credentials. For keys and file based secrets we could use the encrypted Data Volume Containers (de/encrypted via gpg) and for PWs/credentials we would use de/encrypted strings either from ENVs, etcd or consul. My opinion would probably be to use no additional tooling and add PWs and credentials to the encrypted Data Volume Container. |
Concerning the integration into k8s. I think some sort of key rotation and seed secret injection at runtime would be the first step, after we agreed on a method for secret distribution. |
Its hard to evaluate these alternatives without a threat model, as well as stating some assumptions about how kubernetes is used. Some questions:
etc... |
@erictune I agree that it is harder without a specific threat model, but with a few generic threat models and best practices, it is easier to move forward into specifics in my opinion.
So my proposal is to start with the most common issue.
These are a few examples to emphasize my view on the first step. I'm eager to hear other views and will update my "resulting solution" in another comment. |
My "solution" would be tied to #2068 (comment): This volume can then in turn be provided through a number of different services. The image providing the data could get started via a seed (gpg key etc.) with the help of a Crypt, stocker, ldap or some custom de/encryption of an encrypted Data Volume Container. My personal preference right now is to use something like: This is only a suggestion for a best practice guideline now, but could easily be integrated into k8s. With the help of providing a secrets volume of sorts similar to git based volumes #1945. This could then use key rotation, seed injection, ACL and store secrets in etcd or what is choosen. I think basing, secrets, configuration and data, on volumes will make this best practice much more modular and easier to substitute for a homegrown solution from k8s. Keep the thoughts coming. \o/ |
Okay, I think we agree that we have to trust:
Given that we have to trust those components, I'd tend to favor a solution that reuses one of those components, over one that introduces a new component that needs to be locked down. I'm not sure what the current best practices are for distributing secrets along with docker containers. I'm assuming it is something like 3a or 3b. So, we should definitely support that. |
@erictune Yeah I agree with at least basing the initial idea on top of 3a/3b and then use this base to let users choose their tool they wanna work with. Be it etcd/consul/manual files/ENVs. The thing is, that running a private docker registry is a mostly good way to prevent leaking of said images, but it can't always be. |
Coming in late to this - may have missed it in the thread:
|
(Our = Openshift) |
Looking forward to more ideas. I'm already in the process of setting up a "production" image for these ideas. Configuration and data is done, but secrets and key is still in the works. |
This is the structure I imagined for secrets and volume standardisation in general: (Disclaimer: Was also posted in #2068.) |
Sorry for coming late here, I've seen all the proposal in this discussion and find them all lacking, the sharing of data volume come close, but it looks to me as too static, meaning that you have to interact with a file system to affect the secrets, and it also means secrets are avialble all the time through this volume. I have been musing for a while that a local socket based protocol based on a standardized protocol (protobuffer or what you like) that is endpointed by a proxy service on the host could be a better model. In the simplest implementation you have no chicken-egg problem with credentials needed to access the secrets distribution service, the hosts vouches for the containers, yet you can add per container auth/encryption on top of it if so desired. The only thing that needs to be standardized here becomes the API, not a Secrets can then be fetched on the fly. At the same time this pushes part of the security out of the equation by delegating it to the specific implementation (local security is done via simple permissions on unix sockets and whether/how they are bind-mounted in the container). Ideally the proxy service (when a central secret sharing service is used) would Dynamic rerouting based on the specific secrets being requested can also be I think a unix socket+API based design offers significant advantages over a HTH, |
The thing with your proposal in my opinion is, that this proposes just another api standard/implementation. There are already quite a few of these apis one could use. LDAP, crypt, consul and a bunch of enterprise tools. The difference with this proposal or actually with the latest iteration (moby/moby#9277) is that you don't care about the actual implementation as long as app container maintainer and volume provider agree on a directory and filelayout, which can be quite dynamic. One could iterate throught the /con/secret directory for example, or grep for an AWS key etc. pp.. Furthermore with the final proposal to use Volumes as a Service in Kubernetes, there is a way to make most of the features you want available. A Volume as a Service could do a lot more than just be a static fs. It could and should be available per container, per pod or per service and therefore be quite tailored. Additionally short lived tokens or removing secrets after a successful start could be achieved. Not to mention that these volumes should live in memory only. So instead of using just another API, which needs to be spoken too, which requires tools inside the container etc., plain reading of files is already supported, especially considering that one could use /con/secret/ENV and just generate ENVs to be used. Moving from Host Volumes to git based volumes to a fully integrated secret distribution method in kubernetes does only require to change the volume type and not a full reconfiguration to a new set of APIs. |
While you could use the file system as an API, I do not see any good reason to do that. In theory, yes, you could have dynamic content appearing and disappearing from a filesystem, but file system interfaces are not built to do that, it would be a quite fragile construction with corner cases and odd/unexpected behaviors. You can describe conventions, but they would still be something on top and separate from a real filesystem interface, so you would have to retrain developers and programs to behave differently when accessing that specific portion of the filesystem. What is the advantage of doing that ? File systems also have very many layers, including caching in the page cache When it comes to using an API, you could certainly use LDAP, a good LDAP server If I had to choose between LDAP or a File System interface, LDAP would probably Note that using LDAP as storage is quite clearly a possibility, but using it as In general it looks to me that you are trying to propose use of existing tools The most concering aspect, is that by using these tools The filesystem interface is particularly prone to abuse if the application For the most advanced case (like the idea of ending up with a PKCS#11 |
Sorry for the long wait on an answer, but I got stuck with other things. I agree that using the filesystem as an API is not perfect for dynamic stuff, but that is not the main advantage. In my opinion with containers and in general with versioned infrastructure (even versioning data and config) you do not want dynamic content appearing or disappearing without some sort of checkpoint ("docker/git commit" kind of thing). These non dynamic use cases are the focus here. Fully dynamic configuration is only one edgecase I was thinking about. The main point I wanted to make was that for general supporting data/config, a common interface is essential. Mounting your (persistent) storage to /con/*{data,log,configuration} on each container is easier to work with. As different locations can be abstracted away by the application/container builder, which most likely knows the actual implementations better and therefore has the knowledge to abstract that away. Within a one process per container system one data, configuration location is possible and one of the ways to simplify deployment in my opinion. Additionally it abstracts away orchestration details (mount points) from the actual storage location used by an application/container. Sure conventions are only ontop, but standards should not be forced upon, but agreed on. I see value in the discussion more than I see in my specific implementation. The advantage to use the filesystem is that applications can work with them now. It is easier to let them use what they know for now and therefore provide a filesystem implementation. Which could be backed by an underlying API. As seen in this proposal a lot of different tools came up and no standard API could be agreed upon. On the other hand most of these tools provide a way to export more or less the same config files. Or at least a SideContainer could provide this export, without adding custom code into the application container. Separating concerns is one thing I value in the container approach. One thing considered was using tmp filesystems to minimize the attack surface for secrets laying around in the system. LDAP was just one suggested solution and in my and your view it is not worth it. Additionally file distribution is not optimal and seeding LDAP credentials needs another solution again. It is not about choosing existing tools over new implementations. It is more about understanding existing tools and enable a more generalized solution for a broad usage area. The proposed tools are partly used in existing products/projects, that is one reason they were included. Additionally I am not a fan of proposing a new standard, which just ends up increasing the fragmentation in the ecosystem. I wanted to propose a standard, which enables a wide range of tools and applications to work with and in the same breath simplify orchestration and usage of containers. Moving the application details to the image builders and simplify the orchestration details. I have to disagree, that using LDAP/consul or my filesystem proposal at moby/moby#9277 makes it more difficult to protect information. Right now most container users either use ENVs, which show up in their bash history, the process and are available to linked containers etc., or embed their credentials inside their container, which easily gets pushed to a public registry or is accessible in their private registry without any further ACL. When someone can make the application read "wrong" files, one can also assume that they could inject code, rewrite API endpoints and use "wrong" ENVs. Making the application do malicious things is not a problem of filesystem interface usage, but a general issue to be considered. One idea here was to make it possible to move from beginner cases to advanced cases easily as the backend implementation can be switched easily, but the interface stays the same. Right now the filesystem is one of the most used interfaces for applications, but it lacks some standardization inside docker and kubernetes. Moving to another specific implementation for advanced cases is something for the future and I would love to see secret distribution within kubernetes, which does not rely on bending tools, but that does not mean kubernetes cannot provide a common interface via the filesystem too. At least provide it until applications can actually use the proposed API natively. Adding glue code to each used application just moves the tool bending to another level, which I actually dislike even more. |
This proposed update to docs/design/security.md includes proposals on how to ensure containers have consistent Linux security behavior across nodes, how containers authenticate and authorize to the master and other components, and how secret data could be distributed to pods to allow that authentication. References concepts from kubernetes#3910, kubernetes#2030, and kubernetes#2297 as well as upstream issues around the Docker vault and Docker secrets.
I will document secrets and then close this with a link to that doc. |
We now have secrets, which are distributed via a volume. There is also an option to pass them in env vars. This issue is still good reading on the design space, but it doesn't need to be an open issue. |
@erictune what is the status of secrets, and are they documented?
|
They are implemented and documented here: |
Thanks! |
This proposed update to docs/design/security.md includes proposals on how to ensure containers have consistent Linux security behavior across nodes, how containers authenticate and authorize to the master and other components, and how secret data could be distributed to pods to allow that authentication. References concepts from kubernetes#3910, kubernetes#2030, and kubernetes#2297 as well as upstream issues around the Docker vault and Docker secrets.
One missing piece of both guidelines and k8s is a way to distribute secrets.
There are multiple ways to go about it and I want to start the discussion not only to suggest a guideline for secret distribution, but to make it easier to be integrated into k8s. We could start by discussion the various ways and including them for usage in the documentation so that these "best practices" are available and furthermore work great with k8s. As a second step we should try to find one common way of doing it, integrate it into k8s to make it as seamless as possible.
There are two issues with secret distribution I find discussable. Sure there are many more as secret distribution is one of the huge problems. Not think about the perfect solution yet, but a start to make it easier for people to start using k8s or use it as reference for their docker installations.
The first issue concerns PWs and credentials for services. For example database PWs, AWS credentials etc..
The second kind of problems arise with key/file distribution. The issues come with multiple secret files, which need to be distributed. Mainly keys for de/encryption, ssl keys, vpn/ssh keys etc..
Option 1: ENV
Pros:
Cons:
Option 2: LDAP
Pros:
Cons:
Option 3a: Data Volume Container
Pros:
Cons:
Option 3b: Data Volume Container (encrypted)
Pros:
Cons:
Option 4a: etcd/consul
Pros:
Cons:
Option 4b: etcd/consul (encrypted via crypt)
Pros:
Cons:
My favourite method would be to use encrypted Data Volume Containers. (Option 3b) This fits best with the modularity and reproducability of docker and makes it easy to switch out secret distribution later on. For example encrypted Volumes could be based on Ceph volumes instead of docker containers
I'm looking forward for your input.
The text was updated successfully, but these errors were encountered: