stackskipton
4 months ago
SRE/Sysadmin/DevOps/Whatever here, while blog didn't talk about doing anything difficult but setting ENVVAR standards, I will point out all replacements are just as frustrating especially when talking about secrets.
Anything involving vaults where Application reaches out to specific secret vault like Hashicorp Vault/OpenBao/Secrets Manager quickly becomes massive vendor lock in where replacement is very difficult due to library replacement and makes vault uptime extremely important. This puts Ops in extremely difficult place when it becomes time to upgrade or do maintenance.
Config files have problem of you have secrets, how do you get them into config file since config files are generally kept in public systems? Most of the time it's some form of either "Template replacement by privileged system before handing it to application" or "Entire Config File gets loaded into secret vault and passed into application". Templating can be error prone and loading entire config files into secret manager is frustrating as well since someone could screw up the load.
Speaking of config files, since most systems are running containers, and unless you are at Ops discipline company, these config files are never in the right place, it becomes error prone for Ops to screw up the mounting. Also, whatever format you use, JSON/YAML/TOML is ripe for some weird config file bug to emerge like Norway problem in YAML.
Getting secrets from Kubernetes Secrets API I've seen done but lock in again. I'd strongly not recommend this approach unless you are designing a Kubernetes operator or other such type system.
I will say I've seen Subprocess thing bite people but I've seen less and less subprocess generation these days. Most teams go with message bus type system instead of sub processing since it's more robust and allows independent scaling.
yukinon
4 months ago
I am not sure if this considered an anti-pattern, but in one of my teams, we wrote a lightweight generic Secrets library with configurable/pluggable backends (such as AWS Secrets Manager). It had a configurable local cache, with per-parameter overrides to bypass the cache. It meant vendor specific fetch logic was in the pluggable backends, while the app and the secrets lib remained vendor neutral.
When we moved it to Vault, it was seamless. Just meant adding our Vault backend wrapper as a dependency and updating the config to use the Vault backend.
gutafoki
4 months ago
This is how it should be done. Vendor lock-in can almost always be avoided with proper design
jppittma
4 months ago
How is the kubernetes secret API lock in? Genuinely wondering - were you trying to use that deployment yaml for something other than a kubernetes deployment? For most applications, you should be mounting the secret on your application, then you can inject it as either an environment variable or a json file that your application reads in an environment agnostic way.
Then, on the backend, you can configure etcd to use whatever KMS provider you like for encryption.
stackskipton
4 months ago
Because you can't run the container, even for development outside Kubernetes.
Yes, you can mount Secrets as Volumes or Env Var in Kubernetes which is fine but I'm not talking about "How you get env var/secret" but "Methods of dealing with config."
jppittma
4 months ago
Yes you can? The container should be completely agnostic to the fact that it's running in kubernetes. You can do config the same way. Configmaps are mounted as regular files and environment variables. The application doesn't care if the configmap came from the cluster resource or a file your created on your dev machine with dev credentials. You can mount local files into the container yourself. It's docker run -v "source:destination" I think.
joshribakoff
4 months ago
One of you is talking about mapping a secret to an environment variable and the other one of you is talking about having the work load make an API call to retrieve the secret. You’re not even talking about the same thing.
jppittma
4 months ago
The k8s api server is the thing that's configured to talk to your Thales or whatever. On managed kubernetes, these are usually preconfigured to talk to the vendor -- that's the difference between a secret and a config map. The secret is encrypted when it's stored in etcd.
You'd be forgiven for being mistaken however, because this encryption is handled in a way that's transparent to the application.
If you're talking about your application making a call to the k8s api server, then you shouldn't do that unless you're developing a plugin. The kubelet knows how to retrieve and mount secrets from the k8s api server and display them as environment variables to the application. You just declare it as a part of your deployment in the podspec.
stackskipton
4 months ago
sigh I’m extremely competent Ops type and I know. If you mount secrets as Volume or Env Var, that’s Config file or Env var from Application PoV. We are looking at this from Application PoV.
I’ve seen Applications that do direct calls to Kubernetes API and retrieve the secret from it. So they have custom role with bindings and service account and Kubernetes client libraries.
jppittma
4 months ago
If you're not developing k8s operators, you're calling the api server directly, then complaining about lock in, then that's a skill issue. If you're developing k8s operators, then you should use a tool like kind for integration tests and dependency injection for other stuff and the concept of lock in doesn't make sense. You can also deploy your helm chart directly to kind.
cassianoleal
4 months ago
Don’t use live system secrets and credentials when running your application locally. Then you don’t need to access the same secrets.
Keep it simple and design your applications so they’re agnostic to that fact.
It’s really not that hard, I’ve been doing this for at least 6 or 7 years. A little bit of good engineering goes a long way!
Nilocshot
4 months ago
This is where I like things like Tilt. If you're deploying to a k8s cluster, it's probably a good idea to do local dev in as close to a similar environment as possible.
Bit more of an initial hurdle than "just run the docker image"; however.
stackskipton
4 months ago
I've look at Tilt and it's another abstraction for Kubernetes which rarely ends well at scale.
However, most of time, Devs don't need to develop on Kubernetes since it's just Container Runtime and Networking Layer they don't care about. They run container, they connect to HTTP endpoint to talk to other containers, they are happy. Details are left to us Ops people.
fragmede
4 months ago
It seems contradictory to say that Tilt is an abstraction over kubernetes and say that won't work at scale, but then volunteer ops to be a layer of abstraction over kubernetes as a solution.
FWIW, Skaffold.dev is similar to Tilt, and has been working out great. "skaffold dev" on the cli or the corresponding button in the users IDE starts up a local kube cluster (minikube), the dev code in a container, any other configured containers, optionally opening a port to attach a debugger, and watches the code for changes and restarts the container with the dev code when there's changes. Developers aren't beholder to the capacity of whoever's on call on the ops team to manage the containers they need to be productive. The details of pods and CRDs and helm and ArgoCD and kubectl are abstracted away for them. They just run "skaffold dev" and edit code. Ops gets to run "skaffold render" to build and tag images, and generate the corresponding kubernetes manifest.
stackskipton
4 months ago
Ops is not a layer of abstraction over Kubernetes no more then Dev is layer of abstraction over Python. We both have different responsibilities and thinking that Ops is just missing one more library is why it goes so wrong.
Kubernetes is massive beast and I get it. It feels extremely overcomplicated for "Please for the love of all that holy, just run this container." However, trying to abstract away such complexity is like trying to use Golang with some Python to Golang cross compiler. It works until it you need some feature and then oh god, all hell breaks loose.
I have not played with scaffold either but I will say. scaffold render should not be Ops job, I find it goes best when Devs present artifact they believe is ready for production and I can slot into the system. Otherwise, the friction between Devs handing Ops what they think is possibly buildable artifact quickly becomes untenable.
nunez
4 months ago
+1 to all of this.
This is why I continue to use env vars and dotenv for configuration. They are extremely simple, work well, and are compatible with secrets managers and other secrets tooling.
Though lately I've been veering into sOps the last few years. YAML is just so nice for expressing how an app should be configured, and sops makes encrypting chunks of it so easy. Dealing with GPG keys can be challenging though, which Vault/OpenBao solve, but then lock-in becomes an issue (though less so with OpenBao).
benterix
4 months ago
> Getting secrets from Kubernetes Secrets API I've seen done but lock in again.
I don't get this part. Why would you use Kubernetes secrets alone for storing secrets if they are not encrypted by default? Using k8s secrets only makes sense if (0) you are using k8s, (1) you already did some groundwork like encryption at rest for the control plane, and (2) you are actually using a solution like Secrets Store CSI Driver (or alternatives - just don't depend on k8s secret being actually more secret than a ConfigMap by default).
And then, it's the opposite of lock-in as the Secrets Store CSI Driver uspports multiple backends, including open source Conjur.
1718627440
4 months ago
You can have a command setting that is invoked to get the string. This way you don't have vendor login, but also don't need a separate template step.
stackskipton
4 months ago
You still need to present that to Application.
So Command Line leaks worse than Env Var.
Config file, see original post for problems.
Env Var, see blog for problems.
sgarland
4 months ago
I think parent is referring to something like SOPS [0], which can pass secrets via FIFO. That way, there’s nothing on disk, the pipe is cleared after first read, and /proc/cmdline doesn’t reveal anything.
1718627440
4 months ago
No I meant a property in the application config.
For example mbsync/isync does this.
stackskipton
4 months ago
You have a config file, it needs to have secrets so likely you are going to run some templating system where you replace dbpassword: ${dbPassword} with password from some secret system. Hopefuly you understand possible issues with any templating system that could result in replacement failures.
String manipulating is one of those "This is easy" until it's not.
1718627440
4 months ago
Apparently I'm still unclear.
I don't mean to hardcode secrets into the config file either. I was suggesting to put a command into the configuration file that the application then calls to get the secret. This way the secret is only ever passed over a file descriptor between two processes.
sureglymop
4 months ago
I do something similar. I usually have a flag, something like --password-file. It can only be used to specify a file containing the secret and at startup the application reads it.
1718627440
4 months ago
Yes, this is also possible, but which the approach I stated, the secret can be generated by another program or received from the network, it isn't just limited to a file.
stackskipton
4 months ago
My initial Ops gut feeling says "This is as lock in and error prone as Application Vault Libraries" but if Dev wanted to propose this, I'd be willing to see it in real operation.
1718627440
4 months ago
It isn't lock in, because all the application depends on is that it gets a string it can pass to exec/the shell and then reads all data from stdout until EOF as the secret.
stackskipton
4 months ago
Sure, but let's say you have 5 secrets to get or maybe the new vault CLI does not support just stdout printing but prints JSON only.
I still think this is worse than config file/Env Vars.
1718627440
4 months ago
You can always pass echo "SECRET" as the command, so it is a strict superset of the config file. Also programs that tend to provide a command option also tend to provide a simple string option.
user
4 months ago