Closed mwitkow closed 6 years ago
@mwitkow Thank for your valuable contribution, it fits exactly my requirements.
I really liked the OIDC approach (OpenID Connect) rather than an OAuth2 flow, the later is far more complex to configure.
I'm using Keycloak SSO as OIDC provider and the following Vault config:
vault auth-enable oidc
vault write auth/oidc/config \
issuer_url="http://localhost:8080/auth/realms/master" \
client_ids="testclient" \
username_claim="preferred_username" \
groups_claim="groups"
vault policy-write secret-policy secret-policy.hcl
vault write auth/oidc/groups/users policies=secret-policy
vault auth -method=oidc token=<bearer_access_token>
For the folks that want test this change, I've pushed a Vault 0.7.2 Docker image with merge of PR #2796 to Dockerhub as panga/vault:0.7.2-oidc (https://hub.docker.com/r/panga/vault/)
EDIT: I'm using a fork (https://github.com/panga/vault/tree/oidc) with OIDC backend provided by @mwitkow for now.
@jefferai I understand that the reasons for closing #2796 where as you cited in #2571 "In fact, the proliferation of backends that have come up in the last couple of months around this are exactly why we want to take the approach we took with the combined database backend."
However, I wanted to follow up here on what you said in #2796 :
Someone that wants to put in some minor effort to make it work the way we need (ref #2525) should get in contact.
If you're looking for an external contributor to implement a generic, pluggable OAuth2 backend, may I suggest closing this centi-thread and filing a new bug marked with "Help Needed" a clear description of what exactly needs implementing, in what incremental stages and what is the minimum feature set for acceptance? Or maybe phrase it in a separate design doc?
I've been following this discussion since the very beginning, and it is still unclear exactly what you guys are looking for. I think spending some time to clarify this, and adding pointers to "piggy-backable" code for plugins in Vault, would go a very long way if you're looking for an external contributor to build this generic pluggable backend.
For anyone else interested, @pidah @zdoherty @panga, we'll be tryibng out #2796 in testing, and if that proves successful we'll probably by maintaining a public fork of Vault with #2796 in it until the generic OAuth2 backend becomes a substitute.
@mwitkow Nobody has indicated to this point that what we are looking for is unclear. But I'll try to clarify:
There are a lot of relatively incompatible ways to get OIDC information. Sometimes you already have an OIDC token. Sometimes you have credentials that can be used to get an OIDC token; or in other cases, such as Ping, which won't get an OIDC token for password owner workflows but can fetch the equivalent UserInfo after the fact. Sometimes it requires a full OAuth flow first, at which point either an OIDC token can be fetched or similar user info can be gleaned.
It's also not clear from the examples I've seen that even given an OIDC token you can always rely on the same claims to specify group membership.
There are also potentially different ways to authenticate tokens, including ingressing associated public keys.
If you look at this from a higher level perspective, what it really looks like is that you need the following:
With the database backends early on people would just copy the code from one backend to the next and make the changes necessary to talk to e.g. mysql instead of postgresql. Bugs were copied too, and feature disparity grew over time. The way we solved it was a common backend that handled all non-specific functions and plugins conforming to an interface to handle the specific bits. The amount of copypasta has drastically decreased; it's easier to maintain, easier to keep feature parity, and easier not to have bugs proliferate.
In the above list, really only items 2 and 3 are likely to differ significantly between source of the user information. If we adopt a plugin system similar to the database backend, we can have all of the code for items 1 and 4 be the same. For a normal OIDC case, the plugin would be configured with a public key (or the URL to fetch it from); it would accept the JWT, validate the JWT, parse it, and return user info -- things it needs to do anyways, just behind a plugin interface. For Ping, the plugin could take in the user credentials, perform whatever calls it needs, and return the user info. We already merged an Okta backend, but Okta also has a way to fetch user info, and it'd be great if Okta could be supported here too.
There is a little extra work required to use a plugin interface, but common plugin functionality is already done (for the database backend).
I think the confusion with OAuth is that I was saying that such a mechanism could support OAuth eventually if other bits were worked on in Vault's core. But that's neither planned nor requested and I don't in any way see it as being necessary for this PR, or for #2796 or #2571.
However, I would like to see a plugin abstraction, even if the only plugin initially is a pure OIDC plugin. I think it has real value going forward and will be far easier to maintain by the Vault team.
If we adopt a plugin system similar to the database backend, we can have all of the code for items 1 and 4 be the same.
I think 4 would differ -- some plugins will need to call the userinfo endpoint, others can get it from an ID token, and still others might call some other arbitrary service to get that info. Or is that part of step 2 or 3? In other words, are you only referring to the step of a plugin saying "here's the user's info, wherever I got it from" and looking up the policies in the map from step 1?
One other question on the plugin implementation. Will plugins have a good way to be able to use Vault to store configuration info? In our original implementation as we submitted it for direct inclusion, we stored things in the mounted backend's config map, like the Ping URLs for both tokens and userinfo, a client ID, client secret, and the name of the attribute in userinfo to use for the groups. Will plugins have a way to store config data for each mounted instance of an auth plugin? Or if they have to deal with it themselves, will they at least be passed the mount info so they can key off that to support being mounted more than once?
I think the confusion with OAuth is that I was saying that such a mechanism could support OAuth eventually if other bits were worked on in Vault's core. But that's neither planned nor requested and I don't in any way see it as being necessary for this PR, or for #2796 or #2571.
Now I'm slightly confused...OAuth (resource owner flow) is definitely requested, but we're fine implementing it ourselves as a plugin once that's supported. We might even open source it. Other parts of your post make it sound like the plugin system will support us writing such a plugin though, so I'm not quite sure if this comment is anything I should be concerned with.
I think 4 would differ -- some plugins will need to call the userinfo endpoint, others can get it from an ID token, and still others might call some other arbitrary service to get that info. Or is that part of step 2 or 3? In other words, are you only referring to the step of a plugin saying "here's the user's info, wherever I got it from" and looking up the policies in the map from step 1?
Yes. My assertion is that the input to a plugin (into step 2) should be the client input (credentials, which may just simply be an OIDC token) and the output (after step 3) should be a defined data type that indicates what configured users/groups the authenticating user should inherit policies for. For OIDC or anything that can return an OIDC UserInfo-compatible struct this would likely be a fairly direct mapping.
One other question on the plugin implementation. Will plugins have a good way to be able to use Vault to store configuration info?
Yes. Normal storage semantics, just piped over a TLS-encrypted connection. (However, to be perfectly transparent, for built-in plugins they would actually be launched directly as objects in-memory. This is what the database backend does. But that's an implementation detail.)
Now I'm slightly confused...OAuth (resource owner flow) is definitely requested, but we're fine implementing it ourselves as a plugin once that's supported.
Sorry, what I should have said (rather than sowing more confusion) was other OAuth mechanisms could be supported eventually, such as the three-legged server side flow, where the client is given a URL to paste in their browser, after which they are redirected to Vault. That would require other plumbing through Vault's core and http layers. But pure OIDC and what you need for Ping would not require any of that and I don't see any reason they would have to be deferred. That's just implementation against a slightly different interface than exists now.
OK. That is a really long thread and my understanding OIDC has been increased as a result. I am looking at this for the same reason as a few others (I want to use KeyCloak as my auth provider - which defaults to OIDC). While I doubt I can help with the coding on this, I am more than happy to test and/or provide documentation once we get round to a solution. BTW - I like the ide of taking the same approach as you have with databases. Happy to contribute in any way possible.
@Hobbit71 with backend plugins coming out in 0.8, that might be a better way to go than the plugin system specific to OIDC/OAuth I mentioned above.
That is good to hear. Out of interest, how far away is 0.8. Not looking for anything firm here, is it weeks, months or quarters away?
Like I say, when we have that, happy to be involved. While I am not a Go coder, I now know some guys here (where I work) who are and we would love to contribute back to a great tool.
Are there any updates on this? I would love to be able to use OIDC as auth backend in vault.
There are several plugins (GCP, Kubernetes) using OIDC for auth.
@jefferai
There are several plugins (GCP, Kubernetes) using OIDC for auth.
Does this mean it's possible to use something like Dex? Or are you suggesting there are plugins to adapt from if someone wanted to implement generic OIDC.
@kamalmarhubi I would love to see "generic OIDC" but it may be relatively impossible given that most of the implementations we've seen rely heavily on custom metadata. But, those plugins are good starting points for someone wanting to make a plugin for their own needs.
The specs discussed in this thread are at times a bit obtuse, but It is sad to see this still unresolved nearly a year in. The plugin system seems like it could support this entirely outside the vault "batteries included" set.
@jefferai I do not understand the statement of how a generic OIDC plugin is "relatively impossible" if it is constrained to be a well formed JWT token. When you say "custom metadata" is this metadata that is put onto the vault token for some later use, or are you saying something about custom claims in the JWT.
A point of confusion throughout this thread is that OAuth2 and OIDC are different in their intent. OAuth2 is about authorization grants, while OIDC is only about authentication. OIDC is a much more natural fit for Vault auth. If Vault secrets are considered resources, than the most natural fit of OAuth2 for vault would be as a resource server, and that gets all entangled in client-ids and flows and really puts Vault in the middle of an OAuth2 system, not as a peripheral participant (which starts to feel very awkward to have things like login flows in the CLI or backend).
But the original goal of supporting a simple flow - where you have, at the Vault client, an OIDC token (Vault shouldn't care how you got it), and want to login to vault with that. And the Vault plugin supports roles that bind certain signers/issuer and jwt claims to vault policy. This seems very straightforward and worth supporting and seems the direction of #2796 (thank you @mwitkow for the persistence).
Most of the imperative to optimally combine OIDC with any/all OAuth2 support from early in this thread seems to be dissolved by the flexibility of the plug-in system replacing builtin backends.
Is a generic OIDC plugin still of interest or should this just be hosted outside of Vault project now as just a vault plugin?
Hi Preston,
I don't think it's so much a point of confusion around OAuth2/OIDC as the fact that there are some systems (I forget which) that won't grant OIDC tokens initially but will allow fetching such a token once you already have an OAuth2 token and people would like those to be supported too.
Anyways, OIDC support is totally straightforward in theory, but there are of course complicating factors. One is that many of the tokens people might want to use are JWTs but don't include many of the optional claims you'd really want for security, such as issue time or expiration time (I know this was an issue with the GCP and/or Kubernetes plugins). Could we just ignore it and let the user beware? Sure, but then that's added flags to control such bypass.
Another is that in most of the OIDCs we've seen so far in the plugins that have been written put important information in custom claims. So you'd need a way to define which claims are important for matching against roles, and what types those are -- a string, a list, etc.
Sometimes you can issue a call to a server to perform further token validation or get important parameters needed for matching (like the Kubernetes plugin does), but then you have to define how the call is made, what the inputs and outputs are, and what to do with them.
So it's not really a lack of desire to have a generic OIDC auth mechanism, it's that when it comes down to it, we haven't seen, in the specific examples that have been brought to our attention from real-world systems, a complete workflow that is sufficient from purely the OIDC token itself. Instead for GCP and Kubernetes it's been more like OIDC++ in ways that end up being specific to any given system.
If there is sufficient demand for a pure, token-only OIDC mechanism that requires no external validation and has standard claims, I'm totally happy to have it. But I'd want to actually have an understanding of the real-world systems for which it's sufficient, because if it ends up being the case that we put an OIDC backend in and it's unusable for the majority of real-world use-cases then we end up either in a position where we need to keep frankencoding the backend to try to handle more and more special cases, or we're better off creating simple plugins specific to these systems.
@jefferai you mentioned lack of possible use cases.
My is simple I would like to be able to use Vault with either Dex or KeyCloak (preferable KeyCloak).
Workflow would be like this:
Beside KeyCloak/Dex support GitLab.com support would be nice.
What are the claims used in each of those cases, what types are they, and how would they map to Vault identities and policies?
I think it would map to http://www.keycloak.org/docs/3.3/authorization_services/topics/policy/role-policy.html
Keycloak's client_id
would be mapped to identity("role" I guess) in Vault. Adding policies to this client would enable policies in Vault.
Just had a talk with @chrishoffman about this today, as he's writing an auth backend that uses OIDC -- and of course, nothing useful is in non-proprietary extensions, and even worse, there's very little useful at all that doesn't then require taking a single identifying value and making further API calls.
However, we were talking about it in the context of Identity, which is increasingly how we're moving towards people assigning policy, via Identity groups, and realized that a dead simple approach could work well as a "generic" OIDC plugin. (If you don't know much about Vault's Identity system, take a look at https://www.vaultproject.io/docs/secrets/identity/index.html).
The configuration would consist only of:
Identity's API designed to be scripted, so you can easily sync some set of servers or users into Identity and have them auth and be identified as that user every time they auth. So long as you have a known unique identifier that can be validated, you can just do all policy management via Identity, without having to deal with complex mappings of groups/roles/policies/claims (many of which would require further API calls) in the plugin. If you can't get group info out of the JWT, just sync group info into Identity from your source of truth and assign uniquely-identified users to them. Anything much more complicated is probably better served by a specific plugin anyways.
Interested in feedback, and if someone wanted to write such a plugin, I'd be interested in having it in an official repo and pulling it upstream.
Hi @jefferai , myself and members of my team would be interested in this very much. I got questions, tho.
It sound like Chris Hoffmann is working on OIDC auth backend that you intend to live along the generic OIDC plugin that is the subject of this issue. Is that correct? If so, I don't get what is the difference between the two.
Do you want public key endpoint to be specific to this functionality? I was surprised to find there's no "generic" endpoint for giving Vault my public key for verification of whatever payload later on.
Would you like to use all 3 - registered claim names, public claim names, and private claim names? Would you like any verification on the contains of JWT at all, or it's basically as long as the hash is unique and we can map it to recorded Identity, we're good?
What OIDC flow are you thinking about? Implicit would be the easiest to implement, in my opinion.
As I'm re-reading your comment, it occurs to me you just want to map unique claim hash as an identifier of the user accessing Vault's endpoint.
Interactions then would be as follows.
Please let me know what you think.
@ror6ax I'm a bit confused by all the AWS stuff in your example, especially step 4. I think it looks more like this though:
What's the current state of the world here? I read through the whole thread but its still not clear. Is this being actively worked on?
I don't know of anyone actively working on the proposed solution.
This thread / issue saddens me a little. All I and I believe several others here want is to use Keycloak as a Vault auth method. Apparently that's not achievable for the foreseeable future.
@mvdkleijn I believe it's totally achievable, just requires someone to do it.
it's very strange for me, it's highly demanded feature to have for wide society, but in the same time I see that every small initiative got "killed", in the same time we've got Azure auth
https://github.com/hashicorp/vault/pull/2796 https://github.com/hashicorp/vault/pull/2571 https://github.com/hashicorp/vault/issues/644 https://github.com/hashicorp/vault/issues/1986 https://github.com/hashicorp/vault/pull/3005
Nothing has been "killed", whatever that means. But nobody has written a generic enough provider as outlined at https://github.com/hashicorp/vault/issues/2525#issuecomment-369718031
The fact that Azure uses JWTs is besides the point. The majority of the logic in that plugin has nothing to do with JWT verification but rather with checks and binds against Azure specific APIs.
In fact it's an excellent example of why a generic OIDC auth plugin has been hard to figure out. Most things you'd actually use to perform identification are behind custom claims or custom APIs that must be called and parsed. My guess is that that's why nobody has implemented a generic plugin as outlined in that comment.
Someone pointed me towards https://github.com/immutability-io/jwt-auth. Looks like it fits the mold quite closely to how I said a plugin would need to be designed for the generic case, so we may reach out to the author about pulling it in.
Hi all,
The above plugin https://github.com/immutability-io/jwt-auth is my handiwork. I am more than amenable to upstreaming it; but, I recently added a feature that may complicate matters.
The feature is to facilitate (among other things) delegated authentication using a rather opinionated mechanism. Please take a look at this mechanism (authentication with a JWT via a trustee).
I can refactor the plugin to remove this feature, but, I have a few real world use cases that will use it so I will have to figure out how to accommodate the functionality in a less tightly coupled? fashion.
meanwhile you can use: https://github.com/AnchorFree/vault-plugin-oidc (we use it in production for some time already, and it works).
We use jwt-auth in production too - for what it's worth. We modeled it after the GitHub plugin for mapping a claims (configurable) to policies.
jwt-auth also supports OAuth password grants and refreshes - so that the token can be used via renewal more effectively.
The trustee stuff can be used when a CI/CD pipeline wants to act on behalf of a user. IP constraints can be used alternatively.
@onorua Any interest in upstreaming?
@mwitkow I believe https://github.com/AnchorFree/vault-plugin-oidc is actually basically your code, just modernized. Are you still making use of it?
@jefferai sure, we can work on upstreaming it. I saw that we have quite a dead PR, with a dead ticket for more than a year, and decided to make it work for us. I would love to cooperate with @mwitkow or do it on our own, I just want this problem to be solved :)
Initial implementation of an official plugin is at https://github.com/hashicorp/vault-plugin-auth-jwt/pull/1
It handles both OIDC discovery and offline JWT validation workflows.
This is completely untested (by which I mean, literally, I made it compile successfully and pushed it up), but anyone that would like to comment on features and/or provide testing before I write some tests for it, feel free!
I hope to get this officially in for 0.11.
The plugin now has full tests for both OIDC discovery endpoint based and offline verification based workflows. It has been merged into the repo and is now included in vault master. As such, closing this.
@jefferai I just wanted to report on this that the 0.10.4 OIDC flow works for me (i'm using Auth0)
It was very hard to follow the documentation here https://www.vaultproject.io/docs/auth/jwt.html The examples given didn't map well to any of the Auth0 things and i ended up having to read throughly https://www.vaultproject.io/api/auth/jwt/index.html to know what was being mapped to what.
I think it could benefit from better examples for specific services like Auth0.
That being said i was disappointed to see that there was no Vault UI login flow for this - do you know when the improvements to the Vault UI will land for allowing you login with a given JWT token?
Also it would be nice if there was a mapping that could be setup - so that instead of saying this JWT "role" gets X policy - it could parse the "groups_claim" and assign a set of policies - very similar to how the LDAP login flow works.
Thanks and would love to hear your thoughts.
All my OIDC testing was done with Auth0 so it should have just worked with something similar to the OIDC discovery URL that is in those docs. Feel free to PR examples into the docs.
I thought JWT made it into the UI. @meirish can you comment?
You can do group policy mapping with Identity (https://www.vaultproject.io/docs/secrets/identity/index.html). It's a bit confusing right now, we need to shore up the documentation, but basically, set up an external identity group with an alias mapping to the group from auth0. You'll have to do this (once) for each of the auth0 groups but after that membership will automatically happen as people log in, so you can configure policies there. Overall having a central place to do this rather than an implementation of user/group mapping in each plugin makes every plugin significantly less complicated to write and maintain, and makes the centrally managed ones more useful for other features since we can check user/group membership within Vault's core.
Oh, there's a PR of a guide: https://github.com/hashicorp/vault/pull/4968 -- still being reviewed, but might be useful.
I was able to authenticate against Keycloak OIDC provider, but having issues with configuring groups_claim
parameter for role
https://github.com/hashicorp/vault-plugin-auth-jwt/issues/9
if I omit it (despite its required mark in documentation), then I could get Vault token
@avoidik Please don't ping on two tickets. One is enough.
@avoidik How did you manage to use Keycloak OIDC provider ?
I'm trying to use Keycloak as an OIDC provider, but I'm getting lost between documentation, could you explain how did you manage to do it ?
Thank you very much.
Kubernetes supports authentication (and group extraction forth authorization) using OICD (OpenID Connect) JWT
id_tokens
tokens, see here for docs. Basically JWT tokens are crypto-verifiable JSON key-value pairs called "claims".For Kubernetes Auth, two such claims are used:
username
(configurable) - indicating the subject of the tokengroups
(configurable) - indicating the list of groups the user belongs toBoth KeyCloak and Dex are configurable OpenID Connect servers that can delegate to upstream identity providers (e.g. Azure or Google).
This proposal is about introducing an Auth Backend that is a configurable, generic OICD backend that uses JWT token validation.
Contrary to what's been discussed previously in #465, OIDC doesn't require browser flows to be used, and such is not an obstacle for Vault adoption. They can be used in exactly the same fashion as GitHub personal tokens, by copy-pasting.
In fact this is exactly what K8S's
kubectl
is expected to be used, with--token
flag.A couple of other considerations:
min(configured_max_ttl, expiraton_of_id_token)
metadata
of the tokengroups/
configuration endpoint that maps onto policies, similarly as with GithubThe K8S oicd plugin seems fairly straightforward and could act as a basis for this work. We'd actually be willing to send in PRs for this if Vault maintainers would accept them :)