Closed kettenbach-it closed 1 year ago
Good to hear from you again! You should leave those variables set regardless (this way it eases the transition and continues to work for existing configurations (or future configurations)).
Also note that server-side does not imply unencrypted but as you mention, you may use unencrypted tokens when using a server-side config.
Essentially to use server-side you should:
store
and give it an id
(effectively your store-toeken.json
mentioned above)config_token_store_id=primary&config_token_id=1
instead of config_token
As the doc mentions you could use a pointer token
but I'm gathering you want the above approach.
The logic behind how it works isn't too terrible to read in the code if that helps. Just search for isServerSideConfigToken
here: https://github.com/travisghansen/external-auth-server/blob/master/src/server.js
I do use server side!
And I want to get rid of the encryption.
Ah! Simply don't encrypt it. It will detect on each individual token (so some can be encrypted and others not if you wish).
https://github.com/travisghansen/external-auth-server/blob/master/src/server.js#L259-L265
Ah, that's easier than I thought! I'll try that!
Just make sure you json encode the value as it's json-in-json when using a flat file like that.
EDIT: lies! it's not json, but rather the jwt...ignore me ;)
Frankly I've been waiting for someone to create a sort of admin dashboard for eas
that automatically hooks into a DB and let's you manage everything via a gui (issue tokens, disable them, etc, etc). I guess it's not popular enough yet ;)
Hi Travis,
For my taste, a UI with a database would not be very effective. Precisely because we consistently follow the Infrastructure as Code approach and therefore find it good that eas can be completely configured via code in our git. A database & UI would only introduce extra complexity.
But what could make sense would be to configure the whole thing e.g. via yaml instead of json (for a server side config I mean). I find the JSON not very handy. Just too many curly brackets.
I have just tried to give eas the configuration in plain text. So I switched from this:
data:
store-token.json: |
{
"verivinum-prod":"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",
"verivinum-staging":"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",
"
.....
to this:
data:
store-token.json: |
{
"verivinum-prod": {
"aud": "Verivinum Production",
"eas": {
"plugins": [
{
"type": "oidc",
"issuer": {
"discover_url": "https://accounts.google.com/.well-known/openid-configuration"
},
"client": {
.....
}
]
}
},
"verivinum-staging": {
"aud": "Vicosmo Staging",
"eas": {
"plugins": [
{
"type": "oidc",
"issuer": {
"discover_url": "https://accounts.google.com/.well-known/openid-configuration"
},
"client": {
....
etc....
and get the following error:
eas-nxjjt external-auth-server 2022-10-15T09:10:58.626253294+02:00 {"level":"error","service":"external-auth-
server","message":"The first argument must be of type string or an instance of Buffer, ArrayBuffer, or Array or an Array-like
Object. Received an instance of Object","stack":"Error: The first argument must be of type string or an instance of Buffer,
ArrayBuffer, or Array or an Array-like Object. Received an instance of Object\n at Object.decrypt
(/home/eas/app/src/utils.js:82:11)\n at verifyHandler (/home/eas/app/src/server.js:246:48)\n at
processTicksAndRejections (internal/process/task_queues.js:97:5)"}
By the way: removing EAS_CONFIG_TOKEN_SIGN_SECRET results in this so I left it set:
eas-ng4z4 external-auth-server 2022-10-15T09:07:52.028397021+02:00 missing EAS_CONFIG_TOKEN_SIGN_SECRET env variable
I created this store-token.json
this way:
let tokens_unencrypted = {
'verivinum-prod': config_token_cleartext_verivinum_prod,
'verivinum-staging': config_token_cleartext_verivinum_staging,
'verivinum-dev': config_token_cleartext_verivinum_dev,
'gitlab-vicosmo': config_token_cleartext_gitlab_vicosmo
}
console.log(JSON.stringify(tokens_unencrypted, null, " "))
What's wrong with this?
I can support yaml easily enough. The yaml parser support json so the code would be exactly the same.
The values should be the unencrypted jwt (and therefore signed, the signature is still checked) vs the input to create the jwt.
Regarding configuration I have also considered exposing an endpoint in the service that will sign/encrypt a config token using POSTed data (but it would need to be optional and have some form of auth on it).
The values should be the unencrypted jwt (and therefore signed, the signature is still checked) vs the input to create the jwt.
Does this mean to do this:
let tokens = {
'verivinum-prod': jwt.sign(config_token_cleartext_verivinum_prod, config_token_sign_secret),
'verivinum-staging': jwt.sign(config_token_cleartext_verivinum_staging, config_token_sign_secret),
'verivinum-dev': jwt.sign(config_token_cleartext_verivinum_dev, config_token_sign_secret),
'gitlab-vicosmo': jwt.sign(config_token_cleartext_gitlab_vicosmo config_token_sign_secret),
}
If yes, please allow me to ask why all this security (signing, encrypting etc.) is needed for a server side config? This tokens could be kept in a k8s secret just as plain json (or even better yaml). This isn't a problem. There's no need for signing or even encrypting. This way I could just edit the k8s secret, update it via kubectl and I'm done and it i wouldn't need to run those javascript tools. Configuring eas would be a lot easier and more cloud native this way.
And: in the docs you write, that the server side tokens introduced state. I don't think they do. The tokens are just the configuration (https://12factor.net/config) and can be kept in a ConfigMap or Secret. The actual state are e.g. the sessions. Those shouldn't be kept in a container and therefore we're using Redis for this.
Fair points. server-side tokens were not in the original design (in my head and a piece of paper) and as such I don’t necessarily disagree with your assessment for the need of such strict security measures. Indeed for development I have a plugin that isn’t checked into the project which reads config as you have suggested (so I don’t have keep re-signing/encrypting everything for each config change).
Initially for server-side tokens I generally envisioned db usage so the signed/encrypted makes more sense vs injected as config as you have suggested (12 factor and all that). ie: the security of deploying the tokens jointly with eas
is stronger and fundamentally different than eas
reading from a truly external store…hence the comment about state and the desire to ensure encryption and signing.
Having said all of that, I’m not opposed to allowing tokens to be used in the fashion you propose, but I would likely prefer an env var control that ability so as to maintain more secure defaults.
Another consideration is that eas
can run outside of k8s. I have considered adding a plugin store type that is k8s secret(s) which would make the app ‘k8s native’ and likely be a great approach for what you need. Such a plugin could deliberately remove the need for signing/encryption but even then I would want it a configurable option. Mostly in an effort to ensure safe configurations for organizations that need strict ‘separation of duties’.
All good ideas and points! I really like the idea of a native store plugin using k8s secrets!
Concerning db usage: it depends who is updating the config an how frequently! If your target user is a windows-type sysadmin that has to create tokens rarely (and therefore needs an "assistant" to do that), then a db (with UI) would make sense. If your target user is a cloud-native devOps guy who updates tokens using IaC (Infrastructure as Code) and maybe pretty often as well (like you do in dev), then a db would be contract productive. I'm the second guy. And: a db always add's an extra layer of complexity. E.g. who creates the users that can access this db? How is the DB managed? If you have a db, you should have a UI (especially for user type 1). How to you protect the access to the UI? You can't use eas, because of the chicken-and-egg problem. What if you take sql and have to update the schema - then you need to add migrations to your node application and an ORM as well...... If I wanted a solution with UI, I could - afaik - e.g. use kong or apache-api-six. I think the advantage is that eas can be easily integrated in an IaC pattern, just like traefik.
And if you you'd like to strengthen that (and maybe put in into the docs "this is made for IaC!"), then you should go for a better support of k8s. BUT you won't need a plugin that reads k8s secrets!! A k8s secret is brought into the container using env vars or config files by a mapping process at the start of the container. The only thing eas needs to support is reading the cleartext (no signature, no encryption) either from a file or env var(s). The separation of duties (separation of concerns) IS already taken care of by k8s - if other guys are responsible to create the tokens then running the container, this can easily be configured in k8s. Please don't take care of that in the eas. There are even a couple 3rd party solutions for handling secrets in k8s, that would exactly take care of that aspect in much more elaborate way, then eas could ever do.
Hi Travis,
another customer of us, who we consult in cloud native aspects, has been trying to use eas during the last weeks, because we had suggested to him to use eas for a specific use case (Keycloak + traefik + eas + hisCloudApp on k8s). Although the colleague there is an experienced DevOps-expert, the team there did not manage to implement eas. I have advised the team over the last few days and looked at where the problems were. I don't want to name the reasons per se here in public. If you want me to, please let me know. On the other hand, I can also send you an email.
If the reasons are security related please email! If they are usability related etc the feedback is entirely welcome here!
I called the customer todays and asked the senior platform engineer for a honest feedback. Here's what he said (raw and uncut):
Agreed with all of them, all valid points :(
As you mentioned it's a very advanced tool with lots of options which definitely can be daunting (especially oidc/oauth). Obviously I can't do all of the above right now so do they have some specific questions still looming or something I can help with at the moment?
I'll likely have some time next week to dig into issues we've been discussing and hopefully make some progress on each.
Addition from myself:
What would be perfect is:
apiVersion: v1
kind: ConfigMap
metadata:
name: eas-configuration
namespace: eas
data:
store-token.json: |
token1:
aud: "My first token"
eas:
plugins:
type: oidc
issuer:
discover_url: "https://....."
client:
client_id: ......
client_secret: .....
There should be examples for the plugins to run in different scenarios.
The customer should not need to:
But still, putting the config in a git repo following the IaC idea is a very good thing compared to Kong, Traefik Enterprise oder APISix (all of them having OIDC already on board).
I'm willing to help to make this project more successful, because I think it deserves it.
What I could do is to work on the content of the docs as well as their structure
What I can't do: implement things in JS/TS
The problem with generally allowing unsigned and unencypted configs is that the service will accept any non-server-side tokens as well...so then you would be allowing any arbitrary configs potentially doing malicious activity or even just exposing secrets you don't want exposed organizationally. We could add an option to only allow server-side tokens which would make that much more secure and feasible.
Supporting yaml configs generally is a desirable and generally should be quite easy.
Operators shouldn't need to know js, npm, etc, etc. Config tokens can be generated with:
cat config-token.json | docker run --rm -i -e EAS_CONFIG_TOKEN_SIGN_SECRET=foo -e EAS_CONFIG_TOKEN_ENCRYPT_SECRET=bar travisghansen/external-auth-server generate-config-token
In fact I never actually intended the project to directly be used for generating tokens anyway. I'm using standard jwt sign and standard encryption features that can be implemented in any language. I don't really think it's necessary to build tooling though given the availability of the simple docker command above.
I'm open to all forms of contribution! The feedback is appreciated and I'm happy to work through the individual points and come up with solutions that are helpful and secure.
The problem with generally allowing unsigned and unencypted configs is that the service will accept any non-server-side tokens as well...so then you would be allowing any arbitrary configs potentially doing malicious activity or even just exposing secrets you don't want exposed organizationally. We could add an option to only allow server-side tokens which would make that much more secure and feasible.
I can follow the reasoning, even though I am not the type who wants to prevent others from doing stupid things. So allowing the plaintext configuration only when reading it via the file adapter, for example, would therefore make sense.
Operators shouldn't need to know js, npm, etc, etc. Config tokens can be generated with:
Why can't I just write the configuration as yaml in a ConfigMap and be done with it? That's what all the other tools do.
In fact I never actually intended the project to directly be used for generating tokens anyway. I'm using standard jwt sign and standard encryption features that can be implemented in any language. I don't really think it's necessary to build tooling though given the availability of the simple docker command above.
I'd like to need no tooling at all!
Question: What use case is/was eas intended for? I don't really understand passing tokens via http(s). I can think of use cases in which these tokens are generated automatically. But I can't think of anything that makes sense in practice..... I used eas at the time because thomsedden's forwardAuth tool is very limited. I don't remember exactly what was missing. But I remember that it didn't work for my use case. It's definitely the tool you'll find first - probably because of its name - when you Google "forwardauth" in combination with a few other keywords. At least back then, about 3 years ago, it was like this. UI tools like APISix etc. didn't exist back then or they were (and are) too expensive like Traefik Enterprise. Besides, I like IaC. In the end, eas is a super tool for a flexible implementation of a forwardAuth service together with traefik. It does IaC and can do everything it is supposed to. I configure it as often as I configure traefik - once every few years! Therefore, it would make sense to configure it (technically) as simply as possible in the k8s environment. I mean, looking through the many parameters is hard enough. Why then sign and encrypt if it's not necessary in a k8s environment!?
And another question: is it used significantly outside k8s and together with traefik (and OIDC)? I consider this to be the primary use case that will hit every k8s operator using traefik in the community variant sooner or later....
A lot of your questions are asking about removing the need for signing/encryption which I've already said I support, it just needs to be done in a sensible fashion keeping security in mind is all.
The use-case for eas
was to create a stateless service that could handle any number of configurations without needing to deploy a new instance for every configuration (ie: not the pattern needed when using oauth2-proxy
and similar). I wanted a simply way to secure any service I wanted without needing to redeploy the/a forward auth server over and over.
While achieving those goals it needs to:
Again, I agree with the goal of handling the config as IaC (it does so already as your doing, simply signing/encrypting (or not) the values does not change that goal...it does require more work/effort obviously). To alleviate some of the configuration complexity I think there are scenarios where removing the need to sign/encrypt are acceptable, it just needs to be done sensibly. To that end I intend to address this ticket when I have some time to dedicate to this project. I want to add this request and support the remaining oidc flows to remove the need for eas
to idp
communication.
The use-case for
eas
was to create a stateless service that could handle any number of configurations without needing to deploy a new instance for every configuration (ie: not the pattern needed when usingoauth2-proxy
and similar). I wanted a simply way to secure any service I wanted without needing to redeploy the/a forward auth server over and over.
I think in a broader sense "stateless" means that the container does not write any files - at least not those that must not be lost or used by others. (Factor VI) For persistence there are backing services (Factor IV). That a container has a config and is reloaded when it changes is perfectly okay (Factor III). The container does not get a state only because it has an exchangeable config.
You have solved the problem of not having to create a completely new instance of the software just to bind another service very well, since several services per token and even several tokens per store are supported. I think here lies (among other things) a great strength of eas and I don't want to question this part at all.
The fact that you don't even have to adapt the config-file(s) for different configurations, but can pass the same via a http parameter, is something that has rather confused the customer and me, because we have never seen anything like this before. It seems that you have interpreted the term stateless extraordinarily strictly here. A somewhat relaxed approach to this would not be a mistake in my opinion. The system would still be stateless and the other things like performance and separation of concerns (can be done in k8s as well as already said) won't be affected either. Of course, I agree with you that safety must not suffer as a result.
This is getting rather philosophical now.
If I can support you, let me know!
Yeah, I like the input and will do my best to accommodate! I'm generally aware of the complexity and relatively steep curve trying to understand how the project works, it's definitely unique and takes some time to 'digest' the design/approach.
The relaxed approach to stateless is server-side
tokens which as you have pointed out can effectively be considered stateless when using k8s tooling to handle the state (ie: config as state). I think we can retain the security goals while eliminating the need for signing/encrypting the tokens.
That's great! We have a plan!
OK, sorry for the long wait! Life had a bit of a storm there for a few months but I finally have a chance to revisit this. I'm working in the next
branch currently and have added several things:
EAS_ALLOW_PLAIN_SERVER_SIDE_TOKENS
env var to 1
pkce
support for oauth
/ oidc
pluginspkce
support in place it is now possible to support scenarios where eas
can use oidc
without the need for eas
to have access to op
(https://github.com/travisghansen/external-auth-server/issues/158)https://github.com/travisghansen/external-auth-server/pull/165/files
Hi Travis! Happy new year!
I will try using unencrypted and unsigned server-side config tokens given as yaml as soon as you'll upload a docker image! It will greatly simplify my config!
You can try it now in the next
images. I'm working on some more features for the client-side token retrieval flow as well and should have those wrapped up shortly.
Question: right now I have a store-token.json
signed+encrypted in a k8s configMap mounted into the container(s) referenced in the content of EAS_CONFIG_TOKEN_STORES
.
Am I right, that to switch to yaml and plain text, I have to:
store-token.yaml
in the config mapstore-token.yaml
(instead of .json) in content of EAS_CONFIG_TOKEN_STORES
EAS_ALLOW_PLAIN_SERVER_SIDE_TOKENS
to 1
Correct?
That env var isn't signed/encrypted/etc anyway (at least not as it relates to how it's handled internally). The app is currently expecting a valid json string. The new code allows it to be a valid yaml or json string.
let config_token_stores = process.env["EAS_CONFIG_TOKEN_STORES"];
if (config_token_stores) {
config_token_stores = YAML.parse(config_token_stores);
} else {
config_token_stores = {};
}
As far as the data inside the individual store you can:
The latter 2 require setting EAS_ALLOW_PLAIN_SERVER_SIDE_TOKENS=1
or they will be rejected/fail.
Test succeeded!
I put my config as unencrypted/unsigned yaml in a k8s-configMap and eas read it and work correctly.
Now it will be much easier to test some new things like #158
Awesome!
Hi!
As I have read here: https://github.com/travisghansen/external-auth-server/blob/master/CONFIG_TOKENS.md#server-side-tokens the server-side tokens do not have to be encrypted.
We have been doing it with encryption until now and it is quite cumbersome. Without encryption, it would be sufficient to simply edit a k8s secret or a ConfigMap and reload eas, to change eas' config.
My question is: if I write the JSON unencrypted into a
store-token.json
using a secret - is it enough to NOT set the*_SIGN_SECRET
and*_ENCRYPT_SECRET
variables to tell eas that the config is now in plain text?